//================================================================================================
//
//   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(&currentTime, &_portRecoveryTime[i-1] );
				absolutetime_to_nanoseconds(*(AbsoluteTime *)&currentTime, &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*)&currentTime;
						
						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
		}
	}
}