#include <usb_core.h>
#include "usb.h"
#include <timers.h>
-
-#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;
// === 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)
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
host->HostDef->CheckPorts(host->Ptr);
}
- Time_Delay(POLL_ATOM);
+ Time_Delay(100);
}
}
// 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 );
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;
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?
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 );
// 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)
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 )
{
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;