//================================================================================================ // // 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; }
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; }
//================================================================================================ // // 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 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; }
//================================================================================================ // // 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 } } }
void AppleUHCIQueueHead::SetPhysicalLink(IOPhysicalAddress next) { GetSharedLogical()->hlink = HostToUSBLong(next); IOSync(); }
void AppleUHCIIsochTransferDescriptor::SetPhysicalLink(IOPhysicalAddress next) { GetSharedLogical()->link = HostToUSBLong(next); IOSync(); }