From: John Hodge Date: Mon, 6 Aug 2012 07:29:45 +0000 (+0800) Subject: USB - Changed HC API to reflect more advanced features X-Git-Tag: rel0.15~706^2~69 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;ds=sidebyside;h=5db5602b547aa66aa115a9dbb4360fa3633e620e;p=tpg%2Facess2.git USB - Changed HC API to reflect more advanced features - NOTE: USB code currently uses the UHCI behavior and doesn't call the InitControl/etc functions (except for interrupts) --- diff --git a/KernelLand/Modules/USB/Core/include/usb_host.h b/KernelLand/Modules/USB/Core/include/usb_host.h index ab372797..87603dbd 100644 --- a/KernelLand/Modules/USB/Core/include/usb_host.h +++ b/KernelLand/Modules/USB/Core/include/usb_host.h @@ -15,24 +15,40 @@ typedef struct sUSBHostDef tUSBHostDef; typedef void (*tUSBHostCb)(void *DataPtr, void *Data, size_t Length); -typedef void *(*tUSBHostOp)(void *Ptr, int Dest, int DataTgl, tUSBHostCb CB, void *CbData, void *Data, size_t Length); -typedef void *(*tUSBIntOp)(void *Ptr, int Dest, int Period, tUSBHostCb CB, void *CbData, 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 *(*tUSBDataOp)(void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); + +typedef void *(*tUSBControlOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, + int bOutbound, // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT + const void *SetupData, size_t SetupLength, + const void *OutData, size_t OutLength, + void *InData, size_t InLength + ); +typedef void *(*tUSBBulkOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, + int bOutbound, void *Data, size_t Length + ); +typedef void *(*tUSBIsochOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, + int bOutbound, void *Data, size_t Length, int When + ); /** * \brief Defines a USB Host Controller type */ struct sUSBHostDef { - tUSBIntOp InterruptIN; - tUSBIntOp InterruptOUT; - void (*StopInterrupt)(void *Ptr, void *Handle); - - void *(*ControlSETUP)(void *Ptr, int Dest, int DataTgl, void *Data, size_t Length); - tUSBHostOp ControlIN; - tUSBHostOp ControlOUT; + tUSBInitInt InitInterrupt; + tUSBInit InitIsoch; + tUSBInit InitControl; + tUSBInit InitBulk; + void (*RemEndpoint)(void *Ptr, void *Handle); - tUSBHostOp BulkIN; - tUSBHostOp BulkOUT; + // NOTE: If \a Cb is ERRPTR, the handle returned must be free'd by the calling code + // otherwise the controller will free it once done + tUSBIsochOp SendIsoch; + tUSBControlOp SendControl; + tUSBBulkOp SendBulk; + void (*FreeOp)(void *Ptr, void *Handle); void (*CheckPorts)(void *Ptr); }; diff --git a/KernelLand/Modules/USB/Core/usb_devinit.c b/KernelLand/Modules/USB/Core/usb_devinit.c index d260f627..821cf301 100644 --- a/KernelLand/Modules/USB/Core/usb_devinit.c +++ b/KernelLand/Modules/USB/Core/usb_devinit.c @@ -21,6 +21,7 @@ void USB_DeviceDisconnected(tUSBHub *Hub, int Port); void *USB_GetDeviceDataPtr(tUSBInterface *Dev); void USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr); int USB_int_AllocateAddress(tUSBHost *Host); +void USB_int_DeallocateAddress(tUSBHost *Host, int Address); // === CODE === void USB_DeviceConnected(tUSBHub *Hub, int Port) @@ -53,10 +54,24 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) // 2. Get device information { struct sDescriptor_Device desc; + desc.Length = 0; LOG("Getting device descriptor"); // Endpoint 0, Desc Type 1, Index 0 USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc); + if( desc.Length < sizeof(desc) ) { + Log_Error("USB", "Device descriptor undersized (%i<%i)", desc.Length, sizeof(desc)); + USB_int_DeallocateAddress(dev->Host, dev->Address); + LEAVE('-'); + return; + } + if( desc.Type != 1 ) { + Log_Error("USB", "Device descriptor type invalid (%i!=1)", desc.Type); + USB_int_DeallocateAddress(dev->Host, dev->Address); + LEAVE('-'); + return; + } + #if DUMP_DESCRIPTORS LOG("Device Descriptor = {"); LOG(" .Length = %i", desc.Length); @@ -75,7 +90,7 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) LOG(" .NumConfigurations = %i", desc.NumConfigurations); LOG("}"); - #if DEBUG + #if DEBUG if( desc.ManufacturerStr ) { char *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr); @@ -106,9 +121,8 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) memcpy(&dev->DevDesc, &desc, sizeof(desc)); } - // TODO: Support alternate configurations - // 3. Get configurations + // TODO: Support alternate configurations for( int i = 0; i < 1; i ++ ) { struct sDescriptor_Configuration desc; @@ -117,6 +131,12 @@ void USB_DeviceConnected(tUSBHub *Hub, int Port) size_t total_length; USB_int_ReadDescriptor(dev, 0, 2, i, sizeof(desc), &desc); + if( desc.Length < sizeof(desc) ) { + // ERROR: + } + if( desc.Type != 2 ) { + // ERROR: + } // TODO: Check return length? (Do we get a length?) #if DUMP_DESCRIPTORS LOG("Configuration Descriptor %i = {", i); diff --git a/KernelLand/Modules/USB/Core/usb_io.c b/KernelLand/Modules/USB/Core/usb_io.c index 9d58c750..9a3c4173 100644 --- a/KernelLand/Modules/USB/Core/usb_io.c +++ b/KernelLand/Modules/USB/Core/usb_io.c @@ -53,22 +53,14 @@ void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *D { tUSBHost *host; tUSBEndpoint *ep; + void *dest_hdl = (void*)(Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum + 1); ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data); ep = &Dev->Endpoints[Endpoint-1]; host = Dev->Dev->Host; Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); - for( size_t ofs = 0; ofs < Length; ofs += ep->MaxPacketSize ) - { - size_t len = MIN(Length - ofs, ep->MaxPacketSize); - - host->HostDef->BulkOUT( - host->Ptr, Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum, - 0, (len == Length - ofs ? USB_WakeCallback : NULL), Proc_GetCurThread(), - (char*)Data + ofs, len - ); - } + host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 1, (void*)Data, Length); Threads_WaitEvents(THREAD_EVENT_SHORTWAIT); LEAVE('-'); @@ -78,22 +70,14 @@ void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data) { tUSBHost *host; tUSBEndpoint *ep; + void *dest_hdl = (void*)(Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum + 1); ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data); ep = &Dev->Endpoints[Endpoint-1]; host = Dev->Dev->Host; Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); - for( size_t ofs = 0; ofs < Length; ofs += ep->MaxPacketSize ) - { - size_t len = MIN(Length - ofs, ep->MaxPacketSize); - - host->HostDef->BulkIN( - host->Ptr, Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum, - 0, (len == Length - ofs ? USB_WakeCallback : NULL), Proc_GetCurThread(), - (char*)Data + ofs, len - ); - } + host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 0, Data, Length); Threads_WaitEvents(THREAD_EVENT_SHORTWAIT); LEAVE('-'); @@ -103,6 +87,7 @@ void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBu { tAsyncOp *op; tUSBHost *host; + void *dest_hdl = (void*)(Dev->Dev->Address*16 + Dev->Endpoints[Endpoint-1].EndpointNum + 1); ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf); @@ -118,16 +103,7 @@ void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBu host = Dev->Dev->Host; LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum); - for( size_t ofs = 0; ofs < Length; ofs += op->Endpt->MaxPacketSize ) - { - size_t len = MIN(Length - ofs, op->Endpt->MaxPacketSize); - - host->HostDef->BulkIN( - host->Ptr, Dev->Dev->Address*16 + op->Endpt->EndpointNum, - 0, (len == Length - ofs ? USB_AsyncCallback : NULL), op, - (char*)DataBuf + ofs, len - ); - } + host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_AsyncCallback, op, 0, DataBuf, Length); LEAVE('-'); diff --git a/KernelLand/Modules/USB/Core/usb_lowlevel.c b/KernelLand/Modules/USB/Core/usb_lowlevel.c index dce7c33a..7cea58aa 100644 --- a/KernelLand/Modules/USB/Core/usb_lowlevel.c +++ b/KernelLand/Modules/USB/Core/usb_lowlevel.c @@ -28,6 +28,7 @@ void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, in // TODO: Sanity check (and check that Type is valid) struct sDeviceRequest req; int dest = Addr * 16 + EndPt; // TODO: Validate + void *dest_hdl = (void*)(dest+1); // TODO: Get registered handle instead tThread *thisthread = Proc_GetCurThread(); ENTER("pHost xdest iType iReq iVal iIndx iLen pData", @@ -41,36 +42,22 @@ void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, in Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); - LOG("SETUP"); - hdl = Host->HostDef->ControlSETUP(Host->Ptr, dest, 0, &req, sizeof(req)); - - // TODO: Data toggle? - // TODO: Multi-packet transfers - if( Len > 0 ) - { - if( Type & 0x80 ) - { - LOG("IN"); - hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, NULL, NULL, Data, Len); - - LOG("OUT (Status)"); - hdl = Host->HostDef->ControlOUT(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0); - } - else - { - LOG("OUT"); - Host->HostDef->ControlOUT(Host->Ptr, dest, 1, NULL, NULL, Data, Len); - - // Status phase (DataToggle=1) - LOG("IN (Status)"); - hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0); - } + LOG("Send"); + if( Type & 0x80 ) { + // Inbound data + hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 0, + &req, sizeof(req), + NULL, 0, + Data, Len + ); } - else - { - // Zero length, IN status - LOG("IN (Status)"); - hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0); + else { + // Outbound data + hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 1, + &req, sizeof(req), + Data, Len, + NULL, 0 + ); } LOG("Wait..."); Threads_WaitEvents(THREAD_EVENT_SHORTWAIT); @@ -92,10 +79,9 @@ int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address) int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest) { - const int ciMaxPacketSize = 0x400; struct sDeviceRequest req; - int bToggle = 0; int dest = Dev->Address*16 + Endpoint; + void *dest_hdl = (void*)(dest+1); // TODO: Get correct handle ENTER("pDev xdest iType iIndex iLength pDest", Dev, dest, Type, Index, Length, Dest); @@ -109,36 +95,19 @@ int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, i req.Index = LittleEndian16( 0 ); // TODO: Language ID / Interface req.Length = LittleEndian16( Length ); - LOG("SETUP"); - Dev->Host->HostDef->ControlSETUP(Dev->Host->Ptr, dest, 0, &req, sizeof(req)); - - bToggle = 1; - while( Length > ciMaxPacketSize ) - { - LOG("IN (%i rem)", Length - ciMaxPacketSize); - Dev->Host->HostDef->ControlIN( - Dev->Host->Ptr, dest, - bToggle, NULL, NULL, - Dest, ciMaxPacketSize - ); - bToggle = !bToggle; - Length -= ciMaxPacketSize; - } - - LOG("IN (final)"); - Dev->Host->HostDef->ControlIN( Dev->Host->Ptr, dest, bToggle, NULL, NULL, Dest, Length ); - Threads_ClearEvent(THREAD_EVENT_SHORTWAIT); - LOG("OUT (Status)"); - Dev->Host->HostDef->ControlOUT( - Dev->Host->Ptr, dest, 1, - USB_int_WakeThread, Proc_GetCurThread(), - NULL, 0 + + LOG("Send"); + Dev->Host->HostDef->SendControl(Dev->Host->Ptr, dest_hdl, USB_int_WakeThread, Proc_GetCurThread(), 0, + &req, sizeof(req), + NULL, 0, + Dest, Length ); LOG("Waiting"); + // TODO: Detect errors? Threads_WaitEvents(THREAD_EVENT_SHORTWAIT); - + LEAVE('i', 0); return 0; } diff --git a/KernelLand/Modules/USB/Core/usb_poll.c b/KernelLand/Modules/USB/Core/usb_poll.c index 9cdd6b47..a32e08e4 100644 --- a/KernelLand/Modules/USB/Core/usb_poll.c +++ b/KernelLand/Modules/USB/Core/usb_poll.c @@ -61,10 +61,9 @@ void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint) endpt->InputData = malloc(endpt->MaxPacketSize); LOG("Polling 0x%x at %i ms", Iface->Dev->Address * 16 + endpt->EndpointNum, endpt->PollingPeriod); - Iface->Dev->Host->HostDef->InterruptIN( - Iface->Dev->Host->Ptr, - Iface->Dev->Address * 16 + endpt->EndpointNum, - endpt->PollingPeriod, + Iface->Dev->Host->HostDef->InitInterrupt( + Iface->Dev->Host->Ptr, Iface->Dev->Address * 16 + endpt->EndpointNum, + 0, endpt->PollingPeriod, USB_int_PollCallback, endpt, endpt->InputData, endpt->MaxPacketSize ); diff --git a/KernelLand/Modules/USB/EHCI/ehci.c b/KernelLand/Modules/USB/EHCI/ehci.c index 87d84b69..d2e048ba 100644 --- a/KernelLand/Modules/USB/EHCI/ehci.c +++ b/KernelLand/Modules/USB/EHCI/ehci.c @@ -26,14 +26,28 @@ void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bInput, int Period, tUSBHo void *EHCI_InitIsoch (void *Ptr, int Endpoint); void *EHCI_InitControl(void *Ptr, int Endpoint); void *EHCI_InitBulk (void *Ptr, int Endpoint); -void *EHCI_RemEndpoint(void *Ptr, void *Handle); -void *EHCI_SETUP(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); -void *EHCI_IN (void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); -void *EHCI_OUT (void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); +void EHCI_RemEndpoint(void *Ptr, void *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); // === GLOBALS === MODULE_DEFINE(0, VERSION, USB_EHCI, EHCI_Initialise, NULL, "USB_Core", NULL); tEHCI_Controller gaEHCI_Controllers[EHCI_MAX_CONTROLLERS]; +tUSBHostDef gEHCI_HostDef = { + .InitInterrupt = EHCI_InitInterrupt, + .InitIsoch = EHCI_InitIsoch, + .InitBulk = EHCI_InitBulk, + .RemEndpoint = EHCI_RemEndpoint, + .SendIsoch = NULL, + .SendControl = EHCI_SendControl, + .SendBulk = EHCI_SendBulk, + .FreeOp = NULL + }; // === CODE === int EHCI_Initialise(char **Arguments) @@ -98,7 +112,7 @@ int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum) // - Set USBINTR cont->OpRegs->USBIntr = USBINTR_IOC|USBINTR_PortChange|USBINTR_FrameRollover; // - Set PERIODICLIST BASE - cont->OpRegs->PeridocListBase = MM_GetPhysAddr( (tVAddr) cont->PeriodicQueue ); + cont->OpRegs->PeridocListBase = MM_GetPhysAddr( cont->PeriodicQueue ); // - Enable controller cont->OpRegs->USBCmd = (0x40 << 16) | USBCMD_PeriodicEnable | USBCMD_Run; // - Route all ports @@ -109,5 +123,61 @@ int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum) void EHCI_InterruptHandler(int IRQ, void *Ptr) { + tEHCI_Controller *cont = Ptr; + Uint32 sts = cont->OpRegs->USBSts; + + // Clear interrupts + cont->OpRegs->USBSts = sts; + + if( sts & USBINTR_IOC ) { + // IOC + sts &= ~USBINTR_IOC; + } + if( sts & USBINTR_PortChange ) { + // Port change, determine what port and poke helper thread + sts &= ~USBINTR_PortChange; + } + + if( sts & USBINTR_FrameRollover ) { + // Frame rollover, used to aid timing (trigger per-second operations) + sts &= ~USBINTR_FrameRollover; + } + + if( sts ) { + // Unhandled interupt bits + // TODO: Warn + } } + +// -------------------------------------------------------------------- +// USB 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) +{ + return NULL; +} +void *EHCI_InitControl(void *Ptr, int Endpoint) +{ + return NULL; +} +void *EHCI_InitBulk(void *Ptr, int Endpoint) +{ + return NULL; +} +void EHCI_RemEndpoint(void *Ptr, void *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); + + diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index 257171a8..9c5a4bd6 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.c +++ b/KernelLand/Modules/USB/UHCI/uhci.c @@ -35,14 +35,19 @@ tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont); 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_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); -void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); -void UHCI_StopInterrupt(void *Ptr, void *Handle); -void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length); -void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); -void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length); -void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); -void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length); +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_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, + int isOutbound, + const void *SetupData, size_t SetupLength, + const void *OutData, size_t OutLength, + void *InData, size_t InLength + ); +void *UHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length); void UHCI_CheckPortUpdate(void *Ptr); void UHCI_int_InterruptThread(void *Unused); @@ -58,18 +63,22 @@ MODULE_DEFINE(0, VERSION, USB_UHCI, UHCI_Initialise, NULL, "USB_Core", NULL); tUHCI_TD *gaUHCI_TDPool; tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS]; tUSBHostDef gUHCI_HostDef = { - .InterruptIN = UHCI_InterruptIN, - .InterruptOUT = UHCI_InterruptOUT, - .StopInterrupt = UHCI_StopInterrupt, + .InitInterrupt = UHCI_InitInterrupt, +// .InitIsoch = UHCI_InitIsoch, + .InitControl = UHCI_InitControl, + .InitBulk = UHCI_InitBulk, + .RemEndpoint = UHCI_RemoveEndpoint, - .ControlSETUP = UHCI_ControlSETUP, - .ControlIN = UHCI_ControlIN, - .ControlOUT = UHCI_ControlOUT, - - .BulkOUT = UHCI_BulkOUT, - .BulkIN = UHCI_BulkIN, +// .SendIsoch = UHCI_SendIsoch, + .SendControl = UHCI_SendControl, + .SendBulk = UHCI_SendBulk, + .FreeOp = NULL, - .CheckPorts = UHCI_CheckPortUpdate + .CheckPorts = UHCI_CheckPortUpdate, +// .ClearPortFeature = NULL, +// .GetBusState = NULL, +// .GetPortStatus = NULL, +// .SetPortFeature = NULL }; tSemaphore gUHCI_InterruptSempahore; @@ -481,135 +490,158 @@ void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period) UHCI_int_AppendTD(Cont, qh, TD); } -void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, 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) { tUHCI_TD *td; - - if( Period < 0 ) return NULL; - - ENTER("pPtr xDest iPeriod pCb pCbData pBuf iLength", - Ptr, Dest, Period, Cb, CbData, Buf, Length); + if( Period <= 0 ) return NULL; + + ENTER("pPtr xEndpt bbOutbound iPeriod pCb pCbData pBuf iLen", + Ptr, Endpt, bOutbound, Period, Cb, CbData, Buf, Len); // TODO: Data toggle? - td = UHCI_int_CreateTD(Ptr, Dest, PID_IN, 0, Cb, CbData, Buf, Length); + td = UHCI_int_CreateTD(Ptr, Endpt, (bOutbound ? PID_OUT : PID_IN), 0, Cb, CbData, Buf, Len); if( !td ) return NULL; UHCI_int_SetInterruptPoll(Ptr, td, Period); - - LEAVE('p', td); + + LEAVE('p', td); return td; } -// TODO: Does interrupt OUT make sense? -void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) -{ - tUHCI_TD *td; - - if( Period < 0 ) return NULL; - ENTER("pPtr xDest iPeriod pCb pCbData pBuf, iLength", - Ptr, Dest, Period, Cb, CbData, Buf, Length); - - // TODO: Data toggle? - td = UHCI_int_CreateTD(Ptr, Dest, PID_OUT, 0, Cb, CbData, Buf, Length); - if( !td ) return NULL; - - UHCI_int_SetInterruptPoll(Ptr, td, Period); +void *UHCI_InitControl(void *Ptr, int Endpt) +{ + // TODO: Bitmap of tgl values + return (void*)(Endpt+1); +} - LEAVE('p', td); - return td; +void *UHCI_InitBulk(void *Ptr, int Endpt) +{ + // TODO: Bitmap of tgl values + return (void*)(Endpt+1); } -void UHCI_StopInterrupt(void *Ptr, void *Handle) +void UHCI_RemoveEndpoint(void *Ptr, void *Handle) { - // TODO: Stop interrupt transaction - Log_Error("UHCI", "TODO: Implement UHCI_StopInterrupt"); + if( (int)Handle < 0x7FF ) { + + } + else { + // TODO: Stop interrupt transaction + Log_Error("UHCI", "TODO: Implement stopping interrupt polling"); + } } -void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length) +void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, + int bOutbound, // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT + const void *SetupData, size_t SetupLength, + const void *OutData, size_t OutLength, + void *InData, size_t InLength + ) { + ENTER("pPtr pEndpt ibOutbound", Ptr, Endpt, bOutbound); + tUHCI_Controller *Cont = Ptr; tUHCI_QH *qh = &Cont->TDQHPage->ControlQH; tUHCI_TD *td; + int Dest = (int)Endpt-1; + int Tgl = 0; - ENTER("pPtr xDest iTgl pData iLength", Ptr, Dest, Tgl, Data, Length); - - td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, Data, Length); - UHCI_int_AppendTD(Cont, qh, td); + // Sanity check Endpt + if( (tVAddr)Endpt > 0x7FF ) { + 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; - LEAVE('p', td); + // TODO: Build up list and then append to QH in one operation - return td; -} -void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length) -{ - tUHCI_Controller *Cont = Ptr; - tUHCI_QH *qh = &Cont->TDQHPage->ControlQH; - tUHCI_TD *td; + char *data_ptr, *status_ptr; + size_t data_len, status_len; + Uint8 data_pid, status_pid; + + if( bOutbound ) { + data_pid = PID_OUT; data_ptr = (void*)OutData; data_len = OutLength; + status_pid = PID_IN; status_ptr = InData; status_len = InLength; + } + else { + data_pid = PID_IN; data_ptr = InData; data_len = InLength; + status_pid = PID_OUT; status_ptr = (void*)OutData; status_len = OutLength; + } - ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length); + // Sanity check data lengths + if( SetupLength > MAX_PACKET_SIZE ) LEAVE_RET('n', NULL); + if( status_len > MAX_PACKET_SIZE ) LEAVE_RET('n', NULL); - td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, Tgl, Cb, CbData, Data, Length); + // Create and append SETUP packet + td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, (void*)SetupData, SetupLength); UHCI_int_AppendTD(Cont, qh, td); + Tgl = !Tgl; - LEAVE('p', td); - return td; -} -void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length) -{ - tUHCI_Controller *Cont = Ptr; - tUHCI_QH *qh = &Cont->TDQHPage->ControlQH; - tUHCI_TD *td; - - ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length); + // 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); + UHCI_int_AppendTD(Cont, qh, td); + Tgl = !Tgl; + + data_ptr += len; + data_len -= len; + // TODO: Handle multi-packet + } - td = UHCI_int_CreateTD(Cont, Dest, PID_IN, !!Tgl, Cb, CbData, Data, Length); + td = UHCI_int_CreateTD(Cont, Dest, status_pid, Tgl, Cb, CbData, status_ptr, status_len); UHCI_int_AppendTD(Cont, qh, td); - - LEAVE('p', td); + Tgl = !Tgl; + + // Cont->Devs[Dest/16].EndPt[Dest%16].Tgl = !Tgl; + + LEAVE('p', td); return td; } -void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) +void *UHCI_SendBulk(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, int bOutbound, void *Data, size_t Length) { tUHCI_Controller *Cont = Ptr; tUHCI_QH *qh = &Cont->TDQHPage->BulkQH; - tUHCI_TD *td; - char *src = Buf; + tUHCI_TD *td = NULL; + int Dest = (int)Endpt - 1; + int Tgl = 0; - ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length); + ENTER("pPtr pEndpt pCb pCbData bOutbound pData iLength", Ptr, Dest, Cb, CbData, bOutbound, Data, Length); - if( Length > MAX_PACKET_SIZE ) { - Log_Error("UHCI", "Passed an oversized packet by the USB code (%i > %i)", Length, MAX_PACKET_SIZE); - LEAVE('n'); - } - - td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, Cb, CbData, src, Length); - UHCI_int_AppendTD(Cont, qh, td); + // TODO: Validation + // TODO: Data toggle - LEAVE('p', td); - return td; -} -void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length) -{ - tUHCI_Controller *Cont = Ptr; - tUHCI_QH *qh = &Cont->TDQHPage->BulkQH; - tUHCI_TD *td; - char *dst = Buf; + Uint8 pid = (bOutbound ? PID_OUT : PID_IN); - ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length); - if( Length > MAX_PACKET_SIZE ) { - Log_Error("UHCI", "Passed an oversized packet by the USB code (%i > %i)", Length, MAX_PACKET_SIZE); - LEAVE('n'); - } + char *pos = Data; + while( Length > 0 ) + { + size_t len = MIN(MAX_PACKET_SIZE, Length); - td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, Cb, CbData, dst, Length); - UHCI_int_AppendTD(Cont, qh, td); + 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; + } LEAVE('p', td); return td; } +// ========================== // === INTERNAL FUNCTIONS === +// ========================== void UHCI_CheckPortUpdate(void *Ptr) { tUHCI_Controller *Host = Ptr;