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; } } }
/** * This function waits on each emulated VBL to synchronize the real time * with the emulated ST. * Unfortunately SDL_Delay and other sleep functions like usleep or nanosleep * are very inaccurate on some systems like Linux 2.4 or Mac OS X (they can only * wait for a multiple of 10ms due to the scheduler on these systems), so we have * to "busy wait" there to get an accurate timing. * All times are expressed as micro seconds, to avoid too much rounding error. */ void Main_WaitOnVbl(void) { Sint64 CurrentTicks; static Sint64 DestTicks = 0; Sint64 FrameDuration_micro; Sint64 nDelay; nVBLCount++; if (nRunVBLs && nVBLCount >= nRunVBLs) { /* show VBLs/s */ Main_PauseEmulation(true); exit(0); } // FrameDuration_micro = (Sint64) ( 1000000.0 / nScreenRefreshRate + 0.5 ); /* round to closest integer */ FrameDuration_micro = ClocksTimings_GetVBLDuration_micro ( ConfigureParams.System.nMachineType , 68 ); // FrameDuration_micro = 1000000/50; CurrentTicks = Time_GetTicks(); if ( DestTicks == 0 ) /* first call, init DestTicks */ { DestTicks = CurrentTicks + FrameDuration_micro; } nDelay = DestTicks - CurrentTicks; /* Do not wait if we are in fast forward mode or if we are totally out of sync */ if (ConfigureParams.System.bFastForward == true || nDelay < -4*FrameDuration_micro || nDelay > 50*FrameDuration_micro) { if (ConfigureParams.System.bFastForward == true) { if (!nFirstMilliTick) nFirstMilliTick = Main_GetTicks(); } if (nFrameSkips < ConfigureParams.Screen.nFrameSkips) { nFrameSkips += 1; Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips); } /* Only update DestTicks for next VBL */ DestTicks = CurrentTicks + FrameDuration_micro; return; } /* If automatic frameskip is enabled and delay's more than twice * the effect of single frameskip, decrease frameskip */ if (nFrameSkips > 0 && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT && 2*nDelay > FrameDuration_micro/nFrameSkips) { nFrameSkips -= 1; Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips); } if (bAccurateDelays) { /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */ if (nDelay > 1000) Time_Delay(nDelay - 1000); } else { /* No accurate SDL_Delay -> only wait if more than 5ms to go... */ if (nDelay > 5000) Time_Delay(nDelay<10000 ? nDelay-1000 : 9000); } /* Now busy-wait for the right tick: */ while (nDelay > 0) { CurrentTicks = Time_GetTicks(); nDelay = DestTicks - CurrentTicks; /* If the delay is still bigger than one frame, somebody * played tricks with the system clock and we have to abort */ if (nDelay > FrameDuration_micro) break; } //printf ( "tick %lld\n" , CurrentTicks ); /* Update DestTicks for next VBL */ DestTicks += FrameDuration_micro; }