USB - Changed HC API to reflect more advanced features
authorJohn Hodge <[email protected]>
Mon, 6 Aug 2012 07:29:45 +0000 (15:29 +0800)
committerJohn Hodge <[email protected]>
Mon, 6 Aug 2012 07:29:45 +0000 (15:29 +0800)
- NOTE: USB code currently uses the UHCI behavior and doesn't call
  the InitControl/etc functions (except for interrupts)

KernelLand/Modules/USB/Core/include/usb_host.h
KernelLand/Modules/USB/Core/usb_devinit.c
KernelLand/Modules/USB/Core/usb_io.c
KernelLand/Modules/USB/Core/usb_lowlevel.c
KernelLand/Modules/USB/Core/usb_poll.c
KernelLand/Modules/USB/EHCI/ehci.c
KernelLand/Modules/USB/UHCI/uhci.c

index ab37279..87603db 100644 (file)
@@ -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);
 };
index d260f62..821cf30 100644 (file)
@@ -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);
index 9d58c75..9a3c417 100644 (file)
@@ -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('-');
 
index dce7c33..7cea58a 100644 (file)
@@ -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;
 }
index 9cdd6b4..a32e08e 100644 (file)
@@ -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
                );
index 87d84b6..d2e048b 100644 (file)
@@ -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);
+
+
index 257171a..9c5a4bd 100644 (file)
@@ -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;

UCC git Repository :: git.ucc.asn.au