/* * Copyright 2004-2011, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz * Niels S. Reedijk * Salvatore Benedetto */ #ifndef UHCI_H #define UHCI_H #include "usb_private.h" #include "uhci_hardware.h" #include #define UHCI_INTERRUPT_QUEUE 0 #define UHCI_LOW_SPEED_CONTROL_QUEUE 1 #define UHCI_FULL_SPEED_CONTROL_QUEUE 2 #define UHCI_BULK_QUEUE 3 #define UHCI_BANDWIDTH_RECLAMATION_QUEUE 4 #define UHCI_DEBUG_QUEUE 4 struct pci_info; struct pci_device_module_info; struct pci_device; class UHCIRootHub; class Queue { public: Queue(Stack *stack); ~Queue(); bool Lock(); void Unlock(); status_t InitCheck(); status_t LinkTo(Queue *other); status_t TerminateByStrayDescriptor(); status_t AppendTransfer(uhci_qh *transfer, bool lock = true); status_t RemoveTransfer(uhci_qh *transfer, bool lock = true); uint32 PhysicalAddress(); void PrintToStream(); usb_id USBID() { return 0; }; const char * TypeName() { return "uhci"; }; private: status_t fStatus; Stack * fStack; uhci_qh * fQueueHead; uhci_td * fStrayDescriptor; uhci_qh * fQueueTop; mutex fLock; }; typedef struct transfer_data { Transfer * transfer; Queue * queue; uhci_qh * transfer_queue; uhci_td * first_descriptor; uhci_td * data_descriptor; bool incoming; bool canceled; uint16 free_after_frame; transfer_data * link; } transfer_data; // This structure is used to create a list of // descriptors per isochronous transfer typedef struct isochronous_transfer_data { Transfer * transfer; // The next field is used to keep track // of every isochronous descriptor as they are NOT // linked to each other in a queue like in every other // transfer type uhci_td ** descriptors; uint16 last_to_process; bool incoming; bool is_active; isochronous_transfer_data * link; } isochronous_transfer_data; class UHCI : public BusManager { public: UHCI(pci_info *info, pci_device_module_info* pci, pci_device* device, Stack *stack, device_node* node); ~UHCI(); status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); virtual status_t StartDebugTransfer(Transfer *transfer); virtual status_t CheckDebugTransfer(Transfer *transfer); virtual void CancelDebugTransfer(Transfer *transfer); virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force); status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force); status_t SubmitRequest(Transfer *transfer); status_t SubmitIsochronous(Transfer *transfer); // Port operations 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 ResetPort(uint8 index); virtual const char * TypeName() const { return "uhci"; }; private: // Controller resets void GlobalReset(); status_t ControllerReset(); // Interrupt functions static int32 InterruptHandler(void *data); int32 Interrupt(); // Transfer functions status_t AddPendingTransfer(Transfer *transfer, Queue *queue, uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor, bool directionIn); status_t AddPendingIsochronousTransfer( Transfer *transfer, uhci_td **isoRequest, bool directionIn); static int32 FinishThread(void *data); void FinishTransfers(); void AddToFreeList(transfer_data *transfer); static int32 CleanupThread(void *data); void Cleanup(); status_t CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor, uhci_qh **_transferQueue); // Isochronous transfer functions static int32 FinishIsochronousThread(void *data); void FinishIsochronousTransfers(); isochronous_transfer_data * FindIsochronousTransfer(uhci_td *descriptor); status_t LinkIsochronousDescriptor( uhci_td *descriptor, uint16 frame); uhci_td * UnlinkIsochronousDescriptor(uint16 frame); // Transfer queue functions uhci_qh * CreateTransferQueue(uhci_td *descriptor); void FreeTransferQueue(uhci_qh *queueHead); bool LockIsochronous(); void UnlockIsochronous(); // Descriptor functions uhci_td * CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSizeToAllocate); status_t CreateDescriptorChain(Pipe *pipe, uhci_td **firstDescriptor, uhci_td **lastDescriptor, uint8 direction, size_t bufferSizeToAllocate); void FreeDescriptor(uhci_td *descriptor); void FreeDescriptorChain(uhci_td *topDescriptor); void LinkDescriptors(uhci_td *first, uhci_td *second); size_t WriteDescriptorChain(uhci_td *topDescriptor, generic_io_vec *vector, size_t vectorCount, bool physical); size_t ReadDescriptorChain(uhci_td *topDescriptor, generic_io_vec *vector, size_t vectorCount, bool physical, uint8 *lastDataToggle); size_t ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle); void WriteIsochronousDescriptorChain( uhci_td **isoRequest, uint32 packetCount, generic_io_vec *vector); void ReadIsochronousDescriptorChain( isochronous_transfer_data *transfer, generic_io_vec *vector); // Register functions inline void WriteReg8(uint32 reg, uint8 value); inline void WriteReg16(uint32 reg, uint16 value); inline void WriteReg32(uint32 reg, uint32 value); inline uint8 ReadReg8(uint32 reg); inline uint16 ReadReg16(uint32 reg); inline uint32 ReadReg32(uint32 reg); uint32 fRegisterBase; pci_info * fPCIInfo; pci_device_module_info* fPci; pci_device* fDevice; Stack * fStack; uint32 fEnabledInterrupts; // Frame list memory area_id fFrameArea; uint32 * fFrameList; // fFrameBandwidth[n] holds the available bandwidth // of the nth frame in microseconds uint16 * fFrameBandwidth; // fFirstIsochronousTransfer[n] and fLastIsochronousDescriptor[n] // keeps track of the first and last isochronous transfer descriptor // in the nth frame uhci_td ** fFirstIsochronousDescriptor; uhci_td ** fLastIsochronousDescriptor; // Queues int32 fQueueCount; Queue ** fQueues; // Maintain a linked list of transfers transfer_data * fFirstTransfer; transfer_data * fLastTransfer; sem_id fFinishTransfersSem; thread_id fFinishThread; bool fStopThreads; Pipe * fProcessingPipe; transfer_data * fFreeList; thread_id fCleanupThread; sem_id fCleanupSem; int32 fCleanupCount; // Maintain a linked list of isochronous transfers isochronous_transfer_data * fFirstIsochronousTransfer; isochronous_transfer_data * fLastIsochronousTransfer; sem_id fFinishIsochronousTransfersSem; thread_id fFinishIsochronousThread; mutex fIsochronousLock; // Root hub UHCIRootHub * fRootHub; uint8 fRootHubAddress; uint8 fPortResetChange; uint8 fIRQ; bool fUseMSI; }; class UHCIRootHub : public Hub { public: UHCIRootHub(Object *rootObject, int8 deviceAddress); static status_t ProcessTransfer(UHCI *uhci, Transfer *transfer); }; #endif