//================================================================================================
//
//   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();
}