X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FUSB%2FUHCI%2Fuhci.c;h=e57a1c300ca9c38da964ed1265bdc49c861ffb69;hb=11dbd684e9a3d907d43d71a3145205f1a86992fb;hp=4724cf175c8b6ff6fabf1a2aefeb76f8e5bae1ad;hpb=d8bf9f747a87c3c1d23461c155ef90b7fc148a21;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index 4724cf17..e57a1c30 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.c +++ b/KernelLand/Modules/USB/UHCI/uhci.c @@ -16,10 +16,12 @@ #include // === CONSTANTS === -#define MAX_CONTROLLERS 4 +#define MAX_CONTROLLERS 8 //#define NUM_TDs 1024 #define NUM_TDs (PAGE_SIZE/sizeof(tUHCI_TD)) #define MAX_PACKET_SIZE 0x400 +#define MAX_INTERRUPT_LOAD 1024 // Maximum bytes per frame for interrupts + #define PID_IN 0x69 #define PID_OUT 0xE1 #define PID_SETUP 0x2D @@ -95,6 +97,7 @@ int UHCI_Initialise(char **Arguments) { tPAddr tmp; gaUHCI_TDPool = (void *) MM_AllocDMA(1, 32, &tmp); + memset(gaUHCI_TDPool, 0, PAGE_SIZE); } // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices @@ -192,8 +195,10 @@ int UHCI_int_InitHost(tUHCI_Controller *Host) Host->FrameList[i] = addr | 2; } for( int i = 0; i < 64; i ++ ) { - int ofs = dest_offsets[ i & (32-1) ]; + int ofs = dest_offsets[ i & (32-1) ] * 2 + (i >= 32); Uint32 addr = Host->PhysTDQHPage + ofs * sizeof(tUHCI_QH); + LOG("Slot %i to (%i,%i,%i,%i) ms slots", + ofs, 0 + i*4, 256 + i*4, 512 + i*4, 768 + i*4); Host->FrameList[ 0 + i*4] = addr | 2; Host->FrameList[256 + i*4] = addr | 2; Host->FrameList[512 + i*4] = addr | 2; @@ -261,7 +266,7 @@ tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont) if(gaUHCI_TDPool[i]._info.bActive == 0) { gaUHCI_TDPool[i].Link = 1; - gaUHCI_TDPool[i].Control = (1 << 23); + gaUHCI_TDPool[i].Control = TD_CTL_ACTIVE; gaUHCI_TDPool[i]._info.bActive = 1; gaUHCI_TDPool[i]._info.QueueIndex = 128; Mutex_Release( &lock ); @@ -279,8 +284,9 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD) Mutex_Acquire(&lock); // Ensure that there is an interrupt for each used frame - TD->Control |= (1 << 24); + TD->Control |= TD_CTL_IOC; TD->_info.QueueIndex = ((tVAddr)QH - (tVAddr)Cont->TDQHPage->InterruptQHs) / sizeof(tUHCI_QH); + LOG("TD(%p)->QueueIndex = %i", TD, TD->_info.QueueIndex); // Update length TD->Control &= ~0x7FF; TD->Control |= (TD->Token >> 21) & 0x7FF; @@ -337,8 +343,14 @@ tUHCI_TD *UHCI_int_CreateTD( td, Length, Type, Addr); td->Control = (Length - 1) & 0x7FF; - td->Control |= (1 << 23); // Active set + td->Control |= TD_CTL_ACTIVE; // Active set td->Control |= (3 << 27); // 3 retries + // High speed device (must be explicitly enabled + if( Addr & 0x8000 ) + ; + else + td->Control |= 1 << 26; + td->Token = ((Length - 1) & 0x7FF) << 21; td->Token |= (bTgl & 1) << 19; td->Token |= (Addr & 0xF) << 15; @@ -367,10 +379,10 @@ tUHCI_TD *UHCI_int_CreateTD( else { LOG("Relocated OUT/SETUP"); - tVAddr ptr = MM_MapTemp(td->BufferPointer); - memcpy( (void*)ptr, Data, Length ); + void *ptr = MM_MapTemp(td->BufferPointer); + memcpy( ptr, Data, Length ); MM_FreeTemp(ptr); - td->Control |= (1 << 24); + td->Control |= TD_CTL_IOC; } td->_info.bFreePointer = 1; } @@ -392,7 +404,7 @@ tUHCI_TD *UHCI_int_CreateTD( if( info ) { LOG("info = %p", info); - td->Control |= (1 << 24); + td->Control |= TD_CTL_IOC; td->_info.ExtraInfo = info; } @@ -403,7 +415,7 @@ void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period) { tUHCI_QH *qh; const int qh_offsets[] = {126, 124, 120, 112, 96, 64, 0}; -// const int qh_sizes[] = { 1, 2, 4, 8, 16, 32, 64}; + const int qh_sizes[] = { 1, 2, 4, 8, 16, 32, 64}; // Bounds limit if( Period < 0 ) return ; @@ -418,15 +430,52 @@ void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period) if( period_slot < 2 ) period_slot = 0; else period_slot -= 2; - TD->_info.QueueIndex = qh_offsets[period_slot]; // Actually re-filled in _AppendTD, but meh - qh = Cont->TDQHPage->InterruptQHs + TD->_info.QueueIndex; + // _AppendTD calculates this from qh, but we use it to determine qh + TD->_info.QueueIndex = qh_offsets[period_slot]; // TODO: Find queue with lowest load +#if 1 + int min_load = 0; + int min_load_slot = 0; + for( int i = 0; i < qh_sizes[period_slot]; i ++ ) + { + int load, index; + index = qh_offsets[period_slot] + i; + load = 0; + while( index >= 0 && index < 127 ) + { + qh = Cont->TDQHPage->InterruptQHs + index; + load += Cont->InterruptLoad[index]; + index = ((qh->Next & ~3) - Cont->PhysTDQHPage)/sizeof(tUHCI_QH); + } + + LOG("Slot %i (and below) load %i", qh_offsets[period_slot] + i, load); + + // i = 0 will initialise the values, otherwise update if lower + if( i == 0 || load < min_load ) + { + min_load = load; + min_load_slot = i; + } + // - Fast return if no load + if( load == 0 ) break; + } + min_load_slot += qh_offsets[period_slot]; + TD->_info.QueueIndex = min_load_slot; + if( min_load + (TD->Control & 0x7FF) > MAX_INTERRUPT_LOAD ) + { + Log_Warning("UHCI", "Interrupt load on %i ms is too high (slot %i load %i bytes)", + 1 << (period_slot+2), min_load_slot, min_load + ); + } + Cont->InterruptLoad[min_load_slot] += (TD->Control & 0x7FF); +#endif + qh = Cont->TDQHPage->InterruptQHs + TD->_info.QueueIndex; LOG("period_slot = %i, QueueIndex = %i", period_slot, TD->_info.QueueIndex); // Stop any errors causing the TD to stop (NAK will error) - // - If the device goes away, the interrupt should be stopped anyway + // - If the device is unplugged, the removal code should remove the interrupt TD->Control &= ~(3 << 27); UHCI_int_AppendTD(Cont, qh, TD); @@ -529,19 +578,12 @@ void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length); - while( Length > MAX_PACKET_SIZE ) - { - LOG("MaxPacket (rem = %i)", Length); - td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, MAX_PACKET_SIZE); - UHCI_int_AppendTD(Cont, qh, td); - - bToggle = !bToggle; - Length -= MAX_PACKET_SIZE; - src += MAX_PACKET_SIZE; + if( Length > MAX_PACKET_SIZE ) { + Log_Error("UHCI", "Passed an oversized packet by the USB code (%i > %i)", Length, MAX_PACKET_SIZE); + LEAVE('n'); } - - LOG("Final"); - td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, Length); + + td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, Cb, CbData, src, Length); UHCI_int_AppendTD(Cont, qh, td); LEAVE('p', td); @@ -555,19 +597,12 @@ void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, char *dst = Buf; ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length); - while( Length > MAX_PACKET_SIZE ) - { - LOG("MaxPacket (rem = %i)", Length); - td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, MAX_PACKET_SIZE); - UHCI_int_AppendTD(Cont, qh, td); - - bToggle = !bToggle; - Length -= MAX_PACKET_SIZE; - dst += MAX_PACKET_SIZE; + if( Length > MAX_PACKET_SIZE ) { + Log_Error("UHCI", "Passed an oversized packet by the USB code (%i > %i)", Length, MAX_PACKET_SIZE); + LEAVE('n'); } - LOG("Final"); - td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, Length); + td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, Cb, CbData, dst, Length); UHCI_int_AppendTD(Cont, qh, td); LEAVE('p', td); @@ -639,12 +674,14 @@ void UHCI_int_CleanQH(tUHCI_Controller *Cont, tUHCI_QH *QH) { tUHCI_TD *td, *prev = NULL; Uint32 cur_td; + int nCleaned = 0; // Disable controller _OutWord( Cont, USBCMD, 0x0000 ); // Scan QH list cur_td = QH->Child; + LOG("cur_td = 0x%08x", cur_td); while( !(cur_td & 1) ) { td = UHCI_int_GetTDFromPhys(Cont, cur_td); @@ -655,8 +692,10 @@ void UHCI_int_CleanQH(tUHCI_Controller *Cont, tUHCI_QH *QH) } // Active? Ok. - if( td->Control & (1 << 23) ) { + if( td->Control & TD_CTL_ACTIVE ) { + LOG("%p still active", td); prev = td; + cur_td = td->Link; continue ; } @@ -667,6 +706,11 @@ void UHCI_int_CleanQH(tUHCI_Controller *Cont, tUHCI_QH *QH) else prev->Link = td->Link; cur_td = td->Link; + nCleaned ++; + } + + if( nCleaned == 0 ) { + LOG("Nothing cleaned... what the?"); } // re-enable controller @@ -684,8 +728,8 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD) { char *src, *dest; int src_ofs = TD->BufferPointer & (PAGE_SIZE-1); - src = (void *) MM_MapTemp(TD->BufferPointer); - dest = (void *) MM_MapTemp(info->FirstPage); + src = MM_MapTemp(TD->BufferPointer); + dest = MM_MapTemp(info->FirstPage); // Check for a single page transfer if( byte_count + info->Offset <= PAGE_SIZE ) { @@ -700,21 +744,21 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD) 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); + MM_FreeTemp( dest ); + dest = MM_MapTemp(info->SecondPage); memcpy(dest, src + src_ofs + part_len, byte_count - part_len); } - MM_FreeTemp( (tVAddr)src ); - MM_FreeTemp( (tVAddr)dest ); + MM_FreeTemp( src ); + MM_FreeTemp( dest ); } // Callback if( info->Callback != NULL ) { LOG("Calling cb %p (%i bytes)", info->Callback, byte_count); - void *ptr = (void *) MM_MapTemp( TD->BufferPointer ); + void *ptr = MM_MapTemp( TD->BufferPointer ); info->Callback( info->CallbackPtr, ptr, byte_count ); - MM_FreeTemp( (tVAddr)ptr ); + MM_FreeTemp( ptr ); } // Clean up info @@ -731,6 +775,8 @@ void UHCI_int_InterruptThread(void *Pointer) Threads_SetName("UHCI Interrupt Handler"); for( ;; ) { + int nSeen = 0; + LOG("zzzzz...."); // 0 = Take all Semaphore_Wait(&gUHCI_InterruptSempahore, 0); @@ -745,7 +791,9 @@ void UHCI_int_InterruptThread(void *Pointer) // Skip completely inactive TDs if( td->_info.bActive == 0 ) continue ; // Skip ones that are still in use - if( td->Control & (1 << 23) ) continue ; + if( td->Control & TD_CTL_ACTIVE ) continue ; + + nSeen ++; // If no callback/alt buffer, mark as free and move on if( td->_info.ExtraInfo ) @@ -756,17 +804,19 @@ void UHCI_int_InterruptThread(void *Pointer) // Error check if( td->Control & 0x00FF0000 ) { LOG("td->control(Status) = %s%s%s%s%s%s%s%s", - td->Control & (1 << 23) ? "Active " : "", - td->Control & (1 << 22) ? "Stalled " : "", - td->Control & (1 << 21) ? "Data Buffer Error " : "", - td->Control & (1 << 20) ? "Babble " : "", - td->Control & (1 << 19) ? "NAK " : "", - td->Control & (1 << 18) ? "CRC Error, " : "", - td->Control & (1 << 17) ? "Bitstuff Error, " : "", - td->Control & (1 << 16) ? "Reserved " : "" + td->Control & TD_CTL_ACTIVE ? "Active, " : "", + td->Control & TD_CTL_STALLED ? "Stalled, " : "", + td->Control & TD_CTL_DATABUFERR ? "Data Buffer Error, " : "", + td->Control & TD_CTL_BABBLE ? "Babble, " : "", + td->Control & TD_CTL_NAK ? "NAK, " : "", + td->Control & TD_CTL_CRCERR ? "CRC Error, " : "", + td->Control & TD_CTL_BITSTUFF ? "Bitstuff Error, " : "", + td->Control & TD_CTL_RESERVED ? "Reserved " : "" ); + LOG("From queue %i", td->_info.QueueIndex); // Clean up QH (removing all inactive entries) UHCI_int_CleanQH(Cont, Cont->TDQHPage->InterruptQHs + td->_info.QueueIndex); + td->Control = 0; } // Handle rescheduling of interrupt TDs @@ -774,7 +824,7 @@ void UHCI_int_InterruptThread(void *Pointer) { LOG("Re-schedule interrupt %p (offset %i)", td, td->_info.QueueIndex); // TODO: Flip toggle? - td->Control |= (1 << 23); + td->Control |= TD_CTL_ACTIVE; // Add back into controller's interrupt list UHCI_int_AppendTD( Cont, @@ -792,6 +842,10 @@ void UHCI_int_InterruptThread(void *Pointer) LOG("Cleaned %p (->Control = %x)", td, td->Control); td->_info.bActive = 0; } + + if( nSeen == 0 ) { + LOG("Why did you wake me?"); + } } } @@ -801,6 +855,8 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr) // int frame = (_InWord(Host, FRNUM) - 1) & 0x3FF; Uint16 status = _InWord(Host, USBSTS); + LOG("%p: status = 0x%04x", Ptr, status); + // Interrupt-on-completion if( status & 1 ) { @@ -808,7 +864,31 @@ void UHCI_InterruptHandler(int IRQ, void *Ptr) Semaphore_Signal(&gUHCI_InterruptSempahore, 1); } - LOG("status = 0x%04x", status); + // USB Error Interrupt + if( status & 2 ) + { + + } + + // Resume Detect + // - Fired if in suspend state and a USB device sends the RESUME signal + if( status & 4 ) + { + + } + + // Host System Error + if( status & 8 ) + { + + } + + // Host Controller Process Error + if( status & 0x10 ) + { + Log_Error("UHCI", "Host controller process error on controller %p", Ptr); + } + _OutWord(Host, USBSTS, status); }