//================================================================================================ // // 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; }
//================================================================================================ // // 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; }
//================================================================================================ // // SaveControllerStateForSleep // //================================================================================================ // IOReturn AppleUSBOHCI::SaveControllerStateForSleep(void) { UInt8 pciPMCapOffset = 0; UInt16 pmControlStatus = 0; // <rdar://problem/6623922> // The PCI family will have cleared the kPCIPMCSPMEStatus at this point. However, some OHCI controllers will apparently // set the bit again, probably when we actually put the individual ports into suspend. So we need to clear it before we // put the controller into global suspend. _device->findPCICapability(kIOPCIPowerManagementCapability, &pciPMCapOffset); if (pciPMCapOffset > 0x3f) // must be > 3f, section 3.1 { pmControlStatus = pciPMCapOffset + 4; } if (pmControlStatus) { UInt16 pmcsr = _device->configRead16(pmControlStatus); USBLog(7, "AppleUSBOHCI[%p]::SaveControllerStateForSleep before PMCS for device (%p) is (%p)", this, _device, (void*)pmcsr); if (pmcsr & kPCIPMCSPMEStatus) { // this one bit (kPCIPMCSPMEStatus) is Read/Write Clear. All other bits are R/W, so we write back the same value we // read so that it will be clear after the write _device->configWrite16(pmControlStatus, pmcsr); IOSleep(2); USBLog(2, "AppleUSBOHCI[%p]::SaveControllerStateForSleep after PMCS for device (%p) is (%p)", this, _device, (void*)_device->configRead16(pmControlStatus)); } } USBLog(2, "AppleUSBOHCI[%p]::SaveControllerStateForSleep - suspending the bus", this); _remote_wakeup_occurred = false; SuspendUSBBus(true); USBLog(2, "AppleUSBOHCI[%p]::SaveControllerStateForSleep - The bus is now suspended", this); _myBusState = kUSBBusStateSuspended; // on PCI PM machines, arm the PME and go to state D3 if (_hasPCIPwrMgmt) { _pOHCIRegisters->hcInterruptDisable = HostToUSBLong (kOHCIHcInterrupt_MIE); // disable interrupts during D3 state } 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; }
IOReturn com_milvich_driver_Thrustmaster::getReport(IOMemoryDescriptor *report, UInt8 *TMData, IOByteCount length) { UInt8 data[kReportSize]; int rockerPosition; unsigned int buttons = 0; UInt8 hat; if(TMData[kWCSButtonsByte] & kWCSRockerUPMask) { rockerPosition = 0; } else if(TMData[kWCSButtonsByte] & kWCSRockerDownMask) { rockerPosition = 2; } else { rockerPosition = 1; } // zero everything for(int i = 0; i < kReportSize; i++) { data[i] = 0; } // set up the buttons, reordering the bits so that they make more sense, trigger as button // six is just lame... // FCS Buttons buttons = buttons | ((bool)(TMData[kFCSButtonsByte] & kFCSTriggerMask)) << fButtonShifts[0 + rockerPosition]; buttons = buttons | ((bool)(TMData[kFCSButtonsByte] & kFCSThumbHighMask)) << fButtonShifts[3 + rockerPosition]; buttons = buttons | ((bool)(TMData[kFCSButtonsByte] & kFCSThumbLowMask)) << fButtonShifts[6 + rockerPosition]; buttons = buttons | ((bool)(TMData[kFCSButtonsByte] & kFCSPinkyMask)) << fButtonShifts[9 + rockerPosition]; // do the WCS if(fHasThrottle) { buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 1)) << fButtonShifts[12 + rockerPosition]; buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 2)) << fButtonShifts[15 + rockerPosition]; buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 4)) << fButtonShifts[18 + rockerPosition]; buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 8)) << fButtonShifts[21 + rockerPosition]; buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 16)) << fButtonShifts[24 + rockerPosition]; buttons = buttons | ((bool)(TMData[kWCSButtonsByte] & 32)) << fButtonShifts[27 + rockerPosition]; } // swap bytes around *((unsigned int*)data) = HostToUSBLong(buttons); // the hat switch is a pain // As near as I can tell 15 == null, 0 == up, 1 == up right, 2 == right, and so on... if(TMData[kFCSButtonsByte] & kFCSHatUpMask && TMData[kFCSButtonsByte] & kFCSHatRightMask) { hat = 2; } else if(TMData[kFCSButtonsByte] & kFCSHatRightMask && TMData[kFCSButtonsByte] & kFCSHatDownMask) { hat = 4; } else if(TMData[kFCSButtonsByte] & kFCSHatDownMask && TMData[kFCSButtonsByte] & kFCSHatleftMask) { hat = 6; } else if(TMData[kFCSButtonsByte] & kFCSHatleftMask && TMData[kFCSButtonsByte] & kFCSHatUpMask) { hat = 8; } else if(TMData[kFCSButtonsByte] & kFCSHatUpMask) { hat = 1; } else if(TMData[kFCSButtonsByte] & kFCSHatRightMask) { hat = 3; } else if(TMData[kFCSButtonsByte] & kFCSHatDownMask) { hat = 5; } else if(TMData[kFCSButtonsByte] & kFCSHatleftMask) { hat = 7; } else { hat = 0; // should be null } // move the data around based on the rockers position if(fHatIsModified) { if(rockerPosition == 0) { data[kFCSHatReportByte] = 0xf0 | hat; data[kFCSHatReportByte + 1] = 0xff; } if(rockerPosition == 1) { data[kFCSHatReportByte] = (hat << 4) | 0x0f; data[kFCSHatReportByte + 1] = 0xff; } else if(rockerPosition == 2) { data[kFCSHatReportByte] = 0xff; data[kFCSHatReportByte + 1] = hat; } } else { data[kFCSHatReportByte] = hat; } if(!fRockerIsModifier) { // and the rocker swtich if(TMData[kWCSButtonsByte] & kWCSRockerUPMask) { hat = 1; } else if(TMData[kWCSButtonsByte] & kWCSRockerDownMask) { hat = 5; } else { hat = 0; } data[kWCSHatReportByte] = data[kWCSHatReportByte] | hat << 4; } // then do the axis // the x & y axis range from -128 to 127. I convert that to 0 - 255 because a few programs // don't seem to like negative values... and they would think the range is 0-127... // everyone seems happy with a range from 0-255, so thats what I report data[kXAxisReportByte] = (TMData[kXAxisByte] + 128); // x axis data[kYAxisReportByte] = (TMData[kYAxisByte] + 128); // y axis data[kThrottleReportByte] = (255 - TMData[kThrottleByte]); // throttle (slider) data[kRuddersReportByte] = (TMData[kRuddersByte] + 128); // rudder (z)... I think /* IOLog("%s: Input Data: %02x%02x %02x%02x %02x%02x %02x%02x\n", NAME, TMData[0], TMData[1], TMData[2], TMData[3], TMData[4], TMData[5], TMData[6], TMData[7]); IOLog("%s: Output Data: %02x%02x %02x%02x %02x%02x %02x%02x\n", NAME, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); */ // copy the data into the memory descriptor report->writeBytes(0, data, kReportSize); return kIOReturnSuccess; }
//================================================================================================ // // ResumeController // //================================================================================================ // void AppleUSBUHCI::ResumeController(void) { UInt16 cmd; int i; USBTrace( kUSBTUHCI, KTPUHCIResumeController , (uintptr_t)this, 0, 0, 0); showRegisters(7, "+ResumeController"); cmd = ioRead16(kUHCI_CMD); if (cmd & kUHCI_CMD_RS) { USBLog(3, "AppleUSBUHCI[%p]::ResumeController - already running - returning", this); return; } // I need to save the existing frame list before I turn on processing so I can send SOF only for 10ms after we turn the controller on for (i=0;i < kUHCI_NVFRAMES; i++) { _frameList[i] |= HostToUSBLong(kUHCI_FRAME_T); } if (cmd & kUHCI_CMD_EGSM) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController controller is globally suspended - forcing resume", this); cmd |= kUHCI_CMD_FGR; ioWrite16(kUHCI_CMD, cmd); cmd = ioRead16(kUHCI_CMD); USBLog(5, "AppleUSBUHCI[%p]::ResumeController after EGSM->FGR, cmd is[%p]", this, (void*)cmd); } if (cmd & kUHCI_CMD_FGR) { // this could either be because the remote wwakeup caused this state or because we did above // need to wait 20ms IOSleep(20); cmd &= ~kUHCI_CMD_FGR; cmd &= ~kUHCI_CMD_EGSM; ioWrite16(kUHCI_CMD, cmd); } if ((cmd & (kUHCI_CMD_MAXP | kUHCI_CMD_CF)) != (kUHCI_CMD_MAXP | kUHCI_CMD_CF)) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController marking MAXP and CF", this); cmd |= (kUHCI_CMD_MAXP | kUHCI_CMD_CF); ioWrite16(kUHCI_CMD, cmd); } // restore the frame list register if (_framesPaddr != NULL) { USBLog(5, "AppleUSBUHCI[%p]::ResumeController setting FRBASEADDR[%p]", this, (void*)_framesPaddr); ioWrite32(kUHCI_FRBASEADDR, _framesPaddr); } USBLog(5, "AppleUSBUHCI[%p]::ResumeController starting controller", this); Run(true); // wait 10 ms for the device to recover IOSleep(10); // restore the list for (i=0;i < kUHCI_NVFRAMES; i++) { _frameList[i] &= ~HostToUSBLong(kUHCI_FRAME_T); } USBLog(7, "AppleUSBUHCI[%p]::ResumeController resume done, cmd %x, status %x ports[%p, %p]", this, ioRead16(kUHCI_CMD), ioRead16(kUHCI_STS),(void*)ReadPortStatus(0), (void*)ReadPortStatus(1)); showRegisters(7, "-ResumeController"); }
//================================================================================================ // // 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 } } }
//================================================================================================ // // 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])); } } }
// 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; }
void AppleUHCIQueueHead::SetPhysicalLink(IOPhysicalAddress next) { GetSharedLogical()->hlink = HostToUSBLong(next); IOSync(); }
void AppleUHCIIsochTransferDescriptor::SetPhysicalLink(IOPhysicalAddress next) { GetSharedLogical()->link = HostToUSBLong(next); IOSync(); }