Modules/UHCI - Big cleanups to code... but there is a bug somewhere
authorJohn Hodge <[email protected]>
Thu, 23 Feb 2012 16:04:28 +0000 (00:04 +0800)
committerJohn Hodge <[email protected]>
Thu, 23 Feb 2012 16:04:28 +0000 (00:04 +0800)
- After a while (i.e. before the mouse is set up) interrupts stop firing
  or the TDs aren't being processed properly

KernelLand/Modules/USB/UHCI/uhci.c
KernelLand/Modules/USB/UHCI/uhci.h

index b348a45..023d28c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Universal Host Controller Interface
  */
-#define DEBUG  0
+#define DEBUG  1
 #define VERSION        VER2(0,5)
 #include <acess.h>
 #include <vfs.h>
 #include <usb_host.h>
 #include "uhci.h"
 #include <timers.h>
+#include <semaphore.h>
 
 // === CONSTANTS ===
 #define        MAX_CONTROLLERS 4
-#define NUM_TDs        1024
+//#define NUM_TDs      1024
+#define NUM_TDs        64
 
 // === PROTOTYPES ===
  int   UHCI_Initialise(char **Arguments);
 void   UHCI_Cleanup();
 tUHCI_TD       *UHCI_int_AllocateTD(tUHCI_Controller *Cont);
-tUHCI_TD       *UHCI_int_GetTDFromPhys(tPAddr PAddr);
 void   UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD);
 void   *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
 void   *UHCI_DataIN(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
@@ -31,6 +32,7 @@ void  *UHCI_SendSetup(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbDa
  int   UHCI_IsTransferComplete(void *Ptr, void *Handle);
  int   UHCI_Int_InitHost(tUHCI_Controller *Host);
 void   UHCI_CheckPortUpdate(void *Ptr);
+void   UHCI_int_InterruptThread(void *Unused);
 void   UHCI_InterruptHandler(int IRQ, void *Ptr);
 // 
 static void    _OutByte(tUHCI_Controller *Host, int Reg, Uint8 Value);
@@ -49,6 +51,7 @@ tUSBHostDef   gUHCI_HostDef = {
        .IsOpComplete = UHCI_IsTransferComplete,
        .CheckPorts = UHCI_CheckPortUpdate
        };
+tSemaphore     gUHCI_InterruptSempahore;
 
 // === CODE ===
 /**
@@ -62,6 +65,18 @@ int UHCI_Initialise(char **Arguments)
        
        ENTER("");
        
+       // Initialise with no maximum value
+       Semaphore_Init( &gUHCI_InterruptSempahore, 0, 0, "UHCI", "Interrupt Queue");
+
+       if( PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, -1) < 0 )
+       {
+               LEAVE('i', MODULE_ERR_NOTNEEDED);
+               return MODULE_ERR_NOTNEEDED;
+       }
+       
+       // Spin off interrupt handling thread
+       Proc_SpawnWorker( UHCI_int_InterruptThread, NULL );
+
        // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices
        while( (id = PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
        {
@@ -102,11 +117,6 @@ int UHCI_Initialise(char **Arguments)
                i ++;
        }
 
-       if(i == 0) {
-               LEAVE('i', MODULE_ERR_NOTNEEDED);
-               return MODULE_ERR_NOTNEEDED;
-       }
-
        if(i == MAX_CONTROLLERS) {
                Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");
        }
@@ -124,87 +134,65 @@ void UHCI_Cleanup()
 
 tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont)
 {
-        int    i;
-       for(i = 0; i < NUM_TDs; i ++)
+       static tMutex   lock;
+       Mutex_Acquire( &lock );
+       for( int i = 0; i < NUM_TDs; i ++ )
        {
-               if(gaUHCI_TDPool[i].Link == 0) {
+               if(gaUHCI_TDPool[i]._info.bActive == 0)
+               {
                        gaUHCI_TDPool[i].Link = 1;
-                       gaUHCI_TDPool[i].Control = 1 << 23;
+                       gaUHCI_TDPool[i].Control = (1 << 23);
+                       gaUHCI_TDPool[i]._info.bActive = 1;
+                       gaUHCI_TDPool[i]._info.bComplete = 0;
+                       Mutex_Release( &lock );
                        return &gaUHCI_TDPool[i];
                }
-               // Still in use? Skip
-               if( gaUHCI_TDPool[i].Control & (1 << 23) )
-                       continue ;
-               // Is there a callback on it? Skip
-               if( gaUHCI_TDPool[i]._info.Callback )
-                       continue ;
-               // TODO: Garbage collect, but that means removing from the list too
-               #if 0
-               // Ok, this is actually unused
-               gaUHCI_TDPool[i].Link = 1;
-               gaUHCI_TDPool[i].Control = 1 << 23;
-               return &gaUHCI_TDPool[i];
-               #endif
        }
+       Mutex_Release( &lock );
        return NULL;
 }
 
-tUHCI_TD *UHCI_int_GetTDFromPhys(tPAddr PAddr)
-{
-       // TODO: Fix this to work with a non-contiguous pool
-       static tPAddr   td_pool_base;
-       const int pool_size = NUM_TDs;
-        int    offset;
-       if(!td_pool_base)       td_pool_base = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
-       offset = (PAddr - td_pool_base) / sizeof(gaUHCI_TDPool[0]);
-       if( offset < 0 || offset >= pool_size )
-       {
-               Log_Error("UHCI", "TD PAddr %P not from pool", PAddr);
-               return NULL;
-       }
-       return gaUHCI_TDPool + offset;
-}
-
 void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
 {
-        int    next_frame;
-       tUHCI_TD        *prev_td;
-       Uint32  link;
+       static tMutex   lock;   // TODO: Should I use a shortlock (avoid being preempted)
 
-       ENTER("pCont pTD", Cont, TD);
+       Mutex_Acquire(&lock);
+       
+       #if 0
+        int    next_frame;
 
-       // TODO: How to handle FRNUM incrementing while we are in this function?
        next_frame = (_InWord(Cont, FRNUM) + 2) & (1024-1);
+
+       TD->Control |= (1 << 24);       // Ensure that there is an interrupt for each used frame
        
-       // Empty list
-       if( Cont->FrameList[next_frame] & 1 )
-       {
-               // TODO: Ensure 32-bit paddr
-               Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD );
-               TD->Control |= (1 << 24);       // Ensure that there is an interrupt for each used frame
-               LOG("next_frame = %i", next_frame);
-               LEAVE('-');
-               return;
-       }
+       TD->Link = Cont->FrameList[next_frame];
+       Cont->FrameList[next_frame] = MM_GetPhysAddr( (tVAddr)TD );
+       #else
 
-       // Find the end of the list
-       link = Cont->FrameList[next_frame];
-       do {
-               prev_td = UHCI_int_GetTDFromPhys(link);
-               if(!prev_td) {
-                       Log_Error("UHCI", "ERROR: TD list is bad");
-                       TD->Link = 1;
-                       LEAVE('-');
-                       return ;
-               }
-               link = prev_td->Link;
-       } while( !(link & 1) );
+       // TODO: Support other QHs
+       tUHCI_QH *qh = &Cont->BulkQH;
        
-       // Append
-       prev_td->Link = MM_GetPhysAddr( (tVAddr)TD );
+       // Ensure that there is an interrupt for each used frame
+       TD->Control |= (1 << 24);
 
-       LOG("next_frame = %i, prev_td = %p", next_frame, prev_td);
-       LEAVE('-');
+       // Stop controller
+       _OutWord( Cont, USBCMD, 0x0000 );
+       
+       // Add
+       TD->Link = 1;
+       if( qh->Child & 1 ) {
+               qh->Child = MM_GetPhysAddr( (tVAddr)TD );
+       }
+       else {
+               qh->_LastItem->Link = MM_GetPhysAddr( (tVAddr)TD );
+       }
+       qh->_LastItem = TD;
+
+       // Reenable controller
+       _OutWord( Cont, USBCMD, 0x0001 );
+       #endif
+
+       Mutex_Release(&lock);
 }
 
 /**
@@ -218,8 +206,12 @@ void *UHCI_int_SendTransaction(
        tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
 {
        tUHCI_TD        *td;
+       tUHCI_ExtraTDInfo       *info = NULL;
 
-       if( Length > 0x400 )    return NULL;    // Controller allows up to 0x500, but USB doesn't
+       if( Length > 0x400 ) {
+               Log_Error("UHCI", "Transaction length too large (%i > 0x400)", Length);
+               return NULL;    // Controller allows up to 0x500, but USB doesn't
+       }
 
        td = UHCI_int_AllocateTD(Cont);
 
@@ -229,7 +221,9 @@ void *UHCI_int_SendTransaction(
                return NULL;
        }
 
-       td->Link = 1;
+       LOG("TD %p %i bytes, Type %x to 0x%x",
+               td, Length, Type, Addr);
+
        td->Control = (Length - 1) & 0x7FF;
        td->Control |= (1 << 23);
        td->Token  = ((Length - 1) & 0x7FF) << 21;
@@ -238,30 +232,57 @@ void *UHCI_int_SendTransaction(
        td->Token |= ((Addr/16) & 0xFF) << 8;
        td->Token |= Type;
 
-       // TODO: Ensure 32-bit paddr
-       if( ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE ) {
-               Log_Warning("UHCI", "TODO: Support non single page transfers (%x + %x > %x)",
-                       (tVAddr)Data & (PAGE_SIZE-1), Length, PAGE_SIZE
-                       );
-               // TODO: Need to enable IOC to copy the data back
-//             td->BufferPointer = 
-               td->_info.bCopyData = 1;
-               return NULL;
+       if(
+               ((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE
+       #if PHYS_BITS > 32
+               || MM_GetPhysAddr( (tVAddr)Data ) >> 32
+       #endif
+               )
+       {
+               td->BufferPointer = MM_AllocPhysRange(1, 32);
+
+               LOG("Allocated page %x", td->BufferPointer);            
+
+               if( Type == 0x69 )      // IN token
+               {
+                       LOG("Relocated IN");
+                       info = calloc( sizeof(tUHCI_ExtraTDInfo), 1 );
+                       info->Offset = ((tVAddr)Data & (PAGE_SIZE-1));
+                       info->FirstPage = MM_GetPhysAddr( (tVAddr)Data );
+                       info->SecondPage = MM_GetPhysAddr( (tVAddr)Data + Length - 1 );
+               }
+               else
+               {
+                       LOG("Relocated OUT/SETUP");
+                       tVAddr  ptr = MM_MapTemp(td->BufferPointer);
+                       memcpy( (void*)ptr, Data, Length );
+                       MM_FreeTemp(ptr);
+                       td->Control |= (1 << 24);
+               }
+               td->_info.bFreePointer = 1;
        }
-       else {
+       else
+       {
                td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
-               td->_info.bCopyData = 0;
+               td->_info.bFreePointer = 0;
        }
 
        // Interrupt on completion
-       if( Cb ) {
-               td->Control |= (1 << 24);
+       if( Cb )
+       {
+               if( !info )
+                       info = calloc( sizeof(tUHCI_ExtraTDInfo), 1 );
                LOG("IOC Cb=%p CbData=%p", Cb, CbData);
-               td->_info.Callback = Cb;        // NOTE: if ERRPTR then the TD is kept allocated until checked
-               td->_info.CallbackPtr = CbData;
+               // NOTE: if ERRPTR then the TD is kept allocated until checked
+               info->Callback = Cb;
+               info->CallbackPtr = CbData;
        }
        
-       td->_info.DataPtr = Data;
+       if( info ) {
+               LOG("info = %p", info);
+               td->Control |= (1 << 24);
+               td->_info.ExtraInfo = info;
+       }
 
        UHCI_int_AppendTD(Cont, td);
 
@@ -286,13 +307,27 @@ void *UHCI_SendSetup(void *Ptr, int Dest, int DataTgl, tUSBHostCb Cb, void *CbDa
 int UHCI_IsTransferComplete(void *Ptr, void *Handle)
 {
        tUHCI_TD        *td = Handle;
-        int    ret;
-       ret = !(td->Control & (1 << 23));
-       if(ret) {
-               td->_info.Callback = NULL;
+       #if DEBUG
+       tUHCI_Controller        *Cont = &gUHCI_Controllers[0];
+       LOG("%p->Control = %x", td, td->Control);
+       LOG("USBSTS = 0x%x, USBINTR = 0x%x", _InWord(Cont, USBSTS), _InWord(Cont, USBINTR));
+       LOG("Cont->BulkQH.Child = %x", Cont->BulkQH.Child);
+       #endif
+       if(td->Control & (1 << 23)) {
+               return 0;
+       }
+//     LOG("inactive, waiting for completion");
+       if(td->_info.bComplete)
+       {
+               td->_info.bActive = 0;
+               td->_info.bComplete = 0;
                td->Link = 0;
+               return 1;
+       }
+       else
+       {
+               return 0;
        }
-       return ret;
 }
 
 // === INTERNAL FUNCTIONS ===
@@ -306,7 +341,7 @@ int UHCI_Int_InitHost(tUHCI_Controller *Host)
        ENTER("pHost", Host);
 
        _OutWord( Host, USBCMD, 4 );    // GRESET
-       // TODO: Wait for at least 10ms
+       Time_Delay(10);
        _OutWord( Host, USBCMD, 0 );    // GRESET
        
        // Allocate Frame List
@@ -318,11 +353,21 @@ int UHCI_Int_InitHost(tUHCI_Controller *Host)
                LEAVE('i', -1);
                return -1;
        }
+
+       // TODO: Handle QHs not being in a 32-bit paddr range
+       // Need another page, probably get some more TDs from it too
+
+       // Set up interrupt and bulk queue
+       Host->InterruptQH.Next = MM_GetPhysAddr( (tVAddr)&Host->ControlQH ) | 2;
+       Host->InterruptQH.Child = 1;
+       Host->ControlQH.Next = MM_GetPhysAddr( (tVAddr)&Host->BulkQH ) | 2;
+       Host->ControlQH.Child = 1;
+       Host->BulkQH.Next = 1;
+       Host->BulkQH.Child = 1;
+
        LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);
        for( int i = 0; i < 1024; i ++ )
-               Host->FrameList[i] = 1; // Clear List (Disabling all entries)
-       
-       //! \todo Properly fill frame list
+               Host->FrameList[i] = MM_GetPhysAddr( (tVAddr)&Host->InterruptQH ) | 2;
        
        // Set frame length to 1 ms
        _OutByte( Host, SOFMOD, 64 );
@@ -381,58 +426,115 @@ void UHCI_CheckPortUpdate(void *Ptr)
        }
 }
 
-void UHCI_InterruptHandler(int IRQ, void *Ptr)
+void UHCI_int_InterruptThread(void *Unused)
 {
-       tUHCI_Controller *Host = Ptr;
-        int    frame = (_InWord(Host, FRNUM) - 1) & 0x3FF;
-       Uint16  status = _InWord(Host, USBSTS);
-//     Log_Debug("UHCI", "UHIC Interrupt, status = 0x%x, frame = %i", status, frame);
-       
-       // Interrupt-on-completion
-       if( status & 1 )
+       Threads_SetName("UHCI Interrupt Handler");
+       for( ;; )
        {
-               tPAddr  link;
-               
-               for( int i = 0; i < 10; i ++ )
+               LOG("zzzzz....");
+               // 0 = Take all
+               Semaphore_Wait(&gUHCI_InterruptSempahore, 0);
+               LOG("Huh?");
+       
+               for( int i = 0; i < NUM_TDs; i ++ )
                {
-                       link = Host->FrameList[frame];
-                       Host->FrameList[frame] = 1;
-                       while( link && !(link & 1) )
+                        int    byte_count;
+                       tUHCI_ExtraTDInfo       *info;
+                       tUHCI_TD        *td;
+                       
+                       td = &gaUHCI_TDPool[i];
+                       info = td->_info.ExtraInfo;
+
+                       // Skip completely inactive TDs
+                       if( td->_info.bActive == 0 )    continue ;
+                       // Skip ones that are still in use
+                       if( td->Control & (1 << 23) )   continue ;
+
+                       // If no callback/alt buffer, mark as free and move on
+                       if( td->_info.ExtraInfo )
                        {
-                               tUHCI_TD *td = UHCI_int_GetTDFromPhys(link);
-                                int    byte_count = (td->Control&0x7FF)+1;
-                               LOG("link = 0x%x, td = %p, byte_count = %i", link, td, byte_count);
-                               // Handle non-page aligned destination
-                               // TODO: This will break if the destination is not in global memory
-                               if(td->_info.bCopyData)
+                               // Get size of transfer
+                               byte_count = (td->Control & 0x7FF)+1;
+                       
+                               // Handle non page-aligned destination (with a > 32-bit paddr)
+                               if(info->FirstPage)
+                               {
+                                       char    *src, *dest;
+                                        int    src_ofs = td->BufferPointer & (PAGE_SIZE-1);
+                                       src = (void *) MM_MapTemp(td->BufferPointer);
+                                       dest = (void *) MM_MapTemp(info->FirstPage);
+                                       // Check for a single page transfer
+                                       if( byte_count + info->Offset <= PAGE_SIZE )
+                                       {
+                                               LOG("Single page copy %P to %P of %p",
+                                                       td->BufferPointer, info->FirstPage, td);
+                                               memcpy(dest + info->Offset, src + src_ofs, byte_count);
+                                       }
+                                       else
+                                       {
+                                               // Multi-page
+                                               LOG("Multi page copy %P to (%P,%P) of %p",
+                                                       td->BufferPointer, info->FirstPage, info->SecondPage, td);
+                                                int    part_len = PAGE_SIZE - info->Offset;
+                                               memcpy(dest + info->Offset, src + src_ofs, part_len);
+                                               MM_FreeTemp( (tVAddr)dest );
+                                               dest = (void *) MM_MapTemp(info->SecondPage);
+                                               memcpy(dest, src + src_ofs + part_len, byte_count - part_len);
+                                       }
+                                       MM_FreeTemp( (tVAddr)src );
+                                       MM_FreeTemp( (tVAddr)dest );
+                               }
+       
+                               // Don't mark as inactive, the check should do that
+                               if( info->Callback == INVLPTR )
                                {
-                                       void *ptr = (void*)MM_MapTemp(td->BufferPointer);
-                                       Log_Debug("UHCI", "td->_info.DataPtr = %p", td->_info.DataPtr);
-                                       memcpy(td->_info.DataPtr, ptr, byte_count);
-                                       MM_FreeTemp((tVAddr)ptr);
+                                       LOG("Marking %p as complete", td);
+                                       td->_info.bComplete = 1;
+                                       free( info );
+                                       td->_info.ExtraInfo = NULL;
+                                       if( td->_info.bFreePointer )
+                                               MM_DerefPhys( td->BufferPointer );                      
+                                       continue ;
                                }
+
                                // Callback
-                               if(td->_info.Callback && td->_info.Callback != INVLPTR)
+                               if( info->Callback != NULL )
                                {
-                                       LOG("Calling cb %p", td->_info.Callback);
-                                       td->_info.Callback(td->_info.CallbackPtr, td->_info.DataPtr, byte_count);
-                                       td->_info.Callback = NULL;
+                                       LOG("Calling cb %p", info->Callback);
+                                       void    *ptr = (void *) MM_MapTemp( td->BufferPointer );
+                                       info->Callback( info->CallbackPtr, ptr, byte_count );
+                                       MM_FreeTemp( (tVAddr)ptr );
                                }
-                               link = td->Link;
-                               if( td->_info.Callback != INVLPTR )
-                                       td->Link = 0;
+                               
+                               // Clean up info
+                               free( info );
+                               td->_info.ExtraInfo = NULL;
                        }
-                       
-                       if(frame == 0)
-                               frame = 0x3ff;
-                       else
-                               frame --;
+
+                       if( td->_info.bFreePointer )
+                               MM_DerefPhys( td->BufferPointer );                      
+       
+                       // Clean up
+                       td->_info.bActive = 0;
+                       LOG("Cleaned %p", td);
                }
-               
-//             Host->LastCleanedFrame = frame;
+       }
+}
+
+void UHCI_InterruptHandler(int IRQ, void *Ptr)
+{
+       tUHCI_Controller *Host = Ptr;
+//      int    frame = (_InWord(Host, FRNUM) - 1) & 0x3FF;
+       Uint16  status = _InWord(Host, USBSTS);
+       
+       // Interrupt-on-completion
+       if( status & 1 )
+       {
+               // TODO: Support isochronous transfers (will need updating the frame pointer)
+               Semaphore_Signal(&gUHCI_InterruptSempahore, 1);
        }
 
-       LOG("status = 0x%02x", status);
+       LOG("status = 0x%04x", status);
        _OutWord(Host, USBSTS, status);
 }
 
index a93459a..40b589b 100644 (file)
@@ -8,53 +8,20 @@
 
 // === TYPES ===
 typedef struct sUHCI_Controller        tUHCI_Controller;
+typedef struct sUHCI_ExtraTDInfo       tUHCI_ExtraTDInfo;
+
 typedef struct sUHCI_TD        tUHCI_TD;
 typedef struct sUHCI_QH        tUHCI_QH;
 
 // === STRUCTURES ===
-struct sUHCI_Controller
+struct sUHCI_ExtraTDInfo
 {
-       /**
-        * \brief PCI Device ID
-        */
-       Uint16  PciId;
+        int    Offset;
+       tPAddr  FirstPage;
+       tPAddr  SecondPage;
        
-       /**
-        * \brief IO Base Address
-        */
-       Uint16  IOBase;
-       
-       /**
-        * \brief Memory Mapped-IO base address
-        */
-       Uint16  *MemIOMap;
-
-       /**
-        * \brief IRQ Number assigned to the device
-        */
-        int    IRQNum;
-
-       /**
-        * \brief Number of the last frame to be cleaned
-        */
-        int    LastCleanedFrame;
-       
-       /**
-        * \brief Frame list
-        * 
-        * 31:4 - Frame Pointer
-        * 3:2 - Reserved
-        * 1 - QH/TD Selector
-        * 0 - Terminate (Empty Pointer)
-        */
-       Uint32  *FrameList;
-       
-       /**
-        * \brief Physical Address of the Frame List
-        */
-       tPAddr  PhysFrameList;
-
-       tUSBHub *RootHub;
+       tUSBHostCb      Callback;
+       void    *CallbackPtr;
 };
 
 struct sUHCI_TD
@@ -116,10 +83,10 @@ struct sUHCI_TD
 
        struct
        {
-               tUSBHostCb      Callback;
-               void    *CallbackPtr;
-               void    *DataPtr;
-                int    bCopyData;
+               tUHCI_ExtraTDInfo       *ExtraInfo;
+               char    bActive;        // Allocated
+               char    bComplete;      // Job complete
+               char    bFreePointer;   // Free \a BufferPointer once done
        } _info;
 } __attribute__((aligned(16)));
 
@@ -145,6 +112,61 @@ struct sUHCI_QH
         * 0 - Terminate (Last in List)
         */
        Uint32  Child;
+       
+       /*
+        * \note Area for software use
+        * \brief Last TD in this list, used to add things to the end
+        */
+       tUHCI_TD        *_LastItem;
+} __attribute__((aligned(16)));
+
+struct sUHCI_Controller
+{
+       /**
+        * \brief PCI Device ID
+        */
+       Uint16  PciId;
+       
+       /**
+        * \brief IO Base Address
+        */
+       Uint16  IOBase;
+       
+       /**
+        * \brief Memory Mapped-IO base address
+        */
+       Uint16  *MemIOMap;
+
+       /**
+        * \brief IRQ Number assigned to the device
+        */
+        int    IRQNum;
+
+       /**
+        * \brief Number of the last frame to be cleaned
+        */
+        int    LastCleanedFrame;
+       
+       /**
+        * \brief Frame list
+        * 
+        * 31:4 - Frame Pointer
+        * 3:2 - Reserved
+        * 1 - QH/TD Selector
+        * 0 - Terminate (Empty Pointer)
+        */
+       Uint32  *FrameList;
+       
+       /**
+        * \brief Physical Address of the Frame List
+        */
+       tPAddr  PhysFrameList;
+
+       tUSBHub *RootHub;
+
+       tUHCI_QH        InterruptQH;
+       tUHCI_QH        ControlQH;
+       tUHCI_QH        BulkQH;
 };
 
 // === ENUMERATIONS ===

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