//================================================================================================ // // 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)); }
IOReturn AppleUSBUHCI::RHResumePortCompletion(UInt32 port) { UInt16 value; USBLog(5, "AppleUSBUHCI[%p]::RHResumePortCompletion - finishing resume on port %d", this, (int)port); if (!_rhPortBeingResumed[port-1]) { USBLog(1, "AppleUSBUHCI[%p]::RHResumePortCompletion - port %d does not appear to be resuming!", this, (int)port); USBTrace( kUSBTUHCI, kTPUHCIRHResumePortCompletion, (uintptr_t)this, (int)port, 0, kIOReturnInternalError ); return kIOReturnInternalError; } if (!_controllerAvailable) { USBLog(5, "AppleUSBEHCI[%p]::RHResumePortCompletion - cannot finish resume on port %d because the controller is unavailable", this, (int)port); _rhPortBeingResumed[port-1] = false; return kIOReturnInternalError; } value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK; value &= ~(kUHCI_PORTSC_RD | kUHCI_PORTSC_SUSPEND); USBLog(5, "AppleUSBUHCI[%p]: de-asserting resume signal by writing (%p)", this, (void*)value); WritePortStatus(port-1, value); IOSync(); IOSleep(2); // allow it to kick in _rhPortBeingResumed[port-1] = false; _portSuspendChange[port-1] = true; EnsureUsability(); return kIOReturnSuccess; }
//================================================================================================ // // ResetControllerState // //================================================================================================ // IOReturn AppleUSBOHCI::ResetControllerState(void) { USBTrace( kUSBTOHCI, KTPOHCIResetControllerState, (uintptr_t)this, 0, 0, 0); // Disable All OHCI Interrupts _pOHCIRegisters->hcInterruptDisable = HostToUSBLong(kOHCIHcInterrupt_MIE); IOSync(); // Place the USB bus into the Reset State _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Reset << kOHCIHcControl_HCFSPhase)); IOSync(); // always make sure we stay in reset for at least 50 ms IOSleep(50); // Clear all Processing Registers _pOHCIRegisters->hcHCCA = 0; _pOHCIRegisters->hcControlHeadED = 0; _pOHCIRegisters->hcControlCurrentED = 0; _pOHCIRegisters->hcBulkHeadED = 0; _pOHCIRegisters->hcBulkCurrentED = 0; IOSync(); // turn off the global power OHCIRootHubPower(0 /* kOff */); // go ahead and reset the controller _pOHCIRegisters->hcCommandStatus = HostToUSBLong(kOHCIHcCommandStatus_HCR); // Reset OHCI IOSync(); IOSleep(1); // the spec says 10 microseconds return kIOReturnSuccess; }
//================================================================================================ // // powerStateDidChangeTo // //================================================================================================ // IOReturn AppleUSBUHCI::powerStateDidChangeTo ( IOPMPowerFlags capabilities, unsigned long newState, IOService* whichDevice) { USBTrace( kUSBTUHCI, KTPUHCIPowerState, (uintptr_t)this, newState, 0, 2); USBLog(5, "AppleUSBUHCI[%p]::powerStateDidChangeTo new state (%d)", this, (int)newState); showRegisters(7, "powerStateDidChangeTo"); return super::powerStateDidChangeTo(capabilities, newState, whichDevice); }
//================================================================================================ // // powerChangeDone // //================================================================================================ // void AppleUSBUHCI::powerChangeDone ( unsigned long fromState) { unsigned long newState = getPowerState(); USBTrace( kUSBTUHCI, KTPUHCIPowerState, (uintptr_t)this, fromState, newState, 3); USBLog((fromState == newState) || !_controllerAvailable ? 7 : 5, "AppleUSBUHCI[%p]::powerChangeDone from state (%d) to state (%d) _controllerAvailable(%s)", this, (int)fromState, (int)newState, _controllerAvailable ? "true" : "false"); if (_controllerAvailable) showRegisters(7, "powerChangeDone"); super::powerChangeDone(fromState); }
//================================================================================================ // // 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; }
// Reset and enable the port IOReturn AppleUSBUHCI::RHHoldPortReset(int port) { UInt16 value; int i; USBLog(1, "AppleUSBUHCI[%p]::RHHoldPortReset %d", this, port); USBTrace( kUSBTUHCI, kTPUHCIRHHoldPortReset, (uintptr_t)this, (int)port, 0, 0); port--; // convert 1-based to 0-based. value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value | kUHCI_PORTSC_RESET); return kIOReturnSuccess; }
//================================================================================================ // // RestartControllerFromReset // //================================================================================================ // IOReturn AppleUSBOHCI::RestartControllerFromReset(void) { UInt32 newValue; USBTrace( kUSBTOHCI, KTPOHCIRestartControllerFromReset, (uintptr_t)this, _uimInitialized, 0, 0); USBLog(3, "AppleUSBOHCI[%p]::RestartControllerFromReset - Re-loading UIM if necessary (%d)", this, _uimInitialized ); // first, reinit the op regs InitializeOperationalRegisters(); // Set OHCI to operational state and enable processing of control list. _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase); IOSync(); IOSleep(3); // wait the required 3 ms before turning on the lists // <rdar://problem/5981624> We need to make sure that the DRWE bit is properly set any time we go to the operational state newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); if (!(newValue & kOHCIHcRhStatus_DRWE)) { _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 count = 0; newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); // this bit SHOULD now be set while ((count++ < 10) && !(newValue & kOHCIHcRhStatus_DRWE)) { USBError(1, "OHCI driver::RestartControllerFromReset - DRWE bit not sticking. Retrying."); _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); } } } _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); OHCIRootHubPower(1 /* kOn */); _myBusState = kUSBBusStateRunning; return kIOReturnSuccess; }
//================================================================================================ // // EnableInterruptsFromController // //================================================================================================ // IOReturn AppleUSBOHCI::EnableInterruptsFromController(bool enable) { USBTrace( kUSBTOHCI, KTPOHCIEnableInterrupts, (uintptr_t)this, enable, 0, 0); if (enable) { USBLog(2, "AppleUSBOHCI[%p]::EnableInterruptsFromController - enabling interrupts 0x%x", this, (kOHCIHcInterrupt_MIE | kOHCIDefaultInterrupts)); _pOHCIRegisters->hcInterruptEnable = HostToUSBLong (kOHCIHcInterrupt_MIE | kOHCIDefaultInterrupts); IOSync(); } else { _pOHCIRegisters->hcInterruptDisable = HostToUSBLong (kOHCIHcInterrupt_MIE); // disable interrupts during D3 state IOSync(); USBLog(2, "AppleUSBOHCI[%p]::EnableInterruptsFromController - interrupts disabled", this); } return kIOReturnSuccess; }
//================================================================================================ // // 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; }
//================================================================================================ // // WakeControllerFromDoze // //================================================================================================ // IOReturn AppleUSBOHCI::WakeControllerFromDoze(void) { USBTrace( kUSBTOHCI, KTPOHCIWakeControllerFromDoze, (uintptr_t)this, 0, 0, 0); ResumeUSBBus(false); if ( _rootHubStatuschangedInterruptReceived ) { _rootHubStatuschangedInterruptReceived = false; USBLog(6, "AppleUSBOHCI[%p]::WakeControllerFromDoze - we had received a RHSC interrupt, so waiting 21ms before proceeding", this); // Wait for 20 + 1 ms for the OHCI controller to set the change bit in the root hub change register IOSleep(21); } else { USBLog(6, "AppleUSBOHCI[%p]::WakeControllerFromDoze - not from a RHSC interrupt", this); } 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; }
//================================================================================================ // // DozeController // //================================================================================================ // IOReturn AppleUSBOHCI::DozeController(void) { USBTrace( kUSBTOHCI, KTPOHCIDozeController, (uintptr_t)this, 0, 0, 0); // Check to make sure that our RHSC is enabled if ( !(USBToHostLong(_pOHCIRegisters->hcInterruptEnable) & kOHCIHcInterrupt_RHSC) ) { UInt32 interrupts; // Re-enabling the RHSC interrupt, since this seems to be a spurious interrupt USBLog(1, "AppleUSBOHCI[%p]::DozeController - RHSC is disabled. Enabling it", this); interrupts = USBToHostLong(_pOHCIRegisters->hcInterruptEnable); interrupts |= kOHCIHcInterrupt_RHSC; _pOHCIRegisters->hcInterruptEnable = HostToUSBLong(interrupts); IOSync(); } SuspendUSBBus(false); 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; }
// 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); }
IOReturn IOUSBController::CheckForDisjointDescriptor(IOUSBCommand *command, UInt16 maxPacketSize) { IOMemoryDescriptor *buf = command->GetBuffer(); IOBufferMemoryDescriptor *newBuf = NULL; IOByteCount length = command->GetReqCount(); IODMACommand *dmaCommand = command->GetDMACommand(); IOByteCount segLength = 0; IOByteCount offset = 0; IOReturn err; UInt64 offset64; IODMACommand::Segment64 segment64; UInt32 numSegments; // USBTrace_Start( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this ); // Zero length buffers are valid, but they are surely not disjoint, so just return success. // if ( length == 0 ) return kIOReturnSuccess; if (!dmaCommand) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - no dmaCommand", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument, 0, 1 ); return kIOReturnBadArgument; } if (dmaCommand->getMemoryDescriptor() != buf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - mismatched memory descriptor (%p) and dmaCommand memory descriptor (%p)", getName(), this, buf, dmaCommand->getMemoryDescriptor()); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, kIOReturnBadArgument, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 ); return kIOReturnBadArgument; } while (length) { offset64 = offset; numSegments = 1; err = dmaCommand->gen64IOVMSegments(&offset64, &segment64, &numSegments); if (err || (numSegments != 1)) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err (%p) trying to generate segments at offset (%qd), length (%d), segLength (%d), total length (%d), buf (%p), numSegments (%d)", getName(), this, (void*)err, offset64, (int)length, (int)segLength, (int)command->GetReqCount(), buf, (int)numSegments); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, offset64, length, segLength, 3 ); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, segLength, command->GetReqCount(), numSegments, 4 ); return kIOReturnBadArgument; } // 3036056 since length might be less than the length of the descriptor, we are OK if the physical // segment is longer than we need if (segment64.fLength >= length) return kIOReturnSuccess; // this is the last segment, so we are OK // since length is a 32 bit quantity, then we know from the above statement that if we are here we are 32 bit only segLength = (IOByteCount)segment64.fLength; // so the segment is less than the rest of the length - we need to check against maxPacketSize if (segLength % maxPacketSize) { // this is the error case. I need to copy the descriptor to a new descriptor and remember that I did it USBLog(6, "%s[%p]::CheckForDisjointDescriptor - found a disjoint segment of length (%d) MPS (%d)", getName(), this, (int)segLength, maxPacketSize); length = command->GetReqCount(); // we will not return to the while loop, so don't worry about changing the value of length // allocate a new descriptor which is the same total length as the old one newBuf = IOBufferMemoryDescriptor::withOptions((command->GetDirection() == kUSBIn) ? kIODirectionIn : kIODirectionOut, length); if (!newBuf) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - could not allocate new buffer", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnNoMemory, 0, 5 ); return kIOReturnNoMemory; } USBLog(7, "%s[%p]::CheckForDisjointDescriptor, obtained buffer %p of length %d", getName(), this, newBuf, (int)length); // first close out (and complete) the original dma command descriptor USBLog(7, "%s[%p]::CheckForDisjointDescriptor, clearing memDec (%p) from dmaCommand (%p)", getName(), this, dmaCommand->getMemoryDescriptor(), dmaCommand); dmaCommand->clearMemoryDescriptor(); // copy the bytes to the buffer if necessary if (command->GetDirection() == kUSBOut) { USBLog(7, "%s[%p]::CheckForDisjointDescriptor, copying %d bytes from desc %p to buffer %p", getName(), this, (int)length, buf, newBuf->getBytesNoCopy()); if (buf->readBytes(0, newBuf->getBytesNoCopy(), length) != length) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - bad copy on a write", getName(), this); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, 0, 0, 6 ); newBuf->release(); return kIOReturnNoMemory; } } err = newBuf->prepare(); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in prepare", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 7 ); newBuf->release(); return err; } err = dmaCommand->setMemoryDescriptor(newBuf); if (err) { USBLog(1, "%s[%p]::CheckForDisjointDescriptor - err 0x%x in setMemoryDescriptor", getName(), this, err); USBTrace( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, err, 0, 8 ); newBuf->complete(); newBuf->release(); return err; } command->SetOrigBuffer(command->GetBuffer()); command->SetDisjointCompletion(command->GetClientCompletion()); USBLog(7, "%s[%p]::CheckForDisjointDescriptor - changing buffer from (%p) to (%p) and putting new buffer in dmaCommand (%p)", getName(), this, command->GetBuffer(), newBuf, dmaCommand); command->SetBuffer(newBuf); IOUSBCompletion completion; completion.target = this; completion.action = (IOUSBCompletionAction)DisjointCompletion; completion.parameter = command; command->SetClientCompletion(completion); command->SetDblBufLength(length); // for the IOFree - the other buffer may change size return kIOReturnSuccess; } length -= segLength; // adjust our master length pointer offset += segLength; } USBLog(5, "%s[%p]::CheckForDisjointDescriptor - returning kIOReturnBadArgument(0x%x)", getName(), this, kIOReturnBadArgument); // USBTrace_End( kUSBTController, kTPControllerCheckForDisjointDescriptor, (uintptr_t)this, kIOReturnBadArgument); return kIOReturnBadArgument; }
IOReturn IOUSBController::Write(IOMemoryDescriptor *buffer, USBDeviceAddress address, Endpoint *endpoint, IOUSBCompletion *completion, UInt32 noDataTimeout, UInt32 completionTimeout, IOByteCount reqCount) { IOReturn err = kIOReturnSuccess; IOUSBCommand * command = NULL; IODMACommand * dmaCommand = NULL; IOUSBCompletion nullCompletion; int i; bool isSyncTransfer = false; USBLog(7, "%s[%p]::Write - reqCount = %qd", getName(), this, (uint64_t)reqCount); // Validate its a outty pipe and that we have a buffer if ((endpoint->direction != kUSBOut) || !buffer || (buffer->getLength() < reqCount)) { USBLog(5, "%s[%p]::Write - direction is not kUSBOut (%d), No Buffer, or buffer length < reqCount (%qd < %qd). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, (uint64_t)buffer->getLength(), (uint64_t)reqCount, kIOReturnBadArgument); return kIOReturnBadArgument; } if ((endpoint->transferType != kUSBBulk) && (noDataTimeout || completionTimeout)) { USBLog(5, "%s[%p]::Write - Pipe is NOT kUSBBulk (%d) AND specified a timeout (%d, %d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->transferType, (uint32_t)noDataTimeout, (uint32_t)completionTimeout, kIOReturnBadArgument); return kIOReturnBadArgument; // timeouts only on bulk pipes } // Validate the command gate if (!_commandGate) { USBLog(5, "%s[%p]::Write - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError); return kIOReturnInternalError; } if ( (uintptr_t) completion->action == (uintptr_t) &IOUSBSyncCompletion ) { isSyncTransfer = true; // 7889995 - check to see if we are on the workloop thread before setting up the IOUSBCommand if ( _workLoop->onThread() ) { USBError(1,"IOUSBController(%s)[%p]::Write sync request on workloop thread. Use async!", getName(), this); return kIOUSBSyncRequestOnWLThread; } } // allocate the command command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false); // If we couldn't get a command, increase the allocation and try again // if ( command == NULL ) { IncreaseCommandPool(); command = (IOUSBCommand *)_freeUSBCommandPool->getCommand(false); if ( command == NULL ) { USBLog(3,"%s[%p]::Write Could not get a IOUSBCommand",getName(),this); return kIOReturnNoResources; } } // 7455477: from this point forward, we have the command object, and we need to be careful to put it back if there is an error.. if (reqCount) { IOMemoryDescriptor *memDesc; dmaCommand = command->GetDMACommand(); if (!dmaCommand) { USBLog(1, "%s[%p]::Write - no DMA COMMAND", getName(), this); USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, kIOReturnNoResources, 0, 1 ); err = kIOReturnNoResources; } else { memDesc = (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor(); if (memDesc) { USBLog(1, "%s[%p]::Write - dmaCommand (%p) already contains memory descriptor (%p) - clearing", getName(), this, dmaCommand, memDesc); USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, (uintptr_t)dmaCommand, (uintptr_t)memDesc, 2 ); dmaCommand->clearMemoryDescriptor(); } USBLog(7, "%s[%p]::Write - setting memory descriptor (%p) into dmaCommand (%p)", getName(), this, buffer, dmaCommand); err = dmaCommand->setMemoryDescriptor(buffer); if (err) { USBTrace( kUSBTController, kTPControllerWrite, (uintptr_t)this, err, 0, 4 ); USBLog(1, "%s[%p]::Write - err(%p) attempting to set the memory descriptor to the dmaCommand", getName(), this, (void*)err); } } } if (!err) { command->SetIsSyncTransfer(isSyncTransfer); command->SetUseTimeStamp(false); command->SetSelector(WRITE); command->SetRequest(0); // Not a device request command->SetAddress(address); command->SetEndpoint(endpoint->number); #ifdef SUPPORTS_SS_USB command->SetStreamID(0); #endif command->SetDirection(kUSBOut); command->SetType(endpoint->transferType); command->SetBuffer(buffer); command->SetReqCount(reqCount); command->SetClientCompletion(*completion); command->SetNoDataTimeout(noDataTimeout); command->SetCompletionTimeout(completionTimeout); command->SetMultiTransferTransaction(false); command->SetFinalTransferInTransaction(false); for (i=0; i < 10; i++) command->SetUIMScratch(i, 0); nullCompletion.target = (void *) NULL; nullCompletion.action = (IOUSBCompletionAction) NULL; nullCompletion.parameter = (void *) NULL; command->SetDisjointCompletion(nullCompletion); err = CheckForDisjointDescriptor(command, endpoint->maxPacketSize); if (!err) { err = _commandGate->runAction(DoIOTransfer, command); } } // 7455477: handle and and all errors which may have occured above // If we have a sync request, then we always return the command after the DoIOTransfer. If it's an async request, we only return it if // we get an immediate error // if ( isSyncTransfer || (kIOReturnSuccess != err) ) { IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL; if (!isSyncTransfer) { USBLog(2, "%s[%p]::Write - General error (%p) - cleaning up - command(%p) dmaCommand(%p)", getName(), this, (void*)err, command, dmaCommand); } if (memDesc) { USBLog(7, "%s[%p]::Write - General error (%p) - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, (void*)err, memDesc, dmaCommand); dmaCommand->clearMemoryDescriptor(); } nullCompletion = command->GetDisjointCompletion(); if (nullCompletion.action) { USBLog(2, "%s[%p]::Write - SYNC xfer or immediate error with Disjoint Completion", getName(), this); } _freeUSBCommandPool->returnCommand(command); } return err; }
//================================================================================================ // // SuspendUSBBus // //================================================================================================ // void AppleUSBOHCI::SuspendUSBBus(bool goingToSleep) { UInt32 something; UInt32 hcControl; USBTrace( kUSBTOHCI, KTPOHCISuspendUSBBus, (uintptr_t)this, goingToSleep, 0, 0); USBLog(5,"AppleUSBOHCI[%p]::SuspendUSBBus goingToSleep = %s", this, goingToSleep ? "TRUE" : "FALSE"); // 1st turn off all list processing // hcControl = USBToHostLong(_pOHCIRegisters->hcControl); hcControl &= ~(kOHCIHcControl_CLE | kOHCIHcControl_BLE | kOHCIHcControl_PLE | kOHCIHcControl_IE); _pOHCIRegisters->hcControl = HostToUSBLong(hcControl); // We used to wait for a SOF interrupt here. Now just sleep for 1 ms. // IOSleep(1); // check for the WDH register to see if we need to process is [2405732] // if ( _writeDoneHeadInterrupt ) { USBError(1,"AppleUSBOHCI[%p]::SuspendUSBBus Processing WDH before suspending", this); PollInterrupts(); } if ( goingToSleep ) { // now tell the controller to put the bus into suspend mode if (_errataBits & kErrataOHCINoGlobalSuspendOnSleep) { UInt32 port; hcControl = kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase; for (port=0; port < _rootHubNumPorts; port++) { _savedHcRhPortStatus[port] = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); USBLog(5, "AppleUSBOHCI[%p]::SuspendUSBBus - port %d _savedHcRhPortStatus(%p)", this, (int)port+1, (void*)_savedHcRhPortStatus[port]); } } else { hcControl = kOHCIFunctionalState_Suspend << kOHCIHcControl_HCFSPhase; } if (_hasPCIPwrMgmt) hcControl |= kOHCIHcControl_RWC | kOHCIHcControl_RWE; _pOHCIRegisters->hcControl = HostToUSBLong(hcControl); IOSleep(3); // wait 3 milliseconds for things to settle } else { UInt32 port; for (port=0; port < _rootHubNumPorts; port++) { USBLog(7, "AppleUSBOHCI[%p]::SuspendUSBBus - hcRhPortStatus[%d] = %p", this, (int)port+1, (void*) USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port])); } } }
IOReturn IOUSBController::IsocIO(IOMemoryDescriptor * buffer, UInt64 frameStart, UInt32 numFrames, IOUSBLowLatencyIsocFrame * frameList, USBDeviceAddress address, Endpoint * endpoint, IOUSBLowLatencyIsocCompletion * completion, UInt32 updateFrequency) { IOReturn err = kIOReturnSuccess; IOUSBIsocCommand * command = NULL; bool crossEndianRequest = false; IODMACommand * dmaCommand = NULL; bool syncTransfer = false; // Validate the completion // USBLog(7, "%s[%p]::IsocIO(LL)", getName(), this); if (completion == 0) { USBLog(1, "%s[%p]::IsocIO(LL) - No completion. Returning kIOReturnNoCompletion(0x%x)", getName(), this, kIOReturnNoCompletion); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoCompletion, 0, 3 ); return kIOReturnNoCompletion; } // Validate the commandGate // if (_commandGate == 0) { USBLog(1, "%s[%p]::IsocIO(LL) - Could not get _commandGate. Returning kIOReturnInternalError(0x%x)", getName(), this, kIOReturnInternalError); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnInternalError, 0, 4 ); return kIOReturnInternalError; } // If the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client if ( endpoint->direction & 0x80 ) { endpoint->direction &= ~0x80; crossEndianRequest = true; } // Validate the direction of the endpoint -- it has to be kUSBIn or kUSBOut if ( (endpoint->direction != kUSBOut) && ( endpoint->direction != kUSBIn) ) { USBLog(1, "%s[%p]::IsocIO(LL) - Direction is not kUSBOut or kUSBIn (%d). Returning kIOReturnBadArgument(0x%x)", getName(), this, endpoint->direction, kIOReturnBadArgument); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, endpoint->direction, kIOReturnBadArgument, 6 ); return kIOReturnBadArgument; } if ( (uintptr_t)completion->action == (uintptr_t)&IOUSBSyncIsoCompletion ) { syncTransfer = true; if ( _workLoop->onThread() ) { USBError(1,"IOUSBController(%s)[%p]::DoIsocTransfer sync request on workloop thread. Use async!", getName(), this); return kIOUSBSyncRequestOnWLThread; } } command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false); // If we couldn't get a command, increase the allocation and try again // if ( command == NULL ) { IncreaseIsocCommandPool(); command = (IOUSBIsocCommand *)_freeUSBIsocCommandPool->getCommand(false); if ( command == NULL ) { USBLog(1, "%s[%p]::IsocIO(LL) Could not get a IOUSBIsocCommand", getName(), this); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 5 ); return kIOReturnNoResources; } } dmaCommand = command->GetDMACommand(); if (!dmaCommand) { USBLog(1, "%s[%p]::IsocIO(LL) no IODMACommand in the IOUSBCommand", getName(), this); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, kIOReturnNoResources, 0, 1 ); return kIOReturnNoResources; } USBLog(7, "%s[%p]::IsocIO(LL) - putting buffer %p into dmaCommand %p which has getMemoryDescriptor %p", getName(), this, buffer, command->GetDMACommand(), command->GetDMACommand()->getMemoryDescriptor()); err = dmaCommand->setMemoryDescriptor(buffer); // this automatically calls prepare() if (err) { USBLog(1, "%s[%p]::IsocIO(LL) - dmaCommand[%p]->setMemoryDescriptor(%p) failed with status (%p)", getName(), this, command->GetDMACommand(), buffer, (void*)err); USBTrace( kUSBTController, kTPIsocIOLL, (uintptr_t)this, err, 0, 2 ); _freeUSBIsocCommandPool->returnCommand(command); return err; } // If the high order bit of the endpoint transfer type is set, then this means it's a request from an Rosetta client command->SetRosettaClient(crossEndianRequest); command->SetIsSyncTransfer(syncTransfer); // Setup the direction if (endpoint->direction == kUSBOut) { command->SetSelector(WRITE); command->SetDirection(kUSBOut); } else if (endpoint->direction == kUSBIn) { command->SetSelector(READ); command->SetDirection(kUSBIn); } command->SetUseTimeStamp(false); command->SetAddress(address); command->SetEndpoint(endpoint->number); command->SetBuffer(buffer); command->SetCompletion( * ((IOUSBIsocCompletion *) completion) ); command->SetStartFrame(frameStart); command->SetNumFrames(numFrames); command->SetFrameList( (IOUSBIsocFrame *) frameList); command->SetStatus(kIOReturnBadArgument); command->SetUpdateFrequency(updateFrequency); command->SetLowLatency(true); err = _commandGate->runAction(DoIsocTransfer, command); // If we have a sync request, then we always return the command after the DoIsocTransfer. If it's an async request, we only return it if // we get an immediate error // if ( syncTransfer || (kIOReturnSuccess != err) ) { IODMACommand *dmaCommand = command->GetDMACommand(); IOMemoryDescriptor *memDesc = dmaCommand ? (IOMemoryDescriptor *)dmaCommand->getMemoryDescriptor() : NULL; if (memDesc) { USBLog(7, "%s[%p]::IsocIO(LL) - sync xfer or err return - clearing memory descriptor (%p) from dmaCommand (%p)", getName(), this, memDesc, dmaCommand); dmaCommand->clearMemoryDescriptor(); } _freeUSBIsocCommandPool->returnCommand(command); } return err; }
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::UIMRootHubStatusChange(void) { UInt8 bitmap, bit; unsigned int i, index, move; IOUSBHubPortStatus portStatus; USBLog(7, "AppleUSBUHCI[%p]::UIMRootHubStatusChange (_controllerAvailable: %d)", this, _controllerAvailable); if (_controllerAvailable && !_wakingFromHibernation) { // For UHCI, we first need to see if we have a pending resume RHCheckStatus(); // Assume a byte can hold all port bits. assert(kUHCI_NUM_PORTS < 8); /* * Encode the status change bitmap. The format of the bitmap: * bit0 = hub status changed * bit1 = port 1 status changed * bit2 = port 2 status changed * ... * See USB 1.0 spec section 11.8.3 for more info. */ bitmap = 0; bit = 0x2; for (i=1; i <= kUHCI_NUM_PORTS; i++) { GetRootHubPortStatus(&portStatus, i); if (portStatus.changeFlags != 0) { UInt64 elapsedTime; uint64_t currentTime; USBLog(5, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Port %d hub flags:", this, i); RHDumpHubPortStatus(&portStatus); bitmap |= bit; // If this port has seen a recovery attempt (see below) already, check to see what the current time is and if it's > than 2 seconds since the port recovery, then 'forget" about it currentTime = mach_absolute_time(); SUB_ABSOLUTETIME(¤tTime, &_portRecoveryTime[i-1] ); absolutetime_to_nanoseconds(*(AbsoluteTime *)¤tTime, &elapsedTime); elapsedTime /= 1000000000; // Convert to seconds from nanoseconds if ( _previousPortRecoveryAttempted[i-1] && (elapsedTime >= kUHCITimeoutForPortRecovery) ) { USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Forgetting about our portRecovery state since the last change occurred %qd seconds ago", this, elapsedTime); _previousPortRecoveryAttempted[i-1] = false; } // If this port has a PED (port enable change) AND the current status is PortPower and Port Connection (which indicates that a condition // on the bus caused the controller to disable the port) then we need to see if we should attempt to re-enable the port w/out calling the // hub driver. We will do this ONLY if the previous root hub status change for this port did NOT attempt this recovery -- we only try once if ( !_previousPortRecoveryAttempted[i-1] ) { USBLog(7, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Port %d had a change: 0x%x", this, i, portStatus.changeFlags); if ( !(portStatus.statusFlags & kHubPortEnabled) // if we are not presently enabled && (portStatus.changeFlags & kHubPortEnabled) // and we were previously enabled && (portStatus.statusFlags & kHubPortConnection) // and we are presently connected && !(portStatus.changeFlags & kHubPortConnection) // and the connection has not recently changed (i.e. quick disconnect-connect) && (portStatus.statusFlags & kHubPortPower) ) // and the power is on { // Indicate that we are attempting a recovery _previousPortRecoveryAttempted[i-1] = true; currentTime = mach_absolute_time(); _portRecoveryTime[i-1] = *(AbsoluteTime*)¤tTime; USBLog(1, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Port %d attempting to enable a disabled port to work around a fickle UHCI controller", this, i); USBTrace( kUSBTUHCI, kTPUHCIRootHubStatusChange, (uintptr_t)this, portStatus.statusFlags, portStatus.changeFlags, i ); RHEnablePort(i, true); // Clear the bitmap bitmap &= ~bit; } } else { // If this is just the notification that the port has been enabled, then don't reset our previousPortRecoveryAttempt if ( (portStatus.changeFlags & kHubPortEnabled) and (portStatus.statusFlags & kHubPortConnection) and (portStatus.statusFlags & kHubPortPower) and (portStatus.statusFlags & kHubPortEnabled) ) { USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Port %d had a change but it's just the port enabled notification", this, i); } else { USBLog(2, "AppleUSBUHCI[%p]::UIMRootHubStatusChange Port %d had a change but last time we attempted a recovery, so not attempting again", this, i); _previousPortRecoveryAttempted[i-1] = false; } } } bit <<= 1; // Don't clear status bits until explicitly told to. } if (bitmap) { USBLog(5, "AppleUSBUHCI[%p]::UIMRootHubStatusChange RH status bitmap = %x", this, bitmap); } _rootHubStatusChangedBitmap = bitmap; } // Bitmap is only one byte, so it doesn't need swapping. }
static void DisjointCompletion(IOUSBController *me, IOUSBCommand *command, IOReturn status, UInt32 bufferSizeRemaining) { IOBufferMemoryDescriptor *buf = NULL; IODMACommand *dmaCommand = NULL; USBTrace_Start( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command, status, bufferSizeRemaining ); if (!me || !command) { USBError(1, "DisjointCompletion sanity check failed - me(%p) command (%p)", me, command); return; } buf = OSDynamicCast(IOBufferMemoryDescriptor, command->GetBuffer()); dmaCommand = command->GetDMACommand(); if (!dmaCommand || !buf) { USBLog(1, "%s[%p]::DisjointCompletion - no dmaCommand, or buf(%p) is not an IOBMD", me->getName(), me, command->GetBuffer()); USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)command->GetBuffer(), 0, 1 ); return; } if (dmaCommand->getMemoryDescriptor()) { if (dmaCommand->getMemoryDescriptor() != buf) { USBLog(1, "%s[%p]::DisjointCompletion - buf(%p) doesn't match getMemoryDescriptor(%p)", me->getName(), me, buf, dmaCommand->getMemoryDescriptor()); USBTrace( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)me, (uintptr_t)buf, (uintptr_t)dmaCommand->getMemoryDescriptor(), 2 ); } // need to complete the dma command USBLog(6, "%s[%p]::DisjointCompletion - clearing memory descriptor (%p) from dmaCommand (%p)", me->getName(), me, dmaCommand->getMemoryDescriptor(), dmaCommand); dmaCommand->clearMemoryDescriptor(); } if (command->GetDirection() == kUSBIn) { USBLog(5, "%s[%p]::DisjointCompletion, copying %d out of %d bytes to desc %p from buffer %p", me->getName(), me, (int)(command->GetDblBufLength()-bufferSizeRemaining), (int)command->GetDblBufLength(), command->GetOrigBuffer(), buf); command->GetOrigBuffer()->writeBytes(0, buf->getBytesNoCopy(), (command->GetDblBufLength()-bufferSizeRemaining)); } buf->complete(); buf->release(); // done with this buffer command->SetBuffer(NULL); // now call through to the original completion routine IOUSBCompletion completion = command->GetDisjointCompletion(); if ( !command->GetIsSyncTransfer() ) { // Free our command now that we have the completion and we are not going to use it anymore me->ReturnUSBCommand(command); } if (completion.action) { USBLog(status == kIOReturnSuccess ? 7 : 3, "%s[%p]::DisjointCompletion calling through to %p - status 0x%x!", me->getName(), me, completion.action, (uint32_t)status); (*completion.action)(completion.target, completion.parameter, status, bufferSizeRemaining); } USBTrace_End( kUSBTController, kTPControllerDisjointCompletion, (uintptr_t)completion.target, (uintptr_t)completion.parameter, status, bufferSizeRemaining); }
// // 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); }
// 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; }
//================================================================================================ // // 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 AppleUHCIIsochTransferDescriptor::UpdateFrameList(AbsoluteTime timeStamp) { UInt32 statFlags; IOUSBIsocFrame *pFrames; IOUSBLowLatencyIsocFrame *pLLFrames; IOReturn frStatus = kIOReturnSuccess; UInt16 frActualCount = 0; UInt16 frReqCount; statFlags = USBToHostLong(GetSharedLogical()->ctrlStatus); frActualCount = UHCI_TD_GET_ACTLEN(statFlags); // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList statFlags (%x)", this, statFlags); pFrames = _pFrames; if (!pFrames) // this will be the case for the dummy TD return kIOReturnSuccess; pLLFrames = (IOUSBLowLatencyIsocFrame*)_pFrames; if (_lowLatency) { frReqCount = pLLFrames[_frameIndex].frReqCount; } else { frReqCount = pFrames[_frameIndex].frReqCount; } if (statFlags & kUHCI_TD_ACTIVE) { frStatus = kIOUSBNotSent2Err; } else if (statFlags & kUHCI_TD_CRCTO) { frStatus = kIOReturnNotResponding; } else if (statFlags & kUHCI_TD_DBUF) // data buffer (PCI error) { if (_pEndpoint->direction == kUSBOut) frStatus = kIOUSBBufferUnderrunErr; else frStatus = kIOUSBBufferOverrunErr; } else if (statFlags & kUHCI_TD_BABBLE) { if (_pEndpoint->direction == kUSBOut) frStatus = kIOReturnNotResponding; // babble on OUT. this should never happen else frStatus = kIOReturnOverrun; } else if (statFlags & kUHCI_TD_STALLED) // if STALL happens on Isoch, it is most likely covered by one of the other bits above { frStatus = kIOUSBWrongPIDErr; } else { if (frActualCount != frReqCount) { if (_pEndpoint->direction == kUSBOut) { // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList - (OUT) reqCount (%d) actCount (%d)", this, frReqCount, frActualCount); frStatus = kIOUSBBufferUnderrunErr; // this better have generated a DBUF or other error } else if (_pEndpoint->direction == kUSBIn) { // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList - (IN) reqCount (%d) actCount (%d)", this, frReqCount, frActualCount); frStatus = kIOReturnUnderrun; // benign error } } } if (alignBuffer && alignBuffer->userBuffer && alignBuffer->vaddr && (_pEndpoint->direction == kUSBIn)) { // i can't log in here because this is called at interrupt time // i know that this is OK for Low Latency because the buffer will be allocated in low memory and wont' be bounced alignBuffer->userBuffer->writeBytes(alignBuffer->userOffset, (void*)alignBuffer->vaddr, frActualCount); alignBuffer->actCount = frActualCount; } if (_lowLatency) { if ( _requestFromRosettaClient ) { pLLFrames[_frameIndex].frActCount = OSSwapInt16(frActualCount); pLLFrames[_frameIndex].frReqCount = OSSwapInt16(pLLFrames[_frameIndex].frReqCount); AbsoluteTime_to_scalar(&pLLFrames[_frameIndex].frTimeStamp) = OSSwapInt64(AbsoluteTime_to_scalar(&timeStamp)); pLLFrames[_frameIndex].frStatus = OSSwapInt32(frStatus); } else { pLLFrames[_frameIndex].frActCount = frActualCount; pLLFrames[_frameIndex].frTimeStamp = timeStamp; pLLFrames[_frameIndex].frStatus = frStatus; #ifdef __LP64__ USBTrace( kUSBTUHCIInterrupts, kTPUHCIUpdateFrameList , (uintptr_t)((_pEndpoint->direction << 24) | ( _pEndpoint->functionAddress << 8) | _pEndpoint->endpointNumber), (uintptr_t)&pLLFrames[_frameIndex], (uintptr_t)frActualCount, (uintptr_t)timeStamp ); #else USBTrace( kUSBTUHCIInterrupts, kTPUHCIUpdateFrameList , (uintptr_t)((_pEndpoint->direction << 24) | ( _pEndpoint->functionAddress << 8) | _pEndpoint->endpointNumber), (uintptr_t)&pLLFrames[_frameIndex], (uintptr_t)(timeStamp.hi), (uintptr_t)timeStamp.lo ); #endif } } else { if ( _requestFromRosettaClient ) { pFrames[_frameIndex].frActCount = OSSwapInt16(frActualCount); pFrames[_frameIndex].frReqCount = OSSwapInt16(pFrames[_frameIndex].frReqCount); pFrames[_frameIndex].frStatus = OSSwapInt32(frStatus); } else { pFrames[_frameIndex].frActCount = frActualCount; pFrames[_frameIndex].frStatus = frStatus; } } if (frStatus != kIOReturnSuccess) { if (frStatus != kIOReturnUnderrun) { _pEndpoint->accumulatedStatus = frStatus; } else if (_pEndpoint->accumulatedStatus == kIOReturnSuccess) { _pEndpoint->accumulatedStatus = kIOReturnUnderrun; } } return frStatus; }
//================================================================================================ // // ResumeUSBBus // //================================================================================================ // void AppleUSBOHCI::ResumeUSBBus(bool wakingFromSleep) { UInt32 newValue; USBTrace( kUSBTOHCI, KTPOHCIResumeUSBBus, (uintptr_t)this, wakingFromSleep, 0, 0); USBLog(5,"AppleUSBOHCI[%p]::ResumeUSBBus wakingFromSleep = %s", this, wakingFromSleep ? "TRUE" : "FALSE" ); switch ((USBToHostLong(_pOHCIRegisters->hcControl) & kOHCIHcControl_HCFS) >> kOHCIHcControl_HCFSPhase ) { case kOHCIFunctionalState_Suspend: // Place the USB bus into the resume State USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Resuming bus from Suspend state", this); _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Resume << kOHCIHcControl_HCFSPhase); // intentional fall through case kOHCIFunctionalState_Resume: // Complete the resume by waiting for the required delay if (_errataBits & kErrataLucentSuspendResume) // JRH 08-27-99 // this is a very simple yet clever hack for working around a bug in the Lucent controller // By using 35 instead of 20, we overflow an internal 5 bit counter by exactly 3ms, which // stops an errant 3ms suspend from appearing on the bus { USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus- Delaying 35 milliseconds in resume state", this); IOSleep(35); } else { USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Delaying 20 milliseconds in resume state", this); IOSleep(20); } // intentional fall through case kOHCIFunctionalState_Reset: // Place the USB bus into the operational State USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - Changing bus to operational", this); _pOHCIRegisters->hcControl = HostToUSBLong(kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase); IOSync(); IOSleep(3); // wait the required 3 ms before turning on the lists // <rdar://problem/5981624> We need to make sure that the DRWE bit is properly set any time we go to the operational state newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); if (!(newValue & kOHCIHcRhStatus_DRWE)) { _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); if (_errataBits & kErrataNECIncompleteWrite) { UInt32 count = 0; newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); // this bit SHOULD now be set while ((count++ < 10) && !(newValue & kOHCIHcRhStatus_DRWE)) { USBError(1, "OHCI driver::ResumeUSBBus - DRWE bit not sticking. Retrying."); _pOHCIRegisters->hcRhStatus = HostToUSBLong(kOHCIHcRhStatus_OCIC | kOHCIHcRhStatus_DRWE); IOSync(); newValue = USBToHostLong(_pOHCIRegisters->hcRhStatus); } } } _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); break; default: USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus Bus already operational - turning on the lists", this); _pOHCIRegisters->hcControl = HostToUSBLong((kOHCIFunctionalState_Operational << kOHCIHcControl_HCFSPhase) | kOHCIHcControl_CLE | (_OptiOn ? kOHCIHcControl_Zero : kOHCIHcControl_BLE) | kOHCIHcControl_PLE | kOHCIHcControl_IE); IOSync(); break; } // Do this after waking the controller so you see wakeups. if (wakingFromSleep) { UInt32 port, portSC; IOSleep(1); for (port=0; port < _rootHubNumPorts; port++) { UInt32 portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); //USBLog(6, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d, portSC(%p)", this, (int)port+1, (void*)portSC); if (portSC & kOHCIHcRhPortStatus_CSC) { if (portSC & kOHCIHcRhPortStatus_PES) { USBError(1, "USB (OHCI):Port %d on bus 0x%x has connect status change but is still enabled. setting clear port enable. hcRhPortStatus(%p)", (int)port+1, (uint32_t)_busNumber, (void*)portSC); _pOHCIRegisters->hcRhPortStatus[port] = HostToUSBLong(kOHCIHcRhPortStatus_CCS); // CCS when writing is CPE IOSleep(1); portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); } else { USBLog(5, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d on bus 0x%x connected or disconnected. portSC(%p)", this, (int)port+1, (uint32_t)_busNumber, (void*)portSC); // IOLog("USB (OHCI):Port %d on bus 0x%x connected or disconnected. portSC(%p)\n", (int)port+1, (uint32_t)_busNumber, (void*)portSC); } } else if (portSC & kOHCIHcRhPortStatus_PSSC) { if (_rootHubDevice && _rootHubDevice->GetPolicyMaker()) { // Make sure to send port index, not port number _rootHubDevice->GetPolicyMaker()->message(kIOUSBMessageRootHubWakeEvent, this, (void *)(uintptr_t) (port)); } else { IOLog("USB (OHCI):Port %d on bus 0x%x has remote wakeup from some device\n", (int)port+1, (uint32_t)_busNumber); } USBLog(5, "AppleUSBOHCI[%p]::ResumeUSBBus Port %d on bus 0x%x has remote wakeup from some device", this, (int)port+1, (uint32_t)_busNumber); } else if ((_errataBits & kErrataOHCINoGlobalSuspendOnSleep) // if we are on these controllers && (portSC & kOHCIHcRhPortStatus_CCS) // and we are currently connected && !(portSC & kOHCIHcRhPortStatus_PES) // and we are not currently enabled && (_savedHcRhPortStatus[port] & kOHCIHcRhPortStatus_PES)) // and we were enabled before we went to sleep { USBError(1, "USB (OHCI):Port %d on bus 0x%x is connected but not enabled. trying to set port enable. hcRhPortStatus(%p) _savedHcRhPortStatus(%p)", (int)port+1, (uint32_t)_busNumber, (void*)portSC, (void*)_savedHcRhPortStatus[port]); _pOHCIRegisters->hcRhPortStatus[port] = HostToUSBLong(kOHCIHcRhPortStatus_PES); // CCS when writing is CPE IOSleep(1); portSC = USBToHostLong(_pOHCIRegisters->hcRhPortStatus[port]); USBLog(2, "AppleUSBOHCI[%p]::ResumeUSBBus - new hcRhPortStatus(%p)", this, (void*)portSC); } _savedHcRhPortStatus[port] = 0; // clear this out to be safe once we have no more need for it } } }