// === CODE === void Timer_CallbackThread(void *Unused) { Threads_SetName("Timer Callback Thread"); Workqueue_Init(&gTimers_CallbackQueue, "Timer Callbacks", offsetof(tTimer, Next)); for(;;) { tTimer *timer = Workqueue_GetWork(&gTimers_CallbackQueue); if( !timer->Callback ) { LOG("Timer %p doesn't have a callback", timer); ASSERT( timer->Callback ); } // Save callback and argument (because once the mutex is released // the timer may no longer be valid) tTimerCallback *cb = timer->Callback; void *arg = timer->Argument; LOG("Callback fire %p", timer); // Allow Time_RemoveTimer to be called safely timer->bActive = 0; // Fire callback cb(arg); // Mark timer as no longer needed } }
void USB_PortCtl_Worker(void *Unused) { Threads_SetName("USB PortCtl Worker"); for(;;) { tUSBHubPort *port; tUSBHub *hub; port = Workqueue_GetWork(&gUSB_PortCtl_WorkQueue); if( !port ) { Log_Warning("USB", "PortCtl Workqueue returned NULL"); break; } hub = (tUSBHub*)(port - port->PortNum) - 1; LOG("port = %p, hub = %p", port, hub); switch(port->Status) { case 1: // Assert reset USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_RESET); LOG("Port reset starting"); // Wait 50 ms Time_Delay(50); USB_PortCtl_ClearPortFeature(hub, port->PortNum, PORT_RESET); Time_Delay(10); // May take up to 2ms for reset to clear // Enable port LOG("Port enabling"); USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_ENABLE); // Begin connect processing port->Status = 2; USB_DeviceConnected(hub, port->PortNum); break; } } }