From d8bf9f747a87c3c1d23461c155ef90b7fc148a21 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 29 Feb 2012 21:22:54 +0800 Subject: [PATCH] Modules/USB - Interrupt endpoints work - Fixed interrupt callback sleeping in the host's interrupt thread --- KernelLand/Modules/USB/Core/hub.c | 7 +-- KernelLand/Modules/USB/Core/usb_async.h | 27 +++++++++++ KernelLand/Modules/USB/Core/usb_io.c | 13 ++--- KernelLand/Modules/USB/Core/usb_lowlevel.c | 2 +- KernelLand/Modules/USB/Core/usb_poll.c | 26 ++++++---- KernelLand/Modules/USB/UHCI/uhci.c | 55 ++++++++++++---------- 6 files changed, 83 insertions(+), 47 deletions(-) create mode 100644 KernelLand/Modules/USB/Core/usb_async.h diff --git a/KernelLand/Modules/USB/Core/hub.c b/KernelLand/Modules/USB/Core/hub.c index 69599e18..7bc4dc27 100644 --- a/KernelLand/Modules/USB/Core/hub.c +++ b/KernelLand/Modules/USB/Core/hub.c @@ -5,7 +5,7 @@ * hub.c * - Basic hub driver */ -#define DEBUG 1 +#define DEBUG 0 #include #include @@ -123,8 +123,9 @@ void Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Da for( i = 0; i < info->nPorts; i += 8, status ++ ) { if( i/8 >= Length ) break; - if( *status == 0 ) continue; - + LOG("status[%i] = %x", i/8, *status); + if( *status == 0 ) continue; + for( int j = 0; j < 8; j ++ ) if( *status & (1 << j) ) Hub_int_HandleChange(Dev, i+j); diff --git a/KernelLand/Modules/USB/Core/usb_async.h b/KernelLand/Modules/USB/Core/usb_async.h new file mode 100644 index 00000000..e0864ce6 --- /dev/null +++ b/KernelLand/Modules/USB/Core/usb_async.h @@ -0,0 +1,27 @@ +/* + * Acess2 USB Stack + * - By John Hodge (thePowersGang) + * + * usb_async.h + * - USB ASync operations + */ +#ifndef _USB__USB_ASYNC_H_ +#define _USB__USB_ASYNC_H_ +#include + +typedef struct sAsyncOp tAsyncOp; + +struct sAsyncOp +{ + tAsyncOp *Next; + tUSBEndpoint *Endpt; + int Length; + void *Data; +}; + +extern void USB_AsyncCallback(void *Ptr, void *Buf, size_t Length); + +extern tWorkqueue gUSB_AsyncQueue;; + +#endif + diff --git a/KernelLand/Modules/USB/Core/usb_io.c b/KernelLand/Modules/USB/Core/usb_io.c index 745e8a64..a1bf50b1 100644 --- a/KernelLand/Modules/USB/Core/usb_io.c +++ b/KernelLand/Modules/USB/Core/usb_io.c @@ -11,16 +11,7 @@ #include "usb.h" #include "usb_lowlevel.h" #include - -typedef struct sAsyncOp tAsyncOp; - -struct sAsyncOp -{ - tAsyncOp *Next; - tUSBEndpoint *Endpt; - int Length; - void *Data; -}; +#include "usb_async.h" // === PROTOTYPES === void USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data); @@ -115,6 +106,8 @@ void USB_AsyncThread(void *Unused) iface->Driver->Endpoints[op->Endpt->EndpointIdx].DataAvail( iface, op->Endpt->EndpointIdx, op->Length, op->Data); + + free(op); } } diff --git a/KernelLand/Modules/USB/Core/usb_lowlevel.c b/KernelLand/Modules/USB/Core/usb_lowlevel.c index 67381c0b..8eab0098 100644 --- a/KernelLand/Modules/USB/Core/usb_lowlevel.c +++ b/KernelLand/Modules/USB/Core/usb_lowlevel.c @@ -5,7 +5,7 @@ * usb_lowlevel.c * - Low Level IO */ -#define DEBUG 1 +#define DEBUG 0 #include #include "usb.h" #include "usb_proto.h" diff --git a/KernelLand/Modules/USB/Core/usb_poll.c b/KernelLand/Modules/USB/Core/usb_poll.c index d1cbaa93..12e14a9a 100644 --- a/KernelLand/Modules/USB/Core/usb_poll.c +++ b/KernelLand/Modules/USB/Core/usb_poll.c @@ -9,10 +9,7 @@ #include #include "usb.h" #include - -#define POLL_ATOM 25 // 25ms atom -#define POLL_MAX 256 // Max period that can be nominated -#define POLL_SLOTS ((int)(POLL_MAX/POLL_ATOM)) +#include "usb_async.h" // === IMPORTS === extern tUSBHost *gUSB_Hosts; @@ -25,9 +22,17 @@ void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint); // === CODE === void USB_int_PollCallback(void *Ptr, void *Data, size_t Length) { + tAsyncOp *op; tUSBEndpoint *ep = Ptr; - ep->Interface->Driver->Endpoints[ep->EndpointIdx].DataAvail(ep->Interface, ep->EndpointIdx, Length, Data); + op = malloc(sizeof(*op)); + + op->Next = NULL; + op->Endpt = ep; + op->Length = Length; + op->Data = ep->InputData; + + Workqueue_AddWork(&gUSB_AsyncQueue, op); } void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint) @@ -35,15 +40,18 @@ void USB_StartPollingEndpoint(tUSBInterface *Iface, int Endpoint) tUSBEndpoint *endpt; ENTER("pIface iEndpoint", Iface, Endpoint); - LEAVE('-'); // Some sanity checks - if(Endpoint <= 0 || Endpoint > Iface->nEndpoints) + if(Endpoint <= 0 || Endpoint > Iface->nEndpoints) { + LEAVE('-'); return ; + } endpt = &Iface->Endpoints[Endpoint-1]; LOG("endpt(%p)->PollingPeriod = %i", endpt, endpt->PollingPeriod); - if(endpt->PollingPeriod > POLL_MAX || endpt->PollingPeriod <= 0) + if(endpt->PollingPeriod > 256 || endpt->PollingPeriod <= 0) { + LEAVE('-'); return ; + } // TODO: Check that this endpoint isn't already on the queue @@ -73,7 +81,7 @@ int USB_PollThread(void *unused) host->HostDef->CheckPorts(host->Ptr); } - Time_Delay(POLL_ATOM); + Time_Delay(100); } } diff --git a/KernelLand/Modules/USB/UHCI/uhci.c b/KernelLand/Modules/USB/UHCI/uhci.c index 0af6f1a6..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; @@ -434,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? @@ -686,14 +690,14 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD) if( byte_count + info->Offset <= PAGE_SIZE ) { LOG("Single page copy %P to %P of %p", - td->BufferPointer, info->FirstPage, td); + 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); + 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 ); @@ -707,15 +711,18 @@ void UHCI_int_HandleTDComplete(tUHCI_Controller *Cont, tUHCI_TD *TD) // Callback if( info->Callback != NULL ) { - LOG("Calling cb %p", info->Callback); + 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 - free( info ); - TD->_info.ExtraInfo = NULL; + if( TD->_info.QueueIndex > 127 ) + { + free( info ); + TD->_info.ExtraInfo = NULL; + } } void UHCI_int_InterruptThread(void *Pointer) @@ -746,6 +753,22 @@ void UHCI_int_InterruptThread(void *Pointer) 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 ) { @@ -765,22 +788,6 @@ void UHCI_int_InterruptThread(void *Pointer) 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; -- 2.20.1