X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=KernelLand%2FModules%2FUSB%2FUHCI%2Fuhci.c;h=4724cf175c8b6ff6fabf1a2aefeb76f8e5bae1ad;hb=70a143a9de252ddc4f148866b0a93e28904073e5;hp=fc007107fba5b14e361b79f549de536aaeb9524d;hpb=fa8a440a927e1a31c5cd1a82df05a7052da8c536;p=tpg%2Facess2.git diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index fc007107..4724cf17 100644 --- a/KernelLand/Modules/USB/UHCI/uhci.c +++ b/KernelLand/Modules/USB/UHCI/uhci.c @@ -281,6 +281,9 @@ void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD) // Ensure that there is an interrupt for each used frame TD->Control |= (1 << 24); TD->_info.QueueIndex = ((tVAddr)QH - (tVAddr)Cont->TDQHPage->InterruptQHs) / sizeof(tUHCI_QH); + // Update length + TD->Control &= ~0x7FF; + TD->Control |= (TD->Token >> 21) & 0x7FF; // Stop controller _OutWord( Cont, USBCMD, 0x0000 ); @@ -399,12 +402,13 @@ tUHCI_TD *UHCI_int_CreateTD( void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period) { tUHCI_QH *qh; - const int qh_offsets[] = { 0, 64, 96, 112, 120, 124, 126}; -// const int qh_sizes[] = {64, 32, 16, 8, 4, 2, 1}; + const int qh_offsets[] = {126, 124, 120, 112, 96, 64, 0}; +// const int qh_sizes[] = { 1, 2, 4, 8, 16, 32, 64}; // Bounds limit if( Period < 0 ) return ; if( Period > 256 ) Period = 256; + if( Period == 255 ) Period = 256; // Get the log base2 of the period int period_slot = 0; @@ -421,6 +425,10 @@ void UHCI_int_SetInterruptPoll(tUHCI_Controller *Cont, tUHCI_TD *TD, int Period) 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 + TD->Control &= ~(3 << 27); + UHCI_int_AppendTD(Cont, qh, TD); } @@ -430,7 +438,7 @@ void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbD if( Period < 0 ) return NULL; - ENTER("pPtr xDest iPeriod pCb pCbData pBuf, iLength", + ENTER("pPtr xDest iPeriod pCb pCbData pBuf iLength", Ptr, Dest, Period, Cb, CbData, Buf, Length); // TODO: Data toggle? @@ -465,6 +473,7 @@ void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *Cb void UHCI_StopInterrupt(void *Ptr, void *Handle) { // TODO: Stop interrupt transaction + Log_Error("UHCI", "TODO: Implement UHCI_StopInterrupt"); } void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length) @@ -664,6 +673,58 @@ void UHCI_int_CleanQH(tUHCI_Controller *Cont, tUHCI_QH *QH) _OutWord( Cont, USBCMD, 0x0001 ); } +void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD) +{ + int byte_count = (TD->Control & 0x7FF)+1; + tUHCI_ExtraTDInfo *info = TD->_info.ExtraInfo; + + // Handle non page-aligned destination (or with a > 32-bit paddr) + // TODO: Needs fixing for alignment issues + 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 ); + } + + // Callback + if( info->Callback != NULL ) + { + LOG("Calling cb %p (%i bytes)", info->Callback, byte_count); + void *ptr = (void *) MM_MapTemp( TD->BufferPointer ); + info->Callback( info->CallbackPtr, ptr, byte_count ); + MM_FreeTemp( (tVAddr)ptr ); + } + + // Clean up info + if( TD->_info.QueueIndex > 127 ) + { + free( info ); + TD->_info.ExtraInfo = NULL; + } +} + void UHCI_int_InterruptThread(void *Pointer) { tUHCI_Controller *Cont = Pointer; @@ -677,12 +738,9 @@ void UHCI_int_InterruptThread(void *Pointer) for( int i = 0; i < NUM_TDs; i ++ ) { - 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 ; @@ -692,52 +750,26 @@ void UHCI_int_InterruptThread(void *Pointer) // If no callback/alt buffer, mark as free and move on if( td->_info.ExtraInfo ) { - // Get size of transfer - byte_count = (td->Control & 0x7FF)+1; - - // Handle non page-aligned destination (or 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 ); - } - - // Callback - if( 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 ); - } - - // Clean up info - free( info ); - td->_info.ExtraInfo = NULL; + UHCI_int_HandleTDComplete(Cont, td); } + // 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 " : "" + ); + // Clean up QH (removing all inactive entries) + UHCI_int_CleanQH(Cont, Cont->TDQHPage->InterruptQHs + td->_info.QueueIndex); + } + + // Handle rescheduling of interrupt TDs if( td->_info.QueueIndex <= 127 ) { LOG("Re-schedule interrupt %p (offset %i)", td, td->_info.QueueIndex); @@ -752,25 +784,10 @@ void UHCI_int_InterruptThread(void *Pointer) continue ; } + // Clean up if( td->_info.bFreePointer ) MM_DerefPhys( td->BufferPointer ); - // 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 " : "" - ); - // Clean up QH (removing all inactive entries) - UHCI_int_CleanQH(Cont, Cont->TDQHPage->InterruptQHs + td->_info.QueueIndex); - } - // Clean up LOG("Cleaned %p (->Control = %x)", td, td->Control); td->_info.bActive = 0;