#include <semaphore.h>
// === 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
void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD);
tUHCI_TD *UHCI_int_CreateTD(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
// --- API
-void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void UHCI_StopInterrupt(void *Ptr, void *Handle);
-void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length);
-void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len);
+void *UHCI_InitIsoch(void *Ptr, int Endpt, size_t MaxPacketSize);
+void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize);
+void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize);
+void UHCI_RemoveEndpoint(void *Ptr, void *EndptHandle);
+void *UHCI_SendIsoch(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length, int When);
+void *UHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+ int isOutbound,
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ );
+void *UHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length);
void UHCI_CheckPortUpdate(void *Ptr);
void UHCI_int_InterruptThread(void *Unused);
tUHCI_TD *gaUHCI_TDPool;
tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS];
tUSBHostDef gUHCI_HostDef = {
- .InterruptIN = UHCI_InterruptIN,
- .InterruptOUT = UHCI_InterruptOUT,
- .StopInterrupt = UHCI_StopInterrupt,
+ .InitInterrupt = UHCI_InitInterrupt,
+// .InitIsoch = UHCI_InitIsoch,
+ .InitControl = UHCI_InitControl,
+ .InitBulk = UHCI_InitBulk,
+ .RemEndpoint = UHCI_RemoveEndpoint,
- .ControlSETUP = UHCI_ControlSETUP,
- .ControlIN = UHCI_ControlIN,
- .ControlOUT = UHCI_ControlOUT,
-
- .BulkOUT = UHCI_BulkOUT,
- .BulkIN = UHCI_BulkIN,
+// .SendIsoch = UHCI_SendIsoch,
+ .SendControl = UHCI_SendControl,
+ .SendBulk = UHCI_SendBulk,
+ .FreeOp = NULL,
- .CheckPorts = UHCI_CheckPortUpdate
+ .CheckPorts = UHCI_CheckPortUpdate,
+// .ClearPortFeature = NULL,
+// .GetBusState = NULL,
+// .GetPortStatus = NULL,
+// .SetPortFeature = NULL
};
tSemaphore gUHCI_InterruptSempahore;
int ret;
ENTER("");
-
+
+ if( Arguments && *Arguments && strcmp(*Arguments, "0") == 0 )
+ {
+ LOG("Disabled by argument");
+ LEAVE('i', MODULE_ERR_NOTNEEDED);
+ return MODULE_ERR_NOTNEEDED;
+ }
+
// Initialise with no maximum value
Semaphore_Init( &gUHCI_InterruptSempahore, 0, 0, "UHCI", "Interrupt Queue");
{
tPAddr tmp;
gaUHCI_TDPool = (void *) MM_AllocDMA(1, 32, &tmp);
+ memset(gaUHCI_TDPool, 0, PAGE_SIZE);
+ LOG("gaUHCI_TDPool = %p (%P)", gaUHCI_TDPool, tmp);
}
// Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices
+ // Class:SubClass:Protocol = 0xC (Serial) : 0x3 (USB) : 0x00 (UHCI)
while( (id = PCI_GetDeviceByClass(0x0C0300, 0xFFFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
{
tUHCI_Controller *cinfo = &gUHCI_Controllers[i];
Uint32 base_addr;
- // NOTE: Check "protocol" from PCI?
cinfo->PciId = id;
base_addr = PCI_GetBAR(id, 4);
LEAVE('i', -1);
return -1;
}
+ LOG("->FrameList = %p (%P)", Host->FrameList, Host->PhysFrameList);
Host->TDQHPage = (void *) MM_AllocDMA(1, 32, &Host->PhysTDQHPage);
if( !Host->TDQHPage ) {
LEAVE('i', -1);
return -1;
}
+ LOG("->TDQHPage = %p (%P)", Host->TDQHPage, Host->PhysTDQHPage);
// Fill frame list
// - The numbers 0...31, but bit reversed (16 (0b1000) = 1 (0b00001)
0,16,8,24,4,20,12,28,2,18,10,26,6,22,14,30,
1,17,9,25,5,21,13,29,3,19,11,27,7,23,15,31
};
+ // Fill all slots (but every 4th will be changed below
for( int i = 0; i < 1024; i ++ ) {
- Uint32 addr = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->ControlQH );
+ Uint32 addr = MM_GetPhysAddr( &Host->TDQHPage->ControlQH );
Host->FrameList[i] = addr | 2;
}
for( int i = 0; i < 64; i ++ ) {
Host->FrameList[768 + i*4] = addr | 2;
}
- // Build up interrupt binary tree
+ // Build up interrupt binary tree
{
tUHCI_QH *dest = Host->TDQHPage->InterruptQHs;
Uint32 destphys = Host->PhysTDQHPage;
// Set up next pointer to index to i/2 in the next step
for( int _count = 64; _count > 1; _count /= 2 )
{
+ LOG("count=%i, dest=%p, destphys=%P", _count, dest, destphys);
for( int i = 0; i < _count; i ++ ) {
+ LOG(" %i-%i: %P==%P", _count, i, MM_GetPhysAddr(dest+i), destphys+i*sizeof(tUHCI_QH));
dest[i].Next = destphys + (_count + i/2) * sizeof(tUHCI_QH) + 2;
dest[i].Child = 1;
}
dest += _count; destphys += _count * sizeof(tUHCI_QH);
}
// Skip padding, and move to control QH
- dest->Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+ dest->Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
dest->Child = 1;
}
// Set up control and bulk queues
- Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+ Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
Host->TDQHPage->ControlQH.Child = 1;
Host->TDQHPage->BulkQH.Next = 1;
Host->TDQHPage->BulkQH.Child = 1;
PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 );
// Enable processing
+ LOG("Processing enabling");
_OutWord( Host, USBCMD, 0x0001 );
LEAVE('i', 0);
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 );
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;
// Stop controller
+ tPAddr tdaddr = MM_GetPhysAddr( TD );
+ ASSERT(tdaddr);
_OutWord( Cont, USBCMD, 0x0000 );
// Add
TD->Link = 1;
if( QH->Child & 1 ) {
- QH->Child = MM_GetPhysAddr( (tVAddr)TD );
+ QH->Child = tdaddr;
}
else {
// Depth first
- QH->_LastItem->Link = MM_GetPhysAddr( (tVAddr)TD ) | 4;
+ QH->_LastItem->Link = tdaddr | 4;
}
QH->_LastItem = TD;
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;
if(
((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE
#if PHYS_BITS > 32
- || MM_GetPhysAddr( (tVAddr)Data ) >> 32
+ || MM_GetPhysAddr( Data ) >> 32
#endif
)
{
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 );
+ info->FirstPage = MM_GetPhysAddr( Data );
+ info->SecondPage = MM_GetPhysAddr( (const char *)Data + Length - 1 );
}
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;
}
else
{
- td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
+ td->BufferPointer = MM_GetPhysAddr( Data );
td->_info.bFreePointer = 0;
}
if( info ) {
LOG("info = %p", info);
- td->Control |= (1 << 24);
+ td->Control |= TD_CTL_IOC;
td->_info.ExtraInfo = info;
}
UHCI_int_AppendTD(Cont, qh, TD);
}
-void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+// --------------------------------------------------------------------
+// API
+// --------------------------------------------------------------------
+void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound,
+ int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len)
{
tUHCI_TD *td;
-
- if( Period < 0 ) return NULL;
-
- ENTER("pPtr xDest iPeriod pCb pCbData pBuf iLength",
- Ptr, Dest, Period, Cb, CbData, Buf, Length);
+ if( Period <= 0 ) return NULL;
+
+ ENTER("pPtr xEndpt bbOutbound iPeriod pCb pCbData pBuf iLen",
+ Ptr, Endpt, bOutbound, Period, Cb, CbData, Buf, Len);
// TODO: Data toggle?
- td = UHCI_int_CreateTD(Ptr, Dest, PID_IN, 0, Cb, CbData, Buf, Length);
+ td = UHCI_int_CreateTD(Ptr, Endpt, (bOutbound ? PID_OUT : PID_IN), 0, Cb, CbData, Buf, Len);
if( !td ) return NULL;
UHCI_int_SetInterruptPoll(Ptr, td, Period);
-
- LEAVE('p', td);
+
+ LEAVE('p', td);
return td;
}
-// TODO: Does interrupt OUT make sense?
-void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+
+void *UHCI_int_InitEndpt(tUHCI_Controller *Cont, int Type, int Endpt, size_t MaxPacketSize)
{
- tUHCI_TD *td;
+ if( Endpt >= 256*16 )
+ return NULL;
- if( Period < 0 ) return NULL;
+ if( MaxPacketSize > MAX_PACKET_SIZE) {
+ Log_Warning("UHCI", "MaxPacketSize for %x greater than controller max (%i > %i)",
+ Endpt, MaxPacketSize, MAX_PACKET_SIZE);
+ return NULL;
+ }
- ENTER("pPtr xDest iPeriod pCb pCbData pBuf, iLength",
- Ptr, Dest, Period, Cb, CbData, Buf, Length);
+ if( Cont->DevInfo[Endpt / 16] == NULL ) {
+ Cont->DevInfo[Endpt / 16] = calloc( 1, sizeof(*Cont->DevInfo[0]) );
+ }
+ tUHCI_EndpointInfo *epi = &Cont->DevInfo[Endpt/16]->EndpointInfo[Endpt%16];
+ if( epi->Type ) {
+ // oops, in use
+ Log_Warning("UHCI", "Endpoint %x reused?", Endpt);
+ return NULL;
+ }
- // TODO: Data toggle?
- td = UHCI_int_CreateTD(Ptr, Dest, PID_OUT, 0, Cb, CbData, Buf, Length);
- if( !td ) return NULL;
-
- UHCI_int_SetInterruptPoll(Ptr, td, Period);
+ epi->MaxPacketSize = MaxPacketSize;
+ epi->Type = Type;
+ epi->Tgl = 0;
+
+ return (void*)(tVAddr)(Endpt+1);
- LEAVE('p', td);
- return td;
}
-void UHCI_StopInterrupt(void *Ptr, void *Handle)
+void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize)
{
- // TODO: Stop interrupt transaction
- Log_Error("UHCI", "TODO: Implement UHCI_StopInterrupt");
+ return UHCI_int_InitEndpt(Ptr, 1, Endpt, MaxPacketSize);
}
-void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length)
+void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize)
{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
- tUHCI_TD *td;
+ return UHCI_int_InitEndpt(Ptr, 2, Endpt, MaxPacketSize);
+}
- ENTER("pPtr xDest iTgl pData iLength", Ptr, Dest, Tgl, Data, Length);
+void UHCI_RemoveEndpoint(void *Ptr, void *Handle)
+{
+ tUHCI_Controller *Cont = Ptr;
+ if( Handle == NULL )
+ return ;
- td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, Data, Length);
- UHCI_int_AppendTD(Cont, qh, td);
-
- LEAVE('p', td);
-
- return td;
+ if( (tVAddr)Handle <= 256*16 ) {
+ int addr = (tVAddr)Handle;
+ Cont->DevInfo[addr/16]->EndpointInfo[addr%16].Type = 0;
+ }
+ else {
+ // TODO: Stop interrupt transaction
+ Log_Error("UHCI", "TODO: Implement stopping interrupt polling");
+ }
}
-void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
+
+void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+ int bOutbound, // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ )
{
+ ENTER("pPtr pEndpt bOutbound", Ptr, Endpt, bOutbound);
+
tUHCI_Controller *Cont = Ptr;
tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
tUHCI_TD *td;
+ tUHCI_EndpointInfo *epi;
+ int dest, tgl;
+ size_t mps;
- ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
+ if( Endpt == NULL ) {
+ Log_Error("UHCI", "Passed a NULL Endpoint handle");
+ LEAVE('n');
+ return NULL;
+ }
- td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, Tgl, Cb, CbData, Data, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+ // Sanity check Endpt
+ if( (tVAddr)Endpt > 0x800 ) {
+ LEAVE('n');
+ return NULL;
+ }
+ dest = (tVAddr)Endpt - 1;
+ if( Cont->DevInfo[dest/16] == NULL ) LEAVE_RET('n', NULL);
+ epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+ if( epi->Type != 1 ) LEAVE_RET('n', NULL);
+ mps = epi->MaxPacketSize;
+ tgl = epi->Tgl;
+
+ // TODO: Build up list and then append to QH in one operation
+
+ char *data_ptr, *status_ptr;
+ size_t data_len, status_len;
+ Uint8 data_pid, status_pid;
+
+ if( bOutbound ) {
+ data_pid = PID_OUT; data_ptr = (void*)OutData; data_len = OutLength;
+ status_pid = PID_IN; status_ptr = InData; status_len = InLength;
+ }
+ else {
+ data_pid = PID_IN; data_ptr = InData; data_len = InLength;
+ status_pid = PID_OUT; status_ptr = (void*)OutData; status_len = OutLength;
+ }
- LEAVE('p', td);
- return td;
-}
-void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
-{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
- tUHCI_TD *td;
+ // Sanity check data lengths
+ if( SetupLength > mps ) LEAVE_RET('n', NULL);
+ if( status_len > mps ) LEAVE_RET('n', NULL);
- ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
+ // Create and append SETUP packet
+ td = UHCI_int_CreateTD(Cont, dest, PID_SETUP, tgl, NULL, NULL, (void*)SetupData, SetupLength);
+ UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
+
+ // Send data packets
+ while( data_len > 0 )
+ {
+ size_t len = MIN(data_len, mps);
+ td = UHCI_int_CreateTD(Cont, dest, data_pid, tgl, NULL, NULL, data_ptr, len);
+ UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
+
+ data_ptr += len;
+ data_len -= len;
+ }
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, !!Tgl, Cb, CbData, Data, Length);
+ // Send status
+ td = UHCI_int_CreateTD(Cont, dest, status_pid, tgl, Cb, CbData, status_ptr, status_len);
UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
+
+ // Update toggle value
+ epi->Tgl = tgl;
- LEAVE('p', td);
+ // --- HACK!!!
+// for( int i = 0; i < 1024; i ++ )
+// {
+// LOG("- FrameList[%i] = %x", i, Cont->FrameList[i]);
+// }
+ // --- /HACK
+
+ LEAVE('p', td);
return td;
}
-void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+void *UHCI_SendBulk(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, int bOutbound, void *Data, size_t Length)
{
tUHCI_Controller *Cont = Ptr;
tUHCI_QH *qh = &Cont->TDQHPage->BulkQH;
- tUHCI_TD *td;
- char *src = Buf;
+ tUHCI_TD *td = NULL;
+ tUHCI_EndpointInfo *epi;
+ int dest, tgl;
+ size_t mps;
- ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
+ ENTER("pPtr pEndpt pCb pCbData bOutbound pData iLength", Ptr, Endpt, Cb, CbData, bOutbound, Data, 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( Endpt == NULL ) {
+ Log_Error("UHCI", "_SendBulk passed a NULL endpoint handle");
+ LEAVE('n');
+ return NULL;
}
- LOG("Final");
- td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+ // Sanity check Endpt
+ if( (tVAddr)Endpt > 256*16 ) {
+ Log_Error("UHCI", "_SendBulk passed an interrupt endpoint handle");
+ LEAVE('n');
+ return NULL;
+ }
+ dest = (tVAddr)Endpt - 1;
+ if( Cont->DevInfo[dest/16] == NULL ) {
+ Log_Error("UHCI", "_SendBulk passed an uninitialised handle");
+ LEAVE('n');
+ return NULL;
+ }
+ epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+ if( epi->Type != 2 ) {
+ Log_Error("UHCI", "_SendBulk passed an invalid endpoint type (%i!=2)", epi->Type);
+ LEAVE('n');
+ return NULL;
+ }
+ tgl = epi->Tgl;
+ mps = epi->MaxPacketSize;
- LEAVE('p', td);
- return td;
-}
-void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->BulkQH;
- tUHCI_TD *td;
- char *dst = Buf;
+ Uint8 pid = (bOutbound ? PID_OUT : PID_IN);
- ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
- while( Length > MAX_PACKET_SIZE )
+ char *pos = Data;
+ while( Length > 0 )
{
- LOG("MaxPacket (rem = %i)", Length);
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, MAX_PACKET_SIZE);
+ size_t len = MIN(mps, Length);
+
+ td = UHCI_int_CreateTD(Cont, dest, pid, tgl, Cb, (len == Length ? CbData : NULL), pos, len);
UHCI_int_AppendTD(Cont, qh, td);
- bToggle = !bToggle;
- Length -= MAX_PACKET_SIZE;
- dst += MAX_PACKET_SIZE;
+ pos += len;
+ Length -= len;
+ tgl = !tgl;
}
-
- LOG("Final");
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+
+ epi->Tgl = tgl;
LEAVE('p', td);
return td;
}
+// ==========================
// === INTERNAL FUNCTIONS ===
+// ==========================
void UHCI_CheckPortUpdate(void *Ptr)
{
tUHCI_Controller *Host = Ptr;
}
- tPAddr global_pool = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
+ tPAddr global_pool = MM_GetPhysAddr( gaUHCI_TDPool );
if( PAddr < global_pool || PAddr >= global_pool + PAGE_SIZE ) return NULL;
{
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);
}
// 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 ;
}
- LOG("Removed %p from QH %p", td, QH);
+ LOG("Removed %p from QH %p", td, QH);
+ ASSERT(td->Link);
if( !prev )
QH->Child = td->Link;
else
prev->Link = td->Link;
cur_td = td->Link;
+ nCleaned ++;
+ }
+
+ if( nCleaned == 0 ) {
+ LOG("Nothing cleaned... what the?");
}
// re-enable controller
{
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 )
{
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
Threads_SetName("UHCI Interrupt Handler");
for( ;; )
{
+ int nSeen = 0;
+
LOG("zzzzz....");
// 0 = Take all
Semaphore_Wait(&gUHCI_InterruptSempahore, 0);
// 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 )
// 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
{
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,
LOG("Cleaned %p (->Control = %x)", td, td->Control);
td->_info.bActive = 0;
}
+
+ if( nSeen == 0 ) {
+ LOG("Why did you wake me?");
+ }
}
}
// 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 )
{
Semaphore_Signal(&gUHCI_InterruptSempahore, 1);
}
- LOG("status = 0x%04x", status);
+ // USB Error Interrupt
+ if( status & 2 )
+ {
+ Log_Notice("UHCI", "USB Error");
+ }
+
+ // Resume Detect
+ // - Fired if in suspend state and a USB device sends the RESUME signal
+ if( status & 4 )
+ {
+ Log_Notice("UHCI", "Resume Detect");
+ }
+
+ // Host System Error
+ if( status & 8 )
+ {
+ Log_Notice("UHCI", "Host System Error");
+ }
+
+ // Host Controller Process Error
+ if( status & 0x10 )
+ {
+ Log_Error("UHCI", "Host controller process error on controller %p", Ptr);
+ // Spam Tree
+ //for( int i = 0; i < 1024; i += 4 ) {
+ // LOG("%4i: %x", i, Host->FrameList[i]);
+ //}
+
+ tPAddr phys = Host->TDQHPage->ControlQH.Child;
+ while( !(phys & 1) && MM_GetRefCount(phys & ~15))
+ {
+ tUHCI_TD *td = UHCI_int_GetTDFromPhys(Host, phys);
+ LOG("%08P: %08x %08x %08x", phys, td->Control, td->Token, td->BufferPointer);
+ phys = td->Link;
+ }
+ }
+
_OutWord(Host, USBSTS, status);
}