USB - HC API Update
authorJohn Hodge <[email protected]>
Tue, 7 Aug 2012 09:02:38 +0000 (17:02 +0800)
committerJohn Hodge <[email protected]>
Tue, 7 Aug 2012 09:02:38 +0000 (17:02 +0800)
KernelLand/Modules/USB/Core/include/usb_host.h
KernelLand/Modules/USB/Core/usb.c
KernelLand/Modules/USB/Core/usb_devinit.c
KernelLand/Modules/USB/Core/usb_io.c
KernelLand/Modules/USB/Core/usb_lowlevel.c
KernelLand/Modules/USB/EHCI/ehci.c
KernelLand/Modules/USB/EHCI/ehci.h
KernelLand/Modules/USB/UHCI/uhci.c
KernelLand/Modules/USB/UHCI/uhci.h

index 87603db..8b4f96d 100644 (file)
@@ -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,
index ab2427a..9a0e2bc 100644 (file)
@@ -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;
index c5fd2ef..5208ece 100644 (file)
@@ -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
index 346c4cd..de6f6f1 100644 (file)
@@ -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);
index 4c62c3b..57948ce 100644 (file)
@@ -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",
index d2e048b..14b1cfa 100644 (file)
@@ -12,6 +12,7 @@
 #include <usb_host.h>
 #include "ehci.h"
 #include <drv_pci.h>
+#include <limits.h>
 
 // === 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)
+{
+}
 
index 120c2f4..f76b93b 100644 (file)
@@ -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
index 61b71ca..636cd74 100644 (file)
@@ -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;
index 6eff0eb..fbbeba3 100644 (file)
@@ -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 ===

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