_error:
cont->PhysBase = 0;
if( cont->CapRegs )
- MM_Deallocate( (tVAddr)cont->CapRegs );
+ MM_Deallocate( cont->CapRegs );
if( cont->PeriodicQueue )
- MM_Deallocate( (tVAddr)cont->PeriodicQueue );
+ MM_Deallocate( cont->PeriodicQueue );
if( cont->TDPool )
- MM_Deallocate( (tVAddr)cont->TDPool );
+ MM_Deallocate( cont->TDPool );
LEAVE('i', 2);
return 2;
}
int period_pow = _GetClosestPower2(Period);
tEHCI_Endpoint *endpt = EHCI_int_AllocateEndpt(Cont, Endpoint, Length, period_pow);
+ endpt->Next = Cont->FirstInterruptEndpt;
+ Cont->FirstInterruptEndpt = endpt;
// Allocate a QH
tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, endpt, Cb, CbData);
}
}
+void EHCI_int_CheckInterruptQHs(tEHCI_Controller *Cont)
+{
+ for( tEHCI_Endpoint *endpt = Cont->FirstInterruptEndpt; endpt; endpt = endpt->Next )
+ {
+ tEHCI_QH *qh = endpt->ActiveQHs;
+ // Check if the TD of the first QH is active
+ if( qh->Overlay.Token & QTD_TOKEN_STS_ACTIVE )
+ continue ;
+ // Inactive, fire interrupt and re-trigger
+ if( !qh->Impl.Callback ) {
+ // Umm... ?
+ }
+ else
+ {
+ tEHCI_qTD *last = qh->Impl.LastTD;
+ size_t remaining_len = (last->Token >> 16) & 0x7FFF;
+ if( remaining_len > last->Impl.Length )
+ remaining_len = last->Impl.Length;
+ size_t transferred_len = last->Impl.Length - remaining_len;
+
+ LOG("Calling %p(%p) for Intr EndPt %x (%p+0x%x)",
+ qh->Impl.Callback, qh->Impl.CallbackData,
+ qh->Impl.Endpt->EndpointID, last->Impl.Ptr, transferred_len);
+ qh->Impl.Callback(qh->Impl.CallbackData, last->Impl.Ptr, transferred_len);
+ }
+ qh->Impl.FirstTD->Token |= QTD_TOKEN_STS_ACTIVE;
+ qh->Overlay.Token |= QTD_TOKEN_STS_ACTIVE;
+ }
+}
+
void EHCI_int_RetireQHs(tEHCI_Controller *Cont)
{
tEHCI_QH *prev = Cont->DeadQH;
LOG("Calling %p(%p) for EndPt %x (%p+0x%x)",
qh->Impl.Callback, qh->Impl.CallbackData,
qh->Impl.Endpt->EndpointID, last->Impl.Ptr, transferred_len);
+ //if( last->Impl.Ptr )
+ // Debug_HexDump("EHCI Callback Data", last->Impl.Ptr, transferred_len);
qh->Impl.Callback(qh->Impl.CallbackData, last->Impl.Ptr, transferred_len);
}
void EHCI_int_InterruptThread(void *ControllerPtr)
{
tEHCI_Controller *Cont = ControllerPtr;
+ Threads_SetName("EHCI Interrupt Worker");
while(Cont->OpRegs)
{
Uint32 events;
if( events & EHCI_THREADEVENT_IOC )
{
// IOC, handle completed requests
- Log_Warning("EHCI", "%P IOC - TODO: Call registered callbacks and reclaim",
- Cont->PhysBase);
// Search periodic lists for one that fired
+ EHCI_int_CheckInterruptQHs(Cont);
// Retire QHs
// - Remove them from the queue and ask the controller to bell when they're removable
EHCI_int_RetireQHs(Cont);