From dc8805bd19e086fd0752f976abb1bd0393b12c00 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 7 Aug 2012 17:02:38 +0800 Subject: [PATCH] USB - HC API Update --- .../Modules/USB/Core/include/usb_host.h | 2 +- KernelLand/Modules/USB/Core/usb.c | 2 +- KernelLand/Modules/USB/Core/usb_devinit.c | 36 +++- KernelLand/Modules/USB/Core/usb_io.c | 18 +- KernelLand/Modules/USB/Core/usb_lowlevel.c | 7 +- KernelLand/Modules/USB/EHCI/ehci.c | 198 ++++++++++++++++-- KernelLand/Modules/USB/EHCI/ehci.h | 33 ++- KernelLand/Modules/USB/UHCI/uhci.c | 128 +++++++---- KernelLand/Modules/USB/UHCI/uhci.h | 14 +- 9 files changed, 366 insertions(+), 72 deletions(-) diff --git a/KernelLand/Modules/USB/Core/include/usb_host.h b/KernelLand/Modules/USB/Core/include/usb_host.h index 87603dbd..8b4f96da 100644 --- a/KernelLand/Modules/USB/Core/include/usb_host.h +++ b/KernelLand/Modules/USB/Core/include/usb_host.h @@ -16,7 +16,7 @@ typedef struct sUSBHostDef tUSBHostDef; typedef void (*tUSBHostCb)(void *DataPtr, void *Data, size_t Length); typedef void *(*tUSBInitInt)(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len); -typedef void *(*tUSBInit)(void *Ptr, int Endpt); +typedef void *(*tUSBInit)(void *Ptr, int Endpt, size_t MaxPacketSize); typedef void *(*tUSBDataOp)(void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); typedef void *(*tUSBControlOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, diff --git a/KernelLand/Modules/USB/Core/usb.c b/KernelLand/Modules/USB/Core/usb.c index ab2427a4..9a0e2bca 100644 --- a/KernelLand/Modules/USB/Core/usb.c +++ b/KernelLand/Modules/USB/Core/usb.c @@ -43,7 +43,7 @@ tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts) host->RootHubDev.ParentHub = NULL; host->RootHubDev.Host = host; host->RootHubDev.Address = 0; - host->RootHubDev.EndpointHandles[0] = HostDef->InitControl(ControllerPtr, 0); + host->RootHubDev.EndpointHandles[0] = HostDef->InitControl(ControllerPtr, 0, 64); // host->RootHubIf.Next = NULL; host->RootHubIf.Dev = &host->RootHubDev; diff --git a/KernelLand/Modules/USB/Core/usb_devinit.c b/KernelLand/Modules/USB/Core/usb_devinit.c index c5fd2ef3..5208ece7 100644 --- a/KernelLand/Modules/USB/Core/usb_devinit.c +++ b/KernelLand/Modules/USB/Core/usb_devinit.c @@ -51,7 +51,7 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) USB_int_SendSetupSetAddress(dev->Host, dev->Address); LOG("Assigned address %i", dev->Address); - dev->EndpointHandles[0] = dev->Host->HostDef->InitControl(dev->Host->Ptr, dev->Address << 4); + dev->EndpointHandles[0] = dev->Host->HostDef->InitControl(dev->Host->Ptr, dev->Address << 4, 64); for( int i = 1; i < 16; i ++ ) dev->EndpointHandles[i] = 0; @@ -256,7 +256,14 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize)); LOG(" .PollingInterval = %i", endpt->PollingInterval); LOG("}"); - + + // Make sure things don't break + if( !((endpt->Address & 0x7F) < 15) ) { + Log_Error("USB", "Endpoint number %i>16", endpt->Address & 0x7F); + k --; + continue ; + } + dev_if->Endpoints[k].Next = NULL; dev_if->Endpoints[k].Interface = dev_if; dev_if->Endpoints[k].EndpointIdx = k; @@ -268,6 +275,31 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) dev_if->Endpoints[k].InputData = NULL; // TODO: Register endpoint early + int ep_num = endpt->Address & 15; + if( dev->EndpointHandles[ep_num] ) { + Log_Notice("USB", "Device %p:%i ep %i reused", dev->Host->Ptr, dev->Address, ep_num); + } + else { + int addr = dev->Address*16+ep_num; + int mps = dev_if->Endpoints[k].MaxPacketSize; + void *handle = NULL; + switch( endpt->Attributes & 3) + { + case 0: // Control + handle = dev->Host->HostDef->InitControl(dev->Host->Ptr, addr, mps); + break; + case 1: // Isochronous + // handle = dev->Host->HostDef->InitIsoch(dev->Host->Ptr, addr, mps); + break; + case 2: // Bulk + handle = dev->Host->HostDef->InitBulk(dev->Host->Ptr, addr, mps); + break; + case 3: // Interrupt + // handle = dev->Host->HostDef->InitInterrupt(dev->Host->Ptr, addr, ...); + break; + } + dev->EndpointHandles[ep_num] = handle; + } } // Initialise driver diff --git a/KernelLand/Modules/USB/Core/usb_io.c b/KernelLand/Modules/USB/Core/usb_io.c index 346c4cd7..de6f6f11 100644 --- a/KernelLand/Modules/USB/Core/usb_io.c +++ b/KernelLand/Modules/USB/Core/usb_io.c @@ -61,9 +61,9 @@ void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *D dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum]; LOG("dest_hdl = %p", dest_hdl); if( !dest_hdl ) { - dest_hdl = host->HostDef->InitControl(host->Ptr, Dev->Dev->Address*16 + ep->EndpointNum); - Dev->Dev->EndpointHandles[ep->EndpointNum] = dest_hdl; - LOG("dest_hdl = %p (allocated)", dest_hdl); + Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum); + LEAVE('-'); + return; } Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); @@ -85,9 +85,9 @@ void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data) dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum]; LOG("dest_hdl = %p", dest_hdl); if( !dest_hdl ) { - dest_hdl = host->HostDef->InitControl(host->Ptr, Dev->Dev->Address*16 + ep->EndpointNum); - Dev->Dev->EndpointHandles[ep->EndpointNum] = dest_hdl; - LOG("dest_hdl = %p (allocated)", dest_hdl); + Log_Notice("USB", "_RecvData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum); + LEAVE('-'); + return; } Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); @@ -114,9 +114,9 @@ void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBu host = Dev->Dev->Host; dest_hdl = Dev->Dev->EndpointHandles[op->Endpt->EndpointNum]; if( !dest_hdl ) { - dest_hdl = host->HostDef->InitControl(host->Ptr, Dev->Dev->Address*16 + op->Endpt->EndpointNum); - Dev->Dev->EndpointHandles[op->Endpt->EndpointNum] = dest_hdl; - LOG("dest_hdl = %p (allocated)", dest_hdl); + Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, op->Endpt->EndpointNum); + LEAVE('-'); + return; } LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum); diff --git a/KernelLand/Modules/USB/Core/usb_lowlevel.c b/KernelLand/Modules/USB/Core/usb_lowlevel.c index 4c62c3b1..57948cec 100644 --- a/KernelLand/Modules/USB/Core/usb_lowlevel.c +++ b/KernelLand/Modules/USB/Core/usb_lowlevel.c @@ -41,8 +41,8 @@ void *USB_int_Request(tUSBDevice *Device, int EndPt, int Type, int Req, int Val, dest_hdl = Device->EndpointHandles[EndPt]; if( !dest_hdl ) { - dest_hdl = Host->HostDef->InitControl(Host->Ptr, Device->Address*16 + EndPt); - Device->EndpointHandles[EndPt] = dest_hdl; + LEAVE('n'); + return NULL; } req.ReqType = Type; @@ -95,8 +95,7 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i dest_hdl = Dev->EndpointHandles[Endpoint]; if( !dest_hdl ) { - dest_hdl = Dev->Host->HostDef->InitControl(Dev->Host->Ptr, Dev->Address*16 + Endpoint); - Dev->EndpointHandles[Endpoint] = dest_hdl; + return -1; } ENTER("pDev xEndpoint iType iIndex iLength pDest", diff --git a/KernelLand/Modules/USB/EHCI/ehci.c b/KernelLand/Modules/USB/EHCI/ehci.c index d2e048ba..14b1cfa1 100644 --- a/KernelLand/Modules/USB/EHCI/ehci.c +++ b/KernelLand/Modules/USB/EHCI/ehci.c @@ -12,6 +12,7 @@ #include #include "ehci.h" #include +#include // === CONSTANTS === #define EHCI_MAX_CONTROLLERS 4 @@ -23,9 +24,9 @@ void EHCI_InterruptHandler(int IRQ, void *Ptr); // -- API --- void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bInput, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); -void *EHCI_InitIsoch (void *Ptr, int Endpoint); -void *EHCI_InitControl(void *Ptr, int Endpoint); -void *EHCI_InitBulk (void *Ptr, int Endpoint); +void *EHCI_InitIsoch (void *Ptr, int Endpoint, size_t MaxPacketSize); +void *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize); +void *EHCI_InitBulk (void *Ptr, int Endpoint, size_t MaxPacketSize); void EHCI_RemEndpoint(void *Ptr, void *Handle); void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int isOutbound, @@ -34,6 +35,13 @@ void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, void *InData, size_t InLength ); void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length); +void EHCI_FreeOp(void *Ptr, void *Handle); +// --- Internals --- +tEHCI_qTD *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData); +void EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD); +void EHCI_int_AppendTD(tEHCI_QH *QH, tEHCI_qTD *TD); +tEHCI_QH *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize); +void EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH); // === GLOBALS === MODULE_DEFINE(0, VERSION, USB_EHCI, EHCI_Initialise, NULL, "USB_Core", NULL); @@ -46,7 +54,7 @@ tUSBHostDef gEHCI_HostDef = { .SendIsoch = NULL, .SendControl = EHCI_SendControl, .SendBulk = EHCI_SendBulk, - .FreeOp = NULL + .FreeOp = EHCI_FreeOp }; // === CODE === @@ -101,6 +109,7 @@ int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum) // - Allocate periodic queue cont->PeriodicQueue = (void*)MM_AllocDMA(1, 32, NULL); // TODO: Error check + // > Populate queue // -- Bind IRQ -- IRQ_AddHandler(InterruptNum, EHCI_InterruptHandler, cont); @@ -153,31 +162,190 @@ void EHCI_InterruptHandler(int IRQ, void *Ptr) // -------------------------------------------------------------------- // USB API // -------------------------------------------------------------------- -void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bInput, int Period, +void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) { + tEHCI_Controller *Cont = Ptr; + int pow2period, period_pow; + if( Endpoint >= 256*16 ) + return NULL; + if( Period <= 0 ) + return NULL; + if( Period > 256 ) + Period = 256; + + // Round the period to the closest power of two + pow2period = 1; + period_pow = 0; + // - Find the first power above the period + while( pow2period < Period ) + { + pow2period *= 2; + period_pow ++; + } + // - Check which is closest + if( Period - pow2period / 2 > pow2period - Period ) + Period = pow2period; + else { + Period = pow2period/2; + period_pow --; + } + + // Allocate a QH + tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, Length); + qh->Impl.IntPeriodPow = period_pow; + + // Choose an interrupt slot to use + int minslot = 0, minslot_load = INT_MAX; + for( int slot = 0; slot < Period; slot ++ ) + { + int load = 0; + for( int i = 0; i < PERIODIC_SIZE; i += Period ) + load += Cont->InterruptLoad[i+slot]; + if( load == 0 ) break; + if( load < minslot_load ) { + minslot = slot; + minslot_load = load; + } + } + // Increase loading on the selected slot + for( int i = 0; i < PERIODIC_SIZE; i += Period ) + Cont->InterruptLoad[i+minslot] += Length; + qh->Impl.IntOfs = minslot; + + // Allocate TD for the data + tEHCI_qTD *td = EHCI_int_AllocateTD(Cont, (bOutbound ? PID_OUT : PID_IN), Buf, Length, Cb, CbData); + EHCI_int_AppendTD(qh, td); + + // Insert into the periodic list + + return qh; } -void *EHCI_InitIsoch(void *Ptr, int Endpoint) +void *EHCI_InitIsoch(void *Ptr, int Endpoint, size_t MaxPacketSize) { - return NULL; + return (void*)(Endpoint + 1); } -void *EHCI_InitControl(void *Ptr, int Endpoint) +void *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize) { - return NULL; + tEHCI_Controller *Cont = Ptr; + + // Allocate a QH + tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, MaxPacketSize); + + // Append to async list + if( Cont->LastAsyncHead ) { + Cont->LastAsyncHead->HLink = MM_GetPhysAddr(qh)|2; + Cont->LastAsyncHead->Impl.Next = qh; + } + else + Cont->OpRegs->AsyncListAddr = MM_GetPhysAddr(qh)|2; + Cont->LastAsyncHead = qh; + + return qh; } -void *EHCI_InitBulk(void *Ptr, int Endpoint) +void *EHCI_InitBulk(void *Ptr, int Endpoint, size_t MaxPacketSize) { - return NULL; + return EHCI_InitControl(Ptr, Endpoint, MaxPacketSize); } -void EHCI_RemEndpoint(void *Ptr, void *Handle); -void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, +void EHCI_RemEndpoint(void *Ptr, void *Handle) +{ + if( Handle == NULL ) + return ; + else if( (tVAddr)Handle <= 256*16 ) + return ; // Isoch + else { + // Remove QH from list + // - If it's a polling endpoint, need to remove from all periodic lists + + // Deallocate QH + EHCI_int_DeallocateQH(Ptr, Handle); + } +} + +void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int isOutbound, const void *SetupData, size_t SetupLength, const void *OutData, size_t OutLength, void *InData, size_t InLength - ); -void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length); + ) +{ + tEHCI_Controller *Cont = Ptr; + tEHCI_qTD *td_setup, *td_data, *td_status; + + // Sanity checks + if( (tVAddr)Dest <= 256*16 ) + return NULL; + + // Check size of SETUP and status + + // Allocate TDs + td_setup = EHCI_int_AllocateTD(Cont, PID_SETUP, (void*)SetupData, SetupLength, NULL, NULL); + if( isOutbound ) + { + td_data = EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, NULL, NULL); + td_status = EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, Cb, CbData); + } + else + { + td_data = EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, NULL, NULL); + td_status = EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, Cb, CbData); + } + + // Append TDs + EHCI_int_AppendTD(Dest, td_setup); + EHCI_int_AppendTD(Dest, td_data); + EHCI_int_AppendTD(Dest, td_status); + + return td_status; +} + +void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length) +{ + tEHCI_Controller *Cont = Ptr; + + // Sanity check the pointer + // - Can't be NULL or an isoch + if( (tVAddr)Dest <= 256*16 ) + return NULL; + + // Allocate single TD + tEHCI_qTD *td = EHCI_int_AllocateTD(Cont, (Dir ? PID_OUT : PID_IN), Data, Length, Cb, CbData); + EHCI_int_AppendTD(Dest, td); + return td; +} + +void EHCI_FreeOp(void *Ptr, void *Handle) +{ + tEHCI_Controller *Cont = Ptr; + + EHCI_int_DeallocateTD(Cont, Handle); +} + +// -------------------------------------------------------------------- +// Internals +// -------------------------------------------------------------------- +tEHCI_qTD *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData) +{ + return NULL; +} + +void EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD) +{ +} + +void EHCI_int_AppendTD(tEHCI_QH *QH, tEHCI_qTD *TD) +{ +} + +tEHCI_QH *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize) +{ + return NULL; +} + +void EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH) +{ +} diff --git a/KernelLand/Modules/USB/EHCI/ehci.h b/KernelLand/Modules/USB/EHCI/ehci.h index 120c2f43..f76b93be 100644 --- a/KernelLand/Modules/USB/EHCI/ehci.h +++ b/KernelLand/Modules/USB/EHCI/ehci.h @@ -8,6 +8,8 @@ #ifndef _EHCI_H_ #define _EHCI_H_ +#define PERIODIC_SIZE 1024 + typedef struct sEHCI_CapRegs tEHCI_CapRegs; typedef struct sEHCI_OpRegs tEHCI_OpRegs; typedef struct sEHCI_iTD tEHCI_iTD; @@ -172,6 +174,7 @@ struct sEHCI_OpRegs #define USBINTR_HostSystemError 0x0010 #define USBINTR_AsyncAdvance 0x0020 +// Isochronous (High-Speed) Transfer Descriptor struct sEHCI_iTD { Uint32 Link; @@ -189,6 +192,7 @@ struct sEHCI_iTD Uint32 BufferPointers[8]; // Page aligned, low 12 bits are overloaded }; +// Split Transaction Isochronous Transfer Descriptor struct sEHCI_siTD { Uint32 Link; @@ -200,14 +204,22 @@ struct sEHCI_siTD 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 @@ -215,7 +227,17 @@ struct sEHCI_QH Uint32 EndpointExt; Uint32 CurrentTD; tEHCI_qTD Overlay; -}; + struct { + Uint8 IntOfs; + Uint8 IntPeriodPow; + tEHCI_QH *Next; + } Impl; +} __attribute__((aligned(32))); +// sizeof = 48 (64) + +#define PID_OUT 0 +#define PID_IN 1 +#define PID_SETUP 2 struct sEHCI_Controller { @@ -223,7 +245,14 @@ struct sEHCI_Controller tEHCI_CapRegs *CapRegs; tEHCI_OpRegs *OpRegs; + int InterruptLoad[PERIODIC_SIZE]; + tEHCI_QH *LastAsyncHead; + Uint32 *PeriodicQueue; + tEHCI_QH PeriodicQueueV[PERIODIC_SIZE]; + + tEHCI_QH *QHPools[(256*16)*sizeof(tEHCI_QH)/PAGE_SIZE]; // [PAGE_SIZE/64] + tEHCI_qTD *TDPool[PAGE_SIZE/sizeof(tEHCI_qTD)]; }; #endif diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index 61b71cad..636cd74c 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.c +++ b/KernelLand/Modules/USB/UHCI/uhci.c @@ -36,9 +36,9 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD); tUHCI_TD *UHCI_int_CreateTD(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); // --- API void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len); -void *UHCI_InitIsoch(void *Ptr, int Endpt); -void *UHCI_InitControl(void *Ptr, int Endpt); -void *UHCI_InitBulk(void *Ptr, int Endpt); +void *UHCI_InitIsoch(void *Ptr, int Endpt, size_t MaxPacketSize); +void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize); +void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize); void UHCI_RemoveEndpoint(void *Ptr, void *EndptHandle); void *UHCI_SendIsoch(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length, int When); void *UHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, @@ -512,22 +512,54 @@ void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound, return td; } -void *UHCI_InitControl(void *Ptr, int Endpt) +void *UHCI_int_InitEndpt(tUHCI_Controller *Cont, int Type, int Endpt, size_t MaxPacketSize) { - // TODO: Bitmap of tgl values + if( Endpt >= 256*16 ) + return NULL; + + if( MaxPacketSize > MAX_PACKET_SIZE) { + Log_Warning("UHCI", "MaxPacketSize for %x greater than controller max (%i > %i)", + Endpt, MaxPacketSize, MAX_PACKET_SIZE); + return NULL; + } + + if( Cont->DevInfo[Endpt / 16] == NULL ) { + Cont->DevInfo[Endpt / 16] = calloc( 1, sizeof(*Cont->DevInfo[0]) ); + } + tUHCI_EndpointInfo *epi = &Cont->DevInfo[Endpt/16]->EndpointInfo[Endpt%16]; + if( epi->Type ) { + // oops, in use + Log_Warning("UHCI", "Endpoint %x reused?", Endpt); + return NULL; + } + + epi->MaxPacketSize = MaxPacketSize; + epi->Type = Type; + epi->Tgl = 0; + return (void*)(Endpt+1); + } -void *UHCI_InitBulk(void *Ptr, int Endpt) +void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize) { - // TODO: Bitmap of tgl values - return (void*)(Endpt+1); + return UHCI_int_InitEndpt(Ptr, 1, Endpt, MaxPacketSize); +} + +void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize) +{ + return UHCI_int_InitEndpt(Ptr, 2, Endpt, MaxPacketSize); } void UHCI_RemoveEndpoint(void *Ptr, void *Handle) { - if( (int)Handle < 0x7FF ) { - + tUHCI_Controller *Cont = Ptr; + if( Handle == NULL ) + return ; + + if( (tVAddr)Handle <= 256*16 ) { + int addr = (tVAddr)Handle; + Cont->DevInfo[addr/16]->EndpointInfo[addr%16].Type = 0; } else { // TODO: Stop interrupt transaction @@ -547,8 +579,9 @@ void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, tUHCI_Controller *Cont = Ptr; tUHCI_QH *qh = &Cont->TDQHPage->ControlQH; tUHCI_TD *td; - int Dest = (int)Endpt-1; - int Tgl = 0; + tUHCI_EndpointInfo *epi; + int dest, tgl; + size_t mps; if( Endpt == NULL ) { Log_Error("UHCI", "Passed a NULL Endpoint handle"); @@ -561,10 +594,12 @@ void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, LEAVE('n'); return NULL; } - // if( Cont->Devs[Dest/16] == NULL ) LEAVE_RET('n', NULL); - // if( Cont->Devs[Dest/16].EndPt[Dest%16].Type != 1 ) LEAVE_RET('n', NULL); - // MAX_PACKET_SIZE = Cont->Devs[Dest/16].EndPt[Dest%16].MPS; - // Tgl = Cont->Devs[Dest/16].EndPt[Dest%16].Tgl; + dest = (tVAddr)Endpt - 1; + if( Cont->DevInfo[dest/16] == NULL ) LEAVE_RET('n', NULL); + epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16]; + if( epi->Type != 1 ) LEAVE_RET('n', NULL); + mps = epi->MaxPacketSize; + tgl = epi->Tgl; // TODO: Build up list and then append to QH in one operation @@ -582,32 +617,33 @@ void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, } // Sanity check data lengths - if( SetupLength > MAX_PACKET_SIZE ) LEAVE_RET('n', NULL); - if( status_len > MAX_PACKET_SIZE ) LEAVE_RET('n', NULL); + if( SetupLength > mps ) LEAVE_RET('n', NULL); + if( status_len > mps ) LEAVE_RET('n', NULL); // Create and append SETUP packet - td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, (void*)SetupData, SetupLength); + td = UHCI_int_CreateTD(Cont, dest, PID_SETUP, tgl, NULL, NULL, (void*)SetupData, SetupLength); UHCI_int_AppendTD(Cont, qh, td); - Tgl = !Tgl; + tgl = !tgl; - // Data packets + // Send data packets while( data_len > 0 ) { - size_t len = MIN(data_len, MAX_PACKET_SIZE); - td = UHCI_int_CreateTD(Cont, Dest, data_pid, Tgl, NULL, NULL, data_ptr, len); + size_t len = MIN(data_len, mps); + td = UHCI_int_CreateTD(Cont, dest, data_pid, tgl, NULL, NULL, data_ptr, len); UHCI_int_AppendTD(Cont, qh, td); - Tgl = !Tgl; + tgl = !tgl; data_ptr += len; data_len -= len; - // TODO: Handle multi-packet } - td = UHCI_int_CreateTD(Cont, Dest, status_pid, Tgl, Cb, CbData, status_ptr, status_len); + // Send status + td = UHCI_int_CreateTD(Cont, dest, status_pid, tgl, Cb, CbData, status_ptr, status_len); UHCI_int_AppendTD(Cont, qh, td); - Tgl = !Tgl; + tgl = !tgl; - // Cont->Devs[Dest/16].EndPt[Dest%16].Tgl = !Tgl; + // Update toggle value + epi->Tgl = tgl; LEAVE('p', td); return td; @@ -618,35 +654,55 @@ void *UHCI_SendBulk(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, int bOu tUHCI_Controller *Cont = Ptr; tUHCI_QH *qh = &Cont->TDQHPage->BulkQH; tUHCI_TD *td = NULL; - int Dest = (int)Endpt - 1; - int Tgl = 0; + tUHCI_EndpointInfo *epi; + int dest, tgl; + size_t mps; ENTER("pPtr pEndpt pCb pCbData bOutbound pData iLength", Ptr, Dest, Cb, CbData, bOutbound, Data, Length); if( Endpt == NULL ) { - Log_Error("UHCI", "Passed a NULL Endpoint handle"); + Log_Error("UHCI", "_SendBulk passed a NULL endpoint handle"); LEAVE('n'); return NULL; } // Sanity check Endpt - // TODO: Validation - // TODO: Data toggle + if( (tVAddr)Endpt > 256*16 ) { + Log_Error("UHCI", "_SendBulk passed an interrupt endpoint handle"); + LEAVE('n'); + return NULL; + } + dest = (tVAddr)Endpt - 1; + if( Cont->DevInfo[dest/16] == NULL ) { + Log_Error("UHCI", "_SendBulk passed an uninitialised handle"); + LEAVE('n'); + return NULL; + } + epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16]; + if( epi->Type != 2 ) { + Log_Error("UHCI", "_SendBulk passed an invalid endpoint type (%i!=2)", epi->Type); + LEAVE('n'); + return NULL; + } + tgl = epi->Tgl; + mps = epi->MaxPacketSize; Uint8 pid = (bOutbound ? PID_OUT : PID_IN); char *pos = Data; while( Length > 0 ) { - size_t len = MIN(MAX_PACKET_SIZE, Length); + size_t len = MIN(mps, Length); - td = UHCI_int_CreateTD(Cont, Dest, pid, Tgl, Cb, (len == Length ? CbData : NULL), pos, len); + td = UHCI_int_CreateTD(Cont, dest, pid, tgl, Cb, (len == Length ? CbData : NULL), pos, len); UHCI_int_AppendTD(Cont, qh, td); pos += len; Length -= len; - Tgl = !Tgl; + tgl = !tgl; } + + epi->Tgl = tgl; LEAVE('p', td); return td; diff --git a/KernelLand/Modules/USB/UHCI/uhci.h b/KernelLand/Modules/USB/UHCI/uhci.h index 6eff0ebd..fbbeba32 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.h +++ b/KernelLand/Modules/USB/UHCI/uhci.h @@ -8,6 +8,7 @@ // === TYPES === typedef struct sUHCI_Controller tUHCI_Controller; +typedef struct sUHCI_EndpointInfo tUHCI_EndpointInfo; typedef struct sUHCI_ExtraTDInfo tUHCI_ExtraTDInfo; typedef struct sUHCI_TD tUHCI_TD; @@ -24,8 +25,14 @@ struct sUHCI_ExtraTDInfo void *CallbackPtr; }; -#define TD_CTL_IOC (1 << 24) +struct sUHCI_EndpointInfo +{ + unsigned MaxPacketSize : 12; + unsigned Type : 3; + unsigned Tgl : 1; +}; +#define TD_CTL_IOC (1 << 24) #define TD_CTL_ACTIVE (1 << 23) #define TD_CTL_STALLED (1 << 22) #define TD_CTL_DATABUFERR (1 << 21) @@ -113,7 +120,6 @@ struct sUHCI_QH */ Uint32 Next; - /** * \brief Next Entry in list * @@ -200,6 +206,10 @@ struct sUHCI_Controller tUHCI_TD LocalTDPool[ (4096-(128+2)*sizeof(tUHCI_QH)) / sizeof(tUHCI_TD) ]; } *TDQHPage; + + struct { + tUHCI_EndpointInfo EndpointInfo[16]; + } *DevInfo[256]; }; // === ENUMERATIONS === -- 2.20.1