#ifndef _EHCI_H_
#define _EHCI_H_
+#include <threads.h>
+
+#define PERIODIC_SIZE 1024
+
typedef struct sEHCI_CapRegs tEHCI_CapRegs;
typedef struct sEHCI_OpRegs tEHCI_OpRegs;
typedef struct sEHCI_iTD tEHCI_iTD;
* 15 = Asynchronous Schedule Status
* 16:31 = Reserved ?(Zero)
*/
- Uint32 USBSts;
+ volatile Uint32 USBSts;
/**
* USB Interrupt Enable Register
*
*
* Bits 14:3 are used as n index into PeridocListBase
*/
- Uint32 FrIndex;
+ volatile Uint32 FrIndex;
/**
* Control Data Structure Segment Register
*
* 22 = Wake on Over-current Enable
* 23:31 = Reserved (ZERO)
*/
- Uint32 PortSC[15];
+ volatile Uint32 PortSC[15];
};
#define USBCMD_Run 0x0001
#define USBINTR_HostSystemError 0x0010
#define USBINTR_AsyncAdvance 0x0020
+#define PORTSC_CurrentConnectStatus 0x0001
+#define PORTSC_ConnectStatusChange 0x0002
+#define PORTSC_PortEnabled 0x0004
+#define PORTSC_PortEnableChange 0x0008
+#define PORTSC_OvercurrentActive 0x0010
+#define PORTSC_OvercurrentChange 0x0020
+#define PORTSC_ForcePortResume 0x0040
+#define PORTSC_Suspend 0x0080
+#define PORTSC_PortReset 0x0100
+#define PORTSC_Reserved1 0x0200
+#define PORTSC_LineStatus_MASK 0x0C00
+#define PORTSC_LineStatus_SE0 0x0000
+#define PORTSC_LineStatus_Jstate 0x0400
+#define PORTSC_LineStatus_Kstate 0x0800
+#define PORTSC_LineStatus_Undef 0x0C00
+#define PORTSC_PortPower 0x1000
+#define PORTSC_PortOwner 0x2000
+#define PORTSC_PortIndicator_MASK 0xC000
+#define PORTSC_PortIndicator_Off 0x0000
+#define PORTSC_PortIndicator_Amber 0x4000
+#define PORTSC_PortIndicator_Green 0x800
+
+// Isochronous (High-Speed) Transfer Descriptor
struct sEHCI_iTD
{
Uint32 Link;
Uint32 BufferPointers[8]; // Page aligned, low 12 bits are overloaded
};
+// Split Transaction Isochronous Transfer Descriptor
struct sEHCI_siTD
{
Uint32 Link;
Uint32 BackLink;
};
+// Queue Element Transfer Descriptor
struct sEHCI_qTD
{
Uint32 Link;
Uint32 Link2; // Used when there's a short packet
Uint32 Token;
Uint32 Pages[5]; //First has offset in low 12 bits
-};
+
+ // Internals (32 bytes = 4x 64-bit pointers)
+ tUSBHostCb *Callback;
+ void *CallbackData;
+ tEHCI_qTD *Next;
+} __attribute__((aligned(32)));
+// sizeof = 64
+// Queue Head
struct sEHCI_QH
{
Uint32 HLink; // Horizontal link
Uint32 Endpoint;
Uint32 EndpointExt;
Uint32 CurrentTD;
- tEHCI_qTD Overlay;
-};
+ struct {
+ Uint32 Link;
+ Uint32 Link2;
+ Uint32 Token;
+ Uint32 Pages[5];
+ } Overlay;
+ struct {
+ Uint8 IntOfs;
+ Uint8 IntPeriodPow;
+ tEHCI_QH *Next;
+ } Impl;
+} __attribute__((aligned(32)));
+// sizeof = 48 (round up to 64)
+
+#define PID_OUT 0
+#define PID_IN 1
+#define PID_SETUP 2
+
+#define TD_POOL_SIZE (PAGE_SIZE/sizeof(tEHCI_qTD))
+// - 256 addresses * 16 endpoints
+#define QH_POOL_SIZE (256*16)
+#define QH_POOL_PAGES (QH_POOL_SIZE*sizeof(tEHCI_QH)/PAGE_SIZE)
+#define QH_POOL_NPERPAGE (PAGE_SIZE/sizeof(tEHCI_QH))
struct sEHCI_Controller
{
+ tUSBHub *RootHub;
+ tThread *InterruptThread;
+ int nPorts;
+
tPAddr PhysBase;
tEHCI_CapRegs *CapRegs;
tEHCI_OpRegs *OpRegs;
- Uint32 *PeriodicQueue;
+ tEHCI_qTD *DeadTD;
+
+ int InterruptLoad[PERIODIC_SIZE];
+ tEHCI_QH *LastAsyncHead;
+
+ tMutex PeriodicListLock;
+ Uint32 *PeriodicQueue;
+ tEHCI_QH *PeriodicQueueV[PERIODIC_SIZE];
+
+ tMutex QHPoolMutex;
+ tEHCI_QH *QHPools[QH_POOL_PAGES]; // [PAGE_SIZE/64]
+ tMutex TDPoolMutex;
+ tEHCI_qTD *TDPool; // [TD_POOL_SIZE]
};
#endif