* Copyright 2011-2019, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Augustin Cavalier <waddlesplash>
* Michael Lotz <mmlr@mlotz.ch>
* Jian Chiang <j.jian.chiang@gmail.com>
* JΓ©rΓ΄me Duval <jerome.duval@gmail.com>
*/
#ifndef XHCI_H
#define XHCI_H
#include "usb_private.h"
#include "xhci_hardware.h"
struct pci_info;
struct pci_device_module_info;
struct pci_device;
struct xhci_td;
struct xhci_device;
struct xhci_endpoint;
class XHCIRootHub;
* (one for the link TRB, and one for the Event Data TRB). */
#define XHCI_ENDPOINT_RING_SIZE (XHCI_MAX_TRANSFERS * 2)
typedef struct xhci_td {
xhci_trb* trbs;
phys_addr_t trb_addr;
uint32 trb_count;
uint32 trb_used;
void** buffers;
phys_addr_t* buffer_addrs;
size_t buffer_size;
uint32 buffer_count;
Transfer* transfer;
uint8 trb_completion_code;
int32 td_transferred;
int32 trb_left;
xhci_td* next;
} xhci_td;
typedef struct xhci_endpoint {
mutex lock;
xhci_device* device;
uint8 id;
uint8 status;
uint16 max_burst_payload;
xhci_td* td_head;
uint8 used;
uint8 next;
xhci_trb* trbs;
phys_addr_t trb_addr;
} xhci_endpoint;
typedef struct xhci_device {
uint8 slot;
uint8 address;
area_id trb_area;
phys_addr_t trb_addr;
struct xhci_trb *trbs;
area_id input_ctx_area;
phys_addr_t input_ctx_addr;
struct xhci_input_device_ctx *input_ctx;
area_id device_ctx_area;
phys_addr_t device_ctx_addr;
struct xhci_device_ctx *device_ctx;
xhci_endpoint endpoints[XHCI_MAX_ENDPOINTS - 1];
} xhci_device;
class XHCI : public BusManager {
public:
static status_t AddTo(Stack *stack);
XHCI(pci_info *info, pci_device_module_info* pci, pci_device* device, Stack *stack,
device_node* node);
~XHCI();
virtual const char * TypeName() const { return "xhci"; }
status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer);
status_t SubmitControlRequest(Transfer *transfer);
status_t SubmitNormalRequest(Transfer *transfer);
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
virtual status_t StartDebugTransfer(Transfer *transfer);
virtual status_t CheckDebugTransfer(Transfer *transfer);
virtual void CancelDebugTransfer(Transfer *transfer);
virtual status_t NotifyPipeChange(Pipe *pipe,
usb_change change);
virtual Device * AllocateDevice(Hub *parent,
int8 hubAddress, uint8 hubPort,
usb_speed speed);
virtual void FreeDevice(Device *device);
uint8 PortCount() const { return fPortCount; }
status_t GetPortStatus(uint8 index,
usb_port_status *status);
status_t SetPortFeature(uint8 index, uint16 feature);
status_t ClearPortFeature(uint8 index, uint16 feature);
status_t GetPortSpeed(uint8 index, usb_speed *speed);
private:
status_t ControllerReset();
status_t ControllerHalt();
static int32 InterruptHandler(void *data);
int32 Interrupt();
void CleanupDevice(xhci_device *device);
status_t ConfigureEndpoint(xhci_endpoint* ep, uint8 slot,
uint8 number, uint8 type, bool directionIn,
uint16 interval, uint16 maxPacketSize,
usb_speed speed, uint8 maxBurst,
uint16 bytesPerInterval);
uint8 _GetEndpointState(xhci_endpoint* ep);
status_t _InsertEndpointForPipe(Pipe *pipe);
status_t _RemoveEndpointForPipe(Pipe *pipe);
static int32 EventThread(void *data);
void CompleteEvents();
void ProcessEvents();
static int32 FinishThread(void *data);
void FinishTransfers();
xhci_td * CreateDescriptor(uint32 trbCount,
uint32 bufferCount, size_t bufferSize);
void FreeDescriptor(xhci_td *descriptor);
size_t WriteDescriptor(xhci_td *descriptor,
generic_io_vec *vector, size_t vectorCount, bool physical);
size_t ReadDescriptor(xhci_td *descriptor,
generic_io_vec *vector, size_t vectorCount, bool physical);
status_t _LinkDescriptorForPipe(xhci_td *descriptor,
xhci_endpoint *endpoint);
status_t _UnlinkDescriptorForPipe(xhci_td *descriptor,
xhci_endpoint *endpoint);
void DumpRing(xhci_trb *trb, uint32 size);
void QueueCommand(xhci_trb *trb);
void HandleCmdComplete(xhci_trb *trb);
void HandleTransferComplete(xhci_trb *trb);
status_t DoCommand(xhci_trb *trb);
void Ring(uint8 slot, uint8 endpoint);
status_t Noop();
status_t EnableSlot(uint8 *slot);
status_t DisableSlot(uint8 slot);
status_t SetAddress(uint64 inputContext, bool bsr,
uint8 slot);
status_t ConfigureEndpoint(uint64 inputContext,
bool deconfigure, uint8 slot);
status_t EvaluateContext(uint64 inputContext,
uint8 slot);
status_t ResetEndpoint(bool preserve, xhci_endpoint* endpoint);
status_t StopEndpoint(bool suspend, xhci_endpoint* endpoint);
status_t SetTRDequeue(uint64 dequeue, uint16 stream,
uint8 endpoint, uint8 slot);
status_t ResetDevice(uint8 slot);
inline void WriteOpReg(uint32 reg, uint32 value);
inline uint32 ReadOpReg(uint32 reg);
inline status_t WaitOpBits(uint32 reg, uint32 mask, uint32 expected);
inline uint32 ReadCapReg32(uint32 reg);
inline void WriteCapReg32(uint32 reg, uint32 value);
inline uint32 ReadRunReg32(uint32 reg);
inline void WriteRunReg32(uint32 reg, uint32 value);
inline uint32 ReadDoorReg32(uint32 reg);
inline void WriteDoorReg32(uint32 reg, uint32 value);
inline addr_t _OffsetContextAddr(addr_t p);
inline uint32 _ReadContext(uint32* p);
inline void _WriteContext(uint32* p, uint32 value);
inline uint64 _ReadContext(uint64* p);
inline void _WriteContext(uint64* p, uint64 value);
void _SwitchIntelPorts();
private:
area_id fRegisterArea;
uint8 * fRegisters;
uint32 fCapabilityRegisterOffset;
uint32 fOperationalRegisterOffset;
uint32 fRuntimeRegisterOffset;
uint32 fDoorbellRegisterOffset;
pci_info * fPCIInfo;
pci_device_module_info* fPci;
pci_device* fDevice;
Stack * fStack;
uint32 fIRQ;
bool fUseMSI;
area_id fErstArea;
xhci_erst_element * fErst;
xhci_trb * fEventRing;
xhci_trb * fCmdRing;
uint64 fCmdAddr;
uint32 fCmdResult[2];
area_id fDcbaArea;
struct xhci_device_context_array * fDcba;
spinlock fSpinlock;
sem_id fCmdCompSem;
bool fStopThreads;
XHCIRootHub * fRootHub;
uint8 fPortCount;
uint8 fSlotCount;
usb_speed fPortSpeeds[XHCI_MAX_PORTS];
uint32 fScratchpadCount;
area_id fScratchpadArea[XHCI_MAX_SCRATCHPADS];
void * fScratchpad[XHCI_MAX_SCRATCHPADS];
struct xhci_device fDevices[XHCI_MAX_DEVICES];
int32 fContextSizeShift;
mutex fFinishedLock;
xhci_td * fFinishedHead;
sem_id fFinishTransfersSem;
thread_id fFinishThread;
sem_id fEventSem;
thread_id fEventThread;
mutex fEventLock;
uint16 fEventIdx;
uint16 fCmdIdx;
uint8 fEventCcs;
uint8 fCmdCcs;
uint32 fExitLatMax;
};
class XHCIRootHub : public Hub {
public:
XHCIRootHub(Object *rootObject,
int8 deviceAddress);
static status_t ProcessTransfer(XHCI *ehci,
Transfer *transfer);
};
#endif