/* * Copyright 2011-2019, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Augustin Cavalier * Michael Lotz * Jian Chiang * Jérôme Duval */ #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; /* The endpoint ring needs space for 2 TRBs per transfer * (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; // [XHCI_ENDPOINT_RING_SIZE] 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; // [XHCI_MAX_ENDPOINTS - 1][XHCI_ENDPOINT_RING_SIZE] 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); // Port operations for root hub 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: // Controller resets status_t ControllerReset(); status_t ControllerHalt(); // Interrupt functions static int32 InterruptHandler(void *data); int32 Interrupt(); // Device management void CleanupDevice(xhci_device *device); // Endpoint management 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); // Event management static int32 EventThread(void *data); void CompleteEvents(); void ProcessEvents(); // Transfer management static int32 FinishThread(void *data); void FinishTransfers(); // Descriptor management 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); // Command 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); // Doorbell void Ring(uint8 slot, uint8 endpoint); // Commands 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); // Operational register functions inline void WriteOpReg(uint32 reg, uint32 value); inline uint32 ReadOpReg(uint32 reg); inline status_t WaitOpBits(uint32 reg, uint32 mask, uint32 expected); // Capability register functions inline uint32 ReadCapReg32(uint32 reg); inline void WriteCapReg32(uint32 reg, uint32 value); // Runtime register functions inline uint32 ReadRunReg32(uint32 reg); inline void WriteRunReg32(uint32 reg, uint32 value); // Doorbell register functions inline uint32 ReadDoorReg32(uint32 reg); inline void WriteDoorReg32(uint32 reg, uint32 value); // Context functions 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; // Root Hub XHCIRootHub * fRootHub; // Port management uint8 fPortCount; uint8 fSlotCount; usb_speed fPortSpeeds[XHCI_MAX_PORTS]; // Scratchpad uint32 fScratchpadCount; area_id fScratchpadArea[XHCI_MAX_SCRATCHPADS]; void * fScratchpad[XHCI_MAX_SCRATCHPADS]; // Devices struct xhci_device fDevices[XHCI_MAX_DEVICES]; int32 fContextSizeShift; // 0/1 for 32/64 bytes // Transfers mutex fFinishedLock; xhci_td * fFinishedHead; sem_id fFinishTransfersSem; thread_id fFinishThread; // Events 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 // !XHCI_H