IOReturn AppleUSBUHCI::ClearRootHubPortFeature(UInt16 wValue, UInt16 port) { UInt16 value; USBLog(5, "AppleUSBUHCI[%p]::ClearRootHubPortFeature %d %d", this, wValue, port); switch(wValue) { case kUSBHubPortEnableFeature : USBLog(5, "AppleUSBUHCI[%p]: Clear port enable", this); RHEnablePort(port, false); break; case kUSBHubPortConnectionChangeFeature : USBLog(5, "AppleUSBUHCI[%p]: Clear connection change", this); value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK; WritePortStatus(port-1, value | kUHCI_PORTSC_CSC); break; case kUSBHubPortEnableChangeFeature : USBLog(5, "AppleUSBUHCI[%p]: Clear port enable change", this); value = ReadPortStatus(port-1) & kUHCI_PORTSC_MASK; WritePortStatus(port-1, value | kUHCI_PORTSC_PEDC); break; case kUSBHubPortResetChangeFeature : USBLog(5, "AppleUSBUHCI[%p]: Clear port reset change", this); _portWasReset[port-1] = false; break; case kUSBHubPortSuspendFeature : RHSuspendPort(port, false); break; case kUSBHubPortSuspendChangeFeature : USBLog(5, "AppleUSBUHCI[%p]: Clear port suspend change", this); _portSuspendChange[port-1] = false; break; #if 0 // These will all fall through to return unsupported. case kUSBHubPortOverCurrentChangeFeature : RHResetOverCurrentChange(port); break; case kUSBHubPortPowerFeature : //status = RHPortPort(port, false); break; #endif default: USBLog(5,"AppleUSBUHCI[%p]: clear unknown feature %d", this, wValue); break; } 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; }
//================================================================================================ // // 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)); }
// 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; }
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); }
//================================================================================================ // // 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; }
// Reset and enable the port IOReturn AppleUSBUHCI::RHResetPort(int port) { UInt16 value; int i; USBLog(3, "AppleUSBUHCI[%p]::RHResetPort %d", this, port); port--; // convert 1-based to 0-based. value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value | kUHCI_PORTSC_RESET); /* Assert RESET for 50ms */ IOSleep(50); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value & ~kUHCI_PORTSC_RESET); IODelay(10); value = ReadPortStatus(port) & kUHCI_PORTSC_MASK; WritePortStatus(port, value | kUHCI_PORTSC_PED); for (i=10; i>0; i--) { IOSleep(10); value = ReadPortStatus(port); if ((value & kUHCI_PORTSC_CCS) == 0) { /* No device connected; don't enter reset state. */ //USBLog(5, "%s[%p]: no device connected, not entering reset state"); return kIOReturnNotResponding; break; } if (value & (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC)) { /* Change bits detected. Clear them and continue waiting. */ WritePortStatus(port, (value & kUHCI_PORTSC_MASK) | (kUHCI_PORTSC_PEDC | kUHCI_PORTSC_CSC)); continue; } if (value & kUHCI_PORTSC_PED) { /* Port successfully enabled. */ break; } } if (i == 0) { USBLog(5, "AppleUSBUHCI[%p]: reset port FAILED", this); return kIOReturnNotResponding; } // Remember that we were reset _portWasReset[port] = true; USBLog(5, "AppleUSBUHCI[%p]: reset port succeeded", this); return kIOReturnSuccess; }
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; }
IOReturn AppleUSBUHCI::GetRootHubPortStatus(IOUSBHubPortStatus *status, UInt16 port) { UInt16 p_status; UInt16 r_status, r_change; USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus on port %d", this, port+1); RHDumpPortStatus(port); // no longer do this, as the root hub can be queried even when we are suspended //if (_myBusState == kUSBBusStateSuspended) //{ // return kIOReturnNotResponding; //} port--; // convert to 0-based if (port >= kUHCI_NUM_PORTS) { return kIOReturnBadArgument; } p_status = ReadPortStatus(port); // check to see if suspend is on and connect is off - if so, clear the suspend if ((p_status & kUHCI_PORTSC_SUSPEND) && !(p_status & kUHCI_PORTSC_CCS)) { USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus - clearing suspend on disconnected port status[%p]", this, (void*)p_status); p_status &= kUHCI_PORTSC_MASK; // make sure not to clear the change bits p_status &= ~kUHCI_PORTSC_SUSPEND; // clear suspend WritePortStatus(port, p_status); // this does a sync and a delay p_status = ReadPortStatus(port); // reload USBLog(7, "AppleUSBUHCI[%p]::GetRootHubPortStatus - new port status[%p]", this, (void*)p_status); } /* Power is always turned on. */ r_status = kHubPortPower; if (p_status & kUHCI_PORTSC_SUSPEND) r_status |= kHubPortSuspend; if (p_status & kUHCI_PORTSC_RESET) r_status |= kHubPortBeingReset; if (p_status & kUHCI_PORTSC_LS) r_status |= kHubPortLowSpeed; if (p_status & kUHCI_PORTSC_PED) r_status |= kHubPortEnabled; if (p_status & kUHCI_PORTSC_CCS) r_status |= kHubPortConnection; status->statusFlags = HostToUSBWord(r_status); /* Synthesize the change bits that are not * in the hardware. */ r_change = r_status ^ _lastPortStatus[port]; if (p_status & kUHCI_PORTSC_PEDC) { r_change |= kHubPortEnabled; } else { r_change &= ~kHubPortEnabled; } if (p_status & kUHCI_PORTSC_CSC) { r_change |= kHubPortConnection; } else { r_change &= ~kHubPortConnection; } /* Suspend change is only when suspend changes * from true to false. It persists until * reset. */ if ((_lastPortStatus[port] & kHubPortSuspend) && !(r_status & kHubPortSuspend)) { USBLog(5, "AppleUSBUHCI[%p]::GetRootHubPortStatus - Turning on suspend change bit", this); _portSuspendChange[port] = true; } if (_portSuspendChange[port]) { r_change |= kHubPortSuspend; } else { r_change &= ~kHubPortSuspend; } /* Synthetic reset bit. */ if (_portWasReset[port]) { r_change |= kHubPortBeingReset; } status->changeFlags = HostToUSBWord(r_change); if (status->changeFlags) { USBLog(5, "AppleUSBUHCI[%p]::GetRootHubPortStatus for port(%d) returned status is (%x,%x)", this, (int)port+1, r_status, r_change); RHDumpHubPortStatus(status); } _lastPortStatus[port] = r_status; return kIOReturnSuccess; }