//================================================================================================ // // SuspendController // //================================================================================================ // void AppleUSBUHCI::SuspendController(void) { UInt16 cmd, value; int i; USBTrace( kUSBTUHCI, kTPUHCISuspendController, (uintptr_t)this, 0, 0, 1 ); USBLog(5, "AppleUSBUHCI[%p]::SuspendController", this); USBLog(5, "AppleUSBUHCI[%p]: cmd state %x, status %x", this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS)); // Stop the controller Run(false); for (i=0; i< 2; i++) { value = ReadPortStatus(i) & kUHCI_PORTSC_MASK; if (value & kUHCI_PORTSC_PED) { if (value & kUHCI_PORTSC_SUSPEND) { USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is suspended [%p]", this, i, (void*)value); } else { USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is enabled but not suspended [%p]", this, i, (void*)value); } } else { USBLog(5, "AppleUSBUHCI[%p]::SuspendController - port[%d] is not enabled [%p]", this, i, (void*)value); } // only do this for controllers with overcurrent additions. if ((_ERRATA64BITS & kErrataUHCISupportsOvercurrent) && (value & kUHCI_PORTSC_OCI)) // Is the latched Overcurrent set? { // if so, clear it or we won't suspend. USBLog(1, "AppleUSBUHCI[%p]::SuspendController - port[%d] had the overcurrent bit set. Clearing it", this, i); USBTrace( kUSBTUHCI, kTPUHCISuspendController, (uintptr_t)this, i, 0, 2 ); WritePortStatus(i, kUHCI_PORTSC_OCI); // clear overcurrent indicator } } // Put the controller in Global Suspend cmd = ioRead16(kUHCI_CMD) & ~kUHCI_CMD_FGR; cmd |= kUHCI_CMD_EGSM; ioWrite16(kUHCI_CMD, cmd); _myBusState = kUSBBusStateSuspended; IOSleep(3); USBLog(5, "AppleUSBUHCI[%p]: suspend done, cmd %x, status %x", this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS)); }
//================================================================================================ // // DozeController // //================================================================================================ // IOReturn AppleUSBUHCI::DozeController(void) { UInt16 cmd; int i; bool portsBeingResumed = false; USBTrace( kUSBTUHCI, KTPUHCIDozeController, (uintptr_t)this, 0, 0, 0); USBLog(6, "AppleUSBUHCI[%p]::DozeController", this); for (i=0; i<kUHCI_NUM_PORTS; i++) { if (_rhPortBeingResumed[i]) { USBLog(1, "AppleUSBUHCI[%p]::DozeController - port (%d) is being resumed. not stopping the controller", this, i+1); portsBeingResumed = true; } } if (!portsBeingResumed) { showRegisters(7, "+DozeController - stopping controller"); Run(false); // In order to get a Resume Detected interrupt, the controller needs to be in Global suspend mode, so we will do that even when "dozing". USBLog(6, "AppleUSBUHCI[%p]::DozeController Globally suspending", this); // Put the controller in Global Suspend cmd = ioRead16(kUHCI_CMD) & ~kUHCI_CMD_FGR; cmd |= kUHCI_CMD_EGSM; ioWrite16(kUHCI_CMD, cmd); _myBusState = kUSBBusStateSuspended; IOSleep(3); } return kIOReturnSuccess; }
//================================================================================================ // // EnableInterruptsFromController // //================================================================================================ // IOReturn AppleUSBUHCI::EnableInterruptsFromController(bool enable) { USBTrace( kUSBTUHCI, KTPUHCIEnableInterrupts, (uintptr_t)this, enable, 0, 0); if (enable) { USBLog(5, "AppleUSBUHCI[%p]::EnableInterruptsFromController - enabling interrupts, USBIntr(%p) _savedUSBIntr(%p)", this, (void*)ioRead16(kUHCI_INTR), (void*)_saveInterrupts); ioWrite16(kUHCI_INTR, _saveInterrupts); _saveInterrupts = 0; EnableUSBInterrupt(true); } else { _saveInterrupts = ioRead16(kUHCI_INTR); ioWrite16(kUHCI_INTR, 0); EnableUSBInterrupt(false); USBLog(5, "AppleUSBUHCI[%p]::EnableInterruptsFromController - interrupts disabled, _saveInterrupts(%p)", this, (void*)_saveInterrupts); } return kIOReturnSuccess; }
//================================================================================================ // // ResetControllerState // //================================================================================================ // IOReturn AppleUSBUHCI::ResetControllerState(void) { UInt32 value; int i; USBTrace( kUSBTUHCI, KTPUHCIResetControllerState, (uintptr_t)this, 0, 0, 0); USBLog(5, "AppleUSBUHCI[%p]::+ResetControllerState", this); // reset the controller Command(kUHCI_CMD_HCRESET); for(i=0; (i < kUHCI_RESET_DELAY) && (ioRead16(kUHCI_CMD) & kUHCI_CMD_HCRESET); i++) { IOSleep(1); } if (i >= kUHCI_RESET_DELAY) { USBError(1, "AppleUSBUHCI::ResetControllerStatecontroller - reset failed"); return kIOReturnTimeout; } USBLog(5, "AppleUSBUHCI[%p]::ResetControllerStatecontroller - reset done after %d spins", this, i); // restore the frame list register if (_framesPaddr != NULL) { ioWrite32(kUHCI_FRBASEADDR, _framesPaddr); } for (i = 0; i < kUHCI_NUM_PORTS; i++) { _lastPortStatus[i] = 0; } // Use 64-byte packets, and mark controller as configured Command(kUHCI_CMD_MAXP | kUHCI_CMD_CF); USBLog(5, "AppleUSBUHCI[%p]::-ResetControllerState", this); return kIOReturnSuccess; }
//================================================================================================ // // WakeControllerFromDoze // //================================================================================================ // IOReturn AppleUSBUHCI::WakeControllerFromDoze(void) { UInt16 cmd; int i; bool portHasRD[kUHCI_NUM_PORTS]; UInt16 status; USBTrace( kUSBTUHCI, KTPUHCIWakeFromDoze, (uintptr_t)this, 0, 0, 0); // First, see if we have any ports that have the RD bit set. If they do, then we can go ahead and clear it after we waited the 20ms for the // Global resume for (i=0; i<kUHCI_NUM_PORTS; i++) { status = ReadPortStatus(i); if (status & kUHCI_PORTSC_RD) { USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze controller port %d has kUHCI_PORTSC_RD set", this, i+1); portHasRD[i] = true; } else { portHasRD[i] = false; } } // If we are in Global Suspend mode, we need to resume the controller. We will wait 20ms with the gate held. However, since we only // get into this mode if all devices are suspended, then delaying while holding the wl will not prevent any completions from happening, since // there aren't any. cmd = ioRead16(kUHCI_CMD); if (cmd & kUHCI_CMD_EGSM) { USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze controller is globally suspended - forcing resume", this); cmd |= kUHCI_CMD_FGR; ioWrite16(kUHCI_CMD, cmd); cmd = ioRead16(kUHCI_CMD); USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze after EGSM->FGR, cmd is[%p], sleeping 20ms", this, (void*)cmd); IOSleep(20); cmd &= ~kUHCI_CMD_FGR; cmd &= ~kUHCI_CMD_EGSM; ioWrite16(kUHCI_CMD, cmd); // Clear any RD bits in the port if they were set, now that we have waited 20ms for (i=0; i<kUHCI_NUM_PORTS; i++) { if (portHasRD[i] ) { status = ReadPortStatus(i) & kUHCI_PORTSC_MASK; status &= ~(kUHCI_PORTSC_RD | kUHCI_PORTSC_SUSPEND); USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze de-asserting resume signal for port %d by writing (%p)", this, i+1, (void*)status); WritePortStatus(i, status); IOSync(); IOSleep(2); // allow it to kick in } } } USBLog(6, "AppleUSBUHCI[%p]::WakeControllerFromDoze calling Run(true)", this); Run(true); _myBusState = kUSBBusStateRunning; showRegisters(7, "-WakeControllerFromDoze"); return kIOReturnSuccess; }
//================================================================================================ // // RestartControllerFromReset // //================================================================================================ // IOReturn AppleUSBUHCI::RestartControllerFromReset(void) { USBTrace( kUSBTUHCI, KTPUHCIRestartControllerFromReset, (uintptr_t)this, 0, 0, 0); USBLog(5, "AppleUSBUHCI[%p]::RestartControllerFromReset - _myBusState(%d) CMD(%p) STS(%p) FRBASEADDR(%p) IOPCIConfigCommand(%p)", this, (int)_myBusState, (void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand)); Run(true); // prepare the _saveInterrupts variable for later enabling _saveInterrupts = kUHCI_INTR_TIE | kUHCI_INTR_RIE | kUHCI_INTR_IOCE | kUHCI_INTR_SPIE; USBLog(5, "AppleUSBUHCI[%p]::RestartControllerFromReset - I set _saveInterrupts to (%p)", this, (void*)_saveInterrupts); return kIOReturnSuccess; }
//================================================================================================ // // ResumeController // //================================================================================================ // void AppleUSBUHCI::ResumeController(void) { UInt16 cmd; int i; USBTrace( kUSBTUHCI, KTPUHCIResumeController , (uintptr_t)this, 0, 0, 0); showRegisters(7, "+ResumeController"); cmd = ioRead16(kUHCI_CMD); if (cmd & kUHCI_CMD_RS) { USBLog(3, "AppleUSBUHCI[%p]::ResumeController - already running - returning", this); return; } // I need to save the existing frame list before I turn on processing so I can send SOF only for 10ms after we turn the controller on for (i=0;i < kUHCI_NVFRAMES; i++) { _frameList[i] |= HostToUSBLong(kUHCI_FRAME_T); } if (cmd & kUHCI_CMD_EGSM) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController controller is globally suspended - forcing resume", this); cmd |= kUHCI_CMD_FGR; ioWrite16(kUHCI_CMD, cmd); cmd = ioRead16(kUHCI_CMD); USBLog(5, "AppleUSBUHCI[%p]::ResumeController after EGSM->FGR, cmd is[%p]", this, (void*)cmd); } if (cmd & kUHCI_CMD_FGR) { // this could either be because the remote wwakeup caused this state or because we did above // need to wait 20ms IOSleep(20); cmd &= ~kUHCI_CMD_FGR; cmd &= ~kUHCI_CMD_EGSM; ioWrite16(kUHCI_CMD, cmd); } if ((cmd & (kUHCI_CMD_MAXP | kUHCI_CMD_CF)) != (kUHCI_CMD_MAXP | kUHCI_CMD_CF)) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController marking MAXP and CF", this); cmd |= (kUHCI_CMD_MAXP | kUHCI_CMD_CF); ioWrite16(kUHCI_CMD, cmd); } // restore the frame list register if (_framesPaddr != NULL) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController setting FRBASEADDR[%p]", this, (void*)_framesPaddr); ioWrite32(kUHCI_FRBASEADDR, _framesPaddr); } USBLog(5, "AppleUSBUHCI[%p]::ResumeController starting controller", this); Run(true); // wait 10 ms for the device to recover IOSleep(10); // restore the list for (i=0;i < kUHCI_NVFRAMES; i++) { _frameList[i] &= ~HostToUSBLong(kUHCI_FRAME_T); } USBLog(7, "AppleUSBUHCI[%p]::ResumeController resume done, cmd %x, status %x ports[%p, %p]", this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS),(void*)ReadPortStatus(0), (void*)ReadPortStatus(1)); showRegisters(7, "-ResumeController"); }
IOReturn AppleUSBUHCI::RHSuspendPort(int port, bool suspended) { UInt16 cmd, value; USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) _rhPortBeingResumed[%d](%s)", this, port, suspended ? "SUSPEND" : "RESUME", (int)port-1, _rhPortBeingResumed[port-1] ? "true" : "false"); showRegisters(7, "RHSuspendPort"); port--; // convert 1-based to 0-based. if (_rhPortBeingResumed[port]) { if (!suspended) { USBLog(3, "AppleUSBUHCI[%p]::RHSuspendPort - resume on port (%d) already being resumed - gracefully ignoring", this, (int)port+1); return kIOReturnSuccess; } USBLog(1, "AppleUSBUHCI[%p]::RHSuspendPort - trying to suspend port (%d) which is being resumed - UNEXPECTED", this, (int)port+1); USBTrace( kUSBTUHCI, kTPUHCIRHSuspendPort, (uintptr_t)this, (int)port+1, 0, 0); } cmd = ioRead16(kUHCI_CMD); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; if (suspended) { value |= kUHCI_PORTSC_SUSPEND; value &= ~kUHCI_PORTSC_RD; } else { if (cmd & kUHCI_CMD_EGSM) { /* Can't un-suspend a port during global suspend. */ USBError(1, "AppleUSBUHCI[%p]: attempt to resume during global suspend", this); return kIOReturnError; } value |= (kUHCI_PORTSC_SUSPEND | kUHCI_PORTSC_RD); } // Always enable the port also. value |= kUHCI_PORTSC_PED; USBLog(5, "AppleUSBUHCI[%p]: writing (%p) to port control", this, (void*)value); WritePortStatus(port, value); if (suspended) { /* Suspending. * Sleep for 3ms to ensure nothing goes out on the bus * until devices are suspended. */ IOSleep(3); } else { // Resuming USBLog(5,"AppleUSBUHCI[%p]::RHSuspendPort - resuming port %d, calling out to timer", this, (int)port+1); _rhPortBeingResumed[port] = true; thread_call_enter1(_rhResumePortTimerThread[port], (void*)(port+1)); } USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) calling UIMRootHubStatusChange", this, port+1, suspended ? "SUSPEND" : "RESUME"); UIMRootHubStatusChange(); USBLog(5, "AppleUSBUHCI[%p]::RHSuspendPort %d (%s) DONE", this, port+1, suspended ? "SUSPEND" : "RESUME"); return kIOReturnSuccess; }
void AppleUSBUHCI::RHEnablePort(int port, bool enable) { UInt16 value; // USBLog(5, "AppleUSBUHCI[%p]::RHEnablePort %d %d", this, port, enable); port--; // convert 1-based to 0-based. value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; USBLog(3, "AppleUSBUHCI[%p]::RHEnablePort port: %d enable: %d PortSC: 0x%x", this, port+1, enable, value); USBLog(2, "AppleUSBUHCI[%p]::RHEnablePort (CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p FRNUM:%p, SOFMOD:%p, ConfigCMD:%p)", this, (void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)ioRead32(kUHCI_FRNUM), (void*)ioRead32(kUHCI_SOFMOD), (void*)_device->configRead16(kIOPCIConfigCommand)); if (enable) { value |= kUHCI_PORTSC_PED; } else { value &= ~kUHCI_PORTSC_PED; } WritePortStatus(port, value); }
// Called at software interrupt time void AppleUSBUHCI::HandleInterrupt(void) { UInt16 status; UInt32 intrStatus; bool needReset = false; status = ioRead16(kUHCI_STS); USBTrace_Start( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 0); if (_hostControllerProcessInterrupt & kUHCI_STS_HCPE) { _hostControllerProcessInterrupt = 0; USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller process error", this); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 1 ); needReset = true; } if (_hostSystemErrorInterrupt & kUHCI_STS_HSE) { _hostSystemErrorInterrupt = 0; USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller system error(CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p ConfigCMD:%p)", this,(void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand)); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, ioRead16(kUHCI_CMD), 0, 2 ); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_STS), ioRead16(kUHCI_INTR), ioRead16(kUHCI_PORTSC1), 3 ); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_PORTSC2), ioRead32(kUHCI_FRBASEADDR), _device->configRead16(kIOPCIConfigCommand), 4 ); needReset = true; } if (_resumeDetectInterrupt & kUHCI_STS_RD) { _resumeDetectInterrupt = 0; USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller resume detected - calling EnsureUsability", this); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 6); EnsureUsability(); } if (_usbErrorInterrupt & kUHCI_STS_EI) { _usbErrorInterrupt = 0; USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 7); USBLog(6, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller error interrupt", this); } if (_usbCompletionInterrupt & kUHCI_STS_INT) { _usbCompletionInterrupt = 0; // USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 8); // updates hardware interrupt time from shadow vars that are se in the real irq handler UpdateFrameNumberWithTime(); USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Normal interrupt", this); if (_consumerCount != _producerCount) { USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Isoch was handled", this); } } // this code probably doesn't work if (needReset) { IOSleep(1000); USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Resetting controller due to errors detected at interrupt time (0x%x)", this, status); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, needReset, 5 ); Reset(true); Run(true); } if (_myPowerState == kUSBPowerStateOn) { USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, 0, 9); ProcessCompletedTransactions(); // Check for root hub status change RHCheckStatus(); } else { USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - deferring further processing until we are running again", this); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 10); } USBTrace_End( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 0); }
// Called at hardware interrupt time bool AppleUSBUHCI::FilterInterrupt(void) { UInt16 activeInterrupts; Boolean needSignal = false; UInt64 currentFrame; uint64_t timeStamp; // we leave all interrupts enabled, so see which ones are active activeInterrupts = ioRead16(kUHCI_STS) & kUHCI_STS_INTR_MASK; if (activeInterrupts != 0) { USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt , (uintptr_t)this, activeInterrupts, 0, 3 ); if (activeInterrupts & kUHCI_STS_HCPE) { // Host Controller Process Error - usually a bad data structure on the list _hostControllerProcessInterrupt = kUHCI_STS_HCPE; ioWrite16(kUHCI_STS, kUHCI_STS_HCPE); needSignal = true; //USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HCPE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY)); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostControllerProcessInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 1 ); } if (activeInterrupts & kUHCI_STS_HSE) { // Host System Error - usually a PCI issue _hostSystemErrorInterrupt = kUHCI_STS_HSE; ioWrite16(kUHCI_STS, kUHCI_STS_HSE); needSignal = true; //USBLog(1, "AppleUSBUHCI[%p]::FilterInterrupt - HSE error - legacy reg = %p", this, (void*)_device->configRead16(kUHCI_PCI_LEGKEY)); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostSystemErrorInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 2 ); } if (activeInterrupts & kUHCI_STS_RD) { // Resume Detect - remote wakeup _resumeDetectInterrupt = kUHCI_STS_RD; ioWrite16(kUHCI_STS, kUHCI_STS_RD); needSignal = true; } if (activeInterrupts & kUHCI_STS_EI) { // USB Error Interrupt - transaction error (CRC, timeout, etc) _usbErrorInterrupt = kUHCI_STS_EI; ioWrite16(kUHCI_STS, kUHCI_STS_EI); needSignal = true; } if (activeInterrupts & kUHCI_STS_INT) { // Normal IOC interrupt - we need to check out low latency Isoch as well timeStamp = mach_absolute_time(); ioWrite16(kUHCI_STS, kUHCI_STS_INT); needSignal = true; // This function will give us the current frame number and check for rollover at the same time // since we are calling from filterInterrupts we will not be preempted, it will also update the // cached copy of the frame_number_with_time GetFrameNumberInternal(); // we need to check the periodic list to see if there are any Isoch TDs which need to come off // and potentially have their frame lists updated (for Low Latency) we will place them in reverse // order on a "done queue" which will be looked at by the isoch scavanger // only do this if the periodic schedule is enabled if (!_inAbortIsochEP && (_outSlot < kUHCI_NVFRAMES)) { AppleUHCIIsochTransferDescriptor *cachedHead; UInt32 cachedProducer; UInt16 curSlot, testSlot, nextSlot; curSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK); cachedHead = (AppleUHCIIsochTransferDescriptor*)_savedDoneQueueHead; cachedProducer = _producerCount; testSlot = _outSlot; while (testSlot != curSlot) { IOUSBControllerListElement *thing, *nextThing; AppleUHCIIsochTransferDescriptor *isochTD; nextSlot = (testSlot+1) & kUHCI_NVFRAMES_MASK; thing = _logicalFrameList[testSlot]; while (thing != NULL) { nextThing = thing->_logicalNext; isochTD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, thing); if (!isochTD) break; // only care about Isoch in this list - if we get here we are at the interrupt TDs // need to unlink this TD _logicalFrameList[testSlot] = nextThing; _frameList[testSlot] = HostToUSBLong(thing->GetPhysicalLink()); if (isochTD->_lowLatency) isochTD->frStatus = isochTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp); // place this guy on the backward done queue // the reason that we do not use the _logicalNext link is that the done queue is not a null terminated list // and the element linked "last" in the list might not be a true link - trust me isochTD->_doneQueueLink = cachedHead; cachedHead = isochTD; cachedProducer++; if (isochTD->_pEndpoint) { isochTD->_pEndpoint->onProducerQ++; OSDecrementAtomic( &(isochTD->_pEndpoint->scheduledTDs)); } thing = nextThing; } testSlot = nextSlot; _outSlot = testSlot; } IOSimpleLockLock( _wdhLock ); _savedDoneQueueHead = cachedHead; // updates the shadow head _producerCount = cachedProducer; // Validates _producerCount; IOSimpleLockUnlock( _wdhLock ); } // 8394970: Make sure we set the flag AFTER we have incremented our producer count. _usbCompletionInterrupt = kUHCI_STS_INT; } } // We will return false from this filter routine, // but will indicate that there the action routine should be called // by calling _filterInterruptSource->signalInterrupt(). // This is needed because IOKit will disable interrupts for a level interrupt // after the filter interrupt is run, until the action interrupt is called. // We want to be able to have our filter interrupt routine called // before the action routine runs, if needed. That is what will enable // low latency isoch transfers to work, as when the // system is under heavy load, the action routine can be delayed for tens of ms. // if (needSignal) _interruptSource->signalInterrupt(); return false; }
// // This is similar to the code in GetFrameNumber that is only called at hw irq time. It uses separate vars since it can preempt the // real GetFrameNumber function. It does not use the _frameLock mutex because filterinterrupt cannot be preempted. // UInt64 AppleUSBUHCI::GetFrameNumberInternal(void) { UInt32 lastIrqFrameLow; UInt32 currentIrqFrameLow; UInt64 lastIrqFrameHi; UInt64 currentFrame; // // ** only call this function from FilterInterrupt or if the UHCI interrupts are disabled ** // // This code attempts to record the time of the SOF. According to the UHCI 1.1 spec // the IRQ happens at EOF (end of frame) time but we will treat this like SOF time for our purposes. // // *NOTE: debug log messages are disabled. The debug messages can only be enabled if we are using kprintf or some // logging feature that is safe to call at FilterInterrupt time. // If the controller is halted, then we should just bail out if (ioRead16(kUHCI_STS) & kUHCI_STS_HCH) { if (_myPowerState == kUSBPowerStateOn) { // do not use USBLog from here, since this method can be called in interrupt context // USBLog(1, "AppleUSBUHCI[%p]::GetFrameNumber called but controller is halted", this); USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsGetFrameNumberInternal, (uintptr_t)this, kUHCI_STS_HCH, 0, 0); } return 0; } //USBLog(7, "AppleUSBUHCI[%p]::GetFrameNumberInternal - check frame number", this); // _lastIrqFrame preserves the last 64 bit frame number we recorded lastIrqFrameLow = _lastIrqFrameLow; lastIrqFrameHi = _lastIrqFrame & ~0x7ff; currentIrqFrameLow = ReadFrameNumberRegister(); // check for overflow bit(10) change if (currentIrqFrameLow <= lastIrqFrameLow) { uint64_t tempTime; // 11 bit overflow (bit 10 changed) // bump high part lastIrqFrameHi += 0x800; // // if the frame list rolled over or we don't have a value yet then update our cached copy of frame_with_time // the frame counter is 11 bits wide, bit 10 will change every 1000ms (1 sec). // // note: we may make an extra update if we happen to take an interrupt when the 64 bit value rolls over but // this is once in a blue moon and won't cause a problem. // currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow); _tempAnchorFrame = currentFrame; tempTime = mach_absolute_time(); _tempAnchorTime = *(AbsoluteTime*)&tempTime; } else { currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow); } _lastIrqFrameLow = currentIrqFrameLow; _lastIrqFrame = currentFrame; // USBLog(7, "AppleUSBUHCI[%p]:: GetFrameNumberInternal - frame number is %qx (%qd) %qd .sec", this, currentFrame, currentFrame, currentFrame/1000); return (currentFrame); }