* Copyright 2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef EHCI_H
#define EHCI_H
#include "usb_private.h"
#include "ehci_hardware.h"
struct pci_info;
struct pci_device_module_info;
struct pci_device;
class EHCIRootHub;
typedef struct transfer_data {
Transfer * transfer;
ehci_qh * queue_head;
ehci_qtd * data_descriptor;
bool incoming;
bool canceled;
transfer_data * link;
} transfer_data;
typedef struct isochronous_transfer_data {
Transfer * transfer;
ehci_itd ** descriptors;
uint16 last_to_process;
bool incoming;
bool is_active;
isochronous_transfer_data * link;
size_t buffer_size;
void * buffer_log;
addr_t buffer_phy;
} isochronous_transfer_data;
class EHCI : public BusManager {
public:
EHCI(pci_info *info, pci_device_module_info* pci,
pci_device* device, Stack *stack, device_node *node);
~EHCI();
status_t Start();
virtual status_t StartDebugTransfer(Transfer *transfer);
virtual status_t CheckDebugTransfer(Transfer *transfer);
void LinkAsyncDebugQueueHead(ehci_qh *queueHead);
void LinkPeriodicDebugQueueHead(
ehci_qh *queueHead, Pipe *pipe);
virtual void CancelDebugTransfer(Transfer *transfer);
void CleanupDebugTransfer(Transfer *transfer);
virtual status_t SubmitTransfer(Transfer *transfer);
status_t SubmitIsochronous(Transfer *transfer);
virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force);
status_t CancelQueuedIsochronousTransfers(Pipe *pipe, bool force);
virtual status_t NotifyPipeChange(Pipe *pipe,
usb_change change);
uint8 PortCount() { 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 ResetPort(uint8 index);
status_t SuspendPort(uint8 index);
virtual const char * TypeName() const { return "ehci"; }
private:
status_t ControllerReset();
status_t LightReset();
static int32 InterruptHandler(void *data);
int32 Interrupt();
static int32 InterruptPollThread(void *data);
status_t AddPendingTransfer(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd *dataDescriptor,
bool directionIn);
status_t AddPendingIsochronousTransfer(
Transfer *transfer,
ehci_itd **isoRequest, uint32 lastIndex,
bool directionIn, addr_t bufferPhy,
void *bufferLog, size_t bufferSize);
status_t CancelAllPendingTransfers();
static int32 FinishThread(void *data);
void FinishTransfers();
static int32 CleanupThread(void *data);
void Cleanup();
static int32 FinishIsochronousThread(void *data);
void FinishIsochronousTransfers();
isochronous_transfer_data * FindIsochronousTransfer(ehci_itd *itd);
void LinkITDescriptors(ehci_itd *itd,
ehci_itd **last);
void LinkSITDescriptors(ehci_sitd *sitd,
ehci_sitd **last);
void UnlinkITDescriptors(ehci_itd *itd,
ehci_itd **last);
void UnlinkSITDescriptors(ehci_sitd *sitd,
ehci_sitd **last);
ehci_qh * CreateQueueHead();
status_t InitQueueHead(ehci_qh *queueHead,
Pipe *pipe);
void FreeQueueHead(ehci_qh *queueHead);
status_t LinkQueueHead(ehci_qh *queueHead);
status_t LinkInterruptQueueHead(ehci_qh *queueHead,
Pipe *pipe);
status_t UnlinkQueueHead(ehci_qh *queueHead,
ehci_qh **freeList);
status_t FillQueueWithRequest(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd **dataDescriptor,
bool *directionIn,
bool prepareKernelAccess);
status_t FillQueueWithData(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd **dataDescriptor,
bool *directionIn,
bool prepareKernelAccess);
status_t _FillQueueWithPhysicalData(Transfer *transfer,
ehci_qh *queueHead,
ehci_qtd **dataDescriptor,
bool *directionIn);
bool LockIsochronous();
void UnlockIsochronous();
ehci_qtd * CreateDescriptor(
size_t bufferSizeToAllocate,
uint8 pid);
status_t CreateDescriptorChain(Pipe *pipe,
ehci_qtd **firstDescriptor,
ehci_qtd **lastDescriptor,
ehci_qtd *strayDescriptor,
uint8 pid,
size_t buffersLength,
int32 descriptorsCount = -1);
ehci_itd* CreateItdDescriptor();
ehci_sitd* CreateSitdDescriptor();
void FreeDescriptor(ehci_qtd *descriptor);
void FreeDescriptorChain(ehci_qtd *topDescriptor);
void FreeDescriptor(ehci_itd *descriptor);
void FreeDescriptor(ehci_sitd *descriptor);
void FreeIsochronousData(
isochronous_transfer_data *data);
void LinkDescriptors(ehci_qtd *first,
ehci_qtd *last, ehci_qtd *alt);
size_t WriteDescriptorChain(
ehci_qtd *topDescriptor,
generic_io_vec *vector, size_t vectorCount,
bool physical);
size_t ReadDescriptorChain(ehci_qtd *topDescriptor,
generic_io_vec *vector, size_t vectorCount,
bool physical, bool *nextDataToggle);
size_t ReadActualLength(ehci_qtd *topDescriptor,
bool *nextDataToggle);
size_t WriteIsochronousDescriptorChain(
isochronous_transfer_data *transfer);
size_t ReadIsochronousDescriptorChain(
isochronous_transfer_data *transfer);
inline void WriteOpReg(uint32 reg, uint32 value);
inline uint32 ReadOpReg(uint32 reg);
inline uint8 ReadCapReg8(uint32 reg);
inline uint16 ReadCapReg16(uint32 reg);
inline uint32 ReadCapReg32(uint32 reg);
uint8 * fCapabilityRegisters;
uint8 * fOperationalRegisters;
area_id fRegisterArea;
pci_info * fPCIInfo;
pci_device_module_info* fPci;
pci_device* fDevice;
Stack * fStack;
uint32 fEnabledInterrupts;
uint32 fThreshold;
area_id fPeriodicFrameListArea;
uint32 * fPeriodicFrameList;
interrupt_entry * fInterruptEntries;
ehci_itd ** fItdEntries;
ehci_sitd ** fSitdEntries;
ehci_qh * fAsyncQueueHead;
sem_id fAsyncAdvanceSem;
transfer_data * fFirstTransfer;
transfer_data * fLastTransfer;
sem_id fFinishTransfersSem;
thread_id fFinishThread;
Pipe * fProcessingPipe;
ehci_qh * fFreeListHead;
sem_id fCleanupSem;
thread_id fCleanupThread;
bool fStopThreads;
int32 fNextStartingFrame;
uint16 * fFrameBandwidth;
isochronous_transfer_data * fFirstIsochronousTransfer;
isochronous_transfer_data * fLastIsochronousTransfer;
sem_id fFinishIsochronousTransfersSem;
thread_id fFinishIsochronousThread;
mutex fIsochronousLock;
EHCIRootHub * fRootHub;
uint8 fRootHubAddress;
uint8 fPortCount;
uint16 fPortResetChange;
uint16 fPortSuspendChange;
thread_id fInterruptPollThread;
uint32 fIRQ;
bool fUseMSI;
};
class EHCIRootHub : public Hub {
public:
EHCIRootHub(Object *rootObject,
int8 deviceAddress);
static status_t ProcessTransfer(EHCI *ehci,
Transfer *transfer);
};
#endif