#include <libkern/OSByteOrder.h>
#include <libkern/OSDebug.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include "AppleUSBHub.h"
#include "AppleUSBHubPort.h"
#define super IOUSBHubPolicyMaker
#define self this
static ErrataListEntry errataList[] = {
{0x046a, 0x0003, 0x0301, 0x0305, kErrataCaptiveOKBit}, {0x046a, 0x0003, 0x0601, 0x0605, kErrataCaptiveOKBit} };
enum
{
kEHCITestMode_Off = 0,
kEHCITestMode_J_State = 1,
kEHCITestMode_K_State = 2,
kEHCITestMode_SE0_NAK = 3,
kEHCITestMode_Packet = 4,
kEHCITestMode_ForceEnable = 5,
kEHCITestMode_Start = 10,
kEHCITestMode_End = 11
};
#define errataListLength (sizeof(errataList)/sizeof(ErrataListEntry))
OSDefineMetaClassAndStructors(AppleUSBHub, IOUSBHubPolicyMaker)
#define WATCHDOGSECONDS 6
enum
{
kWatchdogTimerPeriod = 1000 * WATCHDOGSECONDS, kDevZeroTimeoutCount = 30 / WATCHDOGSECONDS, kHubDriverRetryCount = 3,
kRootHubPollingInterval = 32,
kInitialDelayTime = 1500 };
#pragma mark ееееееее IOService Methods ееееееее
bool
AppleUSBHub::init( OSDictionary * propTable )
{
if( !super::init(propTable))
return (false);
_numCaptive = 0;
_startupDelay = 0;
_timerSource = NULL;
_gate = NULL;
_portSuspended = false;
_hubHasBeenDisconnected = false;
_hubIsDead = false;
_workThread = NULL;
_resetPortZeroThread = NULL;
_hubDeadCheckThread = NULL;
_busPowerGood = false;
_powerForCaptive = 0;
_outstandingIO = 0;
_outstandingResumes = 0;
_raisedPowerStateCount = 0;
_needToClose = false;
_abortExpected = false;
_needInterruptRead = false;
_devZeroLockedTimeoutCounter = kDevZeroTimeoutCount;
_retryCount = kHubDriverRetryCount;
_checkPortsThreadActive = false;
return(true);
}
bool
AppleUSBHub::start(IOService * provider)
{
USBLog(7, "AppleUSBHub[%p]::start - This is handled by the superclass", this);
return super::start(provider);
}
bool
AppleUSBHub::ConfigureHubDriver(void)
{
IOReturn err = 0;
OSDictionary *providerDict;
OSNumber *errataProperty;
OSNumber *locationIDProperty;
OSBoolean *boolProperty = NULL;
_inStartMethod = true;
USBLog(6, "AppleUSBHub[%p]::ConfigureHubDriver - calling RaisePowerState and IncrementOutstandingIO", this);
RaisePowerState();
IncrementOutstandingIO();
_timerSource = IOTimerEventSource::timerEventSource(this, (IOTimerEventSource::Action) TimeoutOccurred);
if ( _timerSource == NULL )
{
USBError(1, "AppleUSBHub::ConfigureHubDriver Couldn't allocate timer event source");
goto ErrorExit;
}
_gate = IOCommandGate::commandGate(this);
if(!_gate)
{
USBError(1, "AppleUSBHub[%p]::ConfigureHubDriver - unable to create command gate", this);
goto ErrorExit;
}
_workLoop = getWorkLoop();
if ( !_workLoop )
{
USBError(1, "AppleUSBHub::ConfigureHubDriver Couldn't get provider's workloop");
goto ErrorExit;
}
_workLoop->retain();
if ( _workLoop->addEventSource( _timerSource ) != kIOReturnSuccess )
{
USBError(1, "AppleUSBHub::ConfigureHubDriver Couldn't add timer event source");
goto ErrorExit;
}
if ( _workLoop->addEventSource( _gate ) != kIOReturnSuccess )
{
USBError(1, "AppleUSBHub::ConfigureHubDriver Couldn't add gate event source");
goto ErrorExit;
}
_address = _device->GetAddress();
if (!_device->open(this))
{
USBError(1, "AppleUSBHub::ConfigureHubDriver unable to open provider");
goto ErrorExit;
}
errataProperty = (OSNumber *)_device->getProperty("kStartupDelay");
if ( errataProperty )
{
_startupDelay = errataProperty->unsigned32BitValue();
IOSleep( _startupDelay );
}
boolProperty = (OSBoolean *)_device->getProperty("kIgnoreDisconnectOnWakeup");
if ( boolProperty )
{
_ignoreDisconnectOnWakeup = boolProperty->isTrue();
USBLog(5, "AppleUSBHub[%p]::ConfigureHubDriver - found kIgnoreDisconnectOnWakeup (%d)", this, _ignoreDisconnectOnWakeup);
}
_errataBits = GetHubErrataBits();
setProperty("Errata", _errataBits, 32);
err = ConfigureHub();
if ( err == kIOReturnSuccess )
{
if (_hsHub)
registerService();
_workThread = thread_call_allocate((thread_call_func_t)ProcessStatusChangedEntry, (thread_call_param_t)this);
_resetPortZeroThread = thread_call_allocate((thread_call_func_t)ResetPortZeroEntry, (thread_call_param_t)this);
_hubDeadCheckThread = thread_call_allocate((thread_call_func_t)CheckForDeadHubEntry, (thread_call_param_t)this);
_clearFeatureEndpointHaltThread = thread_call_allocate((thread_call_func_t)ClearFeatureEndpointHaltEntry, (thread_call_param_t)this);
_checkForActivePortsThread = thread_call_allocate((thread_call_func_t)CheckForActivePortsEntry, (thread_call_param_t)this);
_waitForPortResumesThread = thread_call_allocate((thread_call_func_t)WaitForPortResumesEntry, (thread_call_param_t)this);
_ensureUsabilityThread = thread_call_allocate((thread_call_func_t)EnsureUsabilityEntry, (thread_call_param_t)this);
_initialDelayThread = thread_call_allocate((thread_call_func_t)InitialDelayEntry, (thread_call_param_t)this);
if ( !_workThread || !_resetPortZeroThread || !_hubDeadCheckThread || !_clearFeatureEndpointHaltThread || !_checkForActivePortsThread || !_waitForPortResumesThread || !_ensureUsabilityThread || !_initialDelayThread)
{
USBError(1, "AppleUSBHub[%p] could not allocate all thread functions. Aborting start", this);
goto ErrorExit;
}
locationIDProperty = (OSNumber *) _device->getProperty(kUSBDevicePropertyLocationID);
if ( locationIDProperty )
{
_locationID = locationIDProperty->unsigned32BitValue();
}
USBLog(1, "AppleUSBHub[%p]::ConfigureHubDriver - USB Generic Hub @ %d (0x%x)", this, _address, (uint32_t)_locationID);
_inStartMethod = false;
USBLog(6, "AppleUSBHub[%p]::ConfigureHubDriver - device name %s - done - calling DecrementOutstandingIO and LowerPowerState", this, _device->getName());
DecrementOutstandingIO();
LowerPowerState();
return true;
}
ErrorExit:
USBError(1,"AppleUSBHub[%p]::ConfigureHubDriver Aborting startup: error 0x%x", this, err);
if ( _device && _device->isOpen(this) )
_device->close(this);
StopPorts();
stop(_device);
if ( _timerSource )
{
if ( _workLoop )
_workLoop->removeEventSource(_timerSource);
_timerSource->release();
_timerSource = NULL;
}
if (_gate)
{
if (_workLoop)
_workLoop->removeEventSource(_gate);
_gate->release();
_gate = NULL;
}
if ( _workLoop )
{
_workLoop->release();
_workLoop = NULL;
}
_inStartMethod = false;
USBLog(6, "AppleUSBHub[%p]::ConfigureHubDriver - done (with err) - calling DecrementOutstandingIO and LowerPowerState", this);
DecrementOutstandingIO();
LowerPowerState();
return false;
}
void
AppleUSBHub::stop(IOService * provider)
{
if (_buffer)
{
_buffer->release();
_buffer = NULL;
}
if (_hsHub)
{
if (_bus)
_bus->RemoveHSHub(_address);
}
if(_hubInterface)
{
_hubInterface->close(this);
_hubInterface->release();
_hubInterface = NULL;
}
if (_workThread)
{
thread_call_cancel(_workThread);
thread_call_free(_workThread);
_workThread = 0;
}
if (_resetPortZeroThread)
{
thread_call_cancel(_resetPortZeroThread);
thread_call_free(_resetPortZeroThread);
_resetPortZeroThread = 0;
}
if (_hubDeadCheckThread)
{
thread_call_cancel(_hubDeadCheckThread);
thread_call_free(_hubDeadCheckThread);
_hubDeadCheckThread = 0;
}
if (_clearFeatureEndpointHaltThread)
{
thread_call_cancel(_clearFeatureEndpointHaltThread);
thread_call_free(_clearFeatureEndpointHaltThread);
_clearFeatureEndpointHaltThread = 0;
}
if (_checkForActivePortsThread)
{
thread_call_cancel(_checkForActivePortsThread);
thread_call_free(_checkForActivePortsThread);
_checkForActivePortsThread = 0;
}
if (_waitForPortResumesThread)
{
thread_call_cancel(_waitForPortResumesThread);
thread_call_free(_waitForPortResumesThread);
_waitForPortResumesThread = 0;
}
if (_ensureUsabilityThread)
{
thread_call_cancel(_ensureUsabilityThread);
thread_call_free(_ensureUsabilityThread);
_ensureUsabilityThread = 0;
}
if (_initialDelayThread)
{
thread_call_cancel(_initialDelayThread);
thread_call_free(_initialDelayThread);
_initialDelayThread = 0;
}
if (_workLoop)
_workLoop->removeEventSource(_gate);
if ( _workLoop )
_workLoop->removeEventSource(_timerSource);
USBLog(3, "AppleUSBHub[%p]::stop - calling PMstop", this);
PMstop();
USBLog(3, "AppleUSBHub[%p]::stop - calling super::stop", this);
super::stop(provider);
}
IOReturn
AppleUSBHub::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
IOUSBHubPortReEnumerateParam * params ;
IOUSBHubPortClearTTParam * ttParams;
USBLog(3, "AppleUSBHub[%p]::message(%p)(%s) - isInactive(%s) _myPowerState(%d) _powerStateChangingTo(%d)", this, (void*)type, HubMessageToString(type), isInactive() ? "true" : "false", (int)_myPowerState, (int)_powerStateChangingTo);
switch ( type )
{
case kIOUSBMessageHubIsDeviceConnected:
if ( isInactive() || _hubIsDead )
{
USBLog(3,"AppleUSBHub[%p] : got kIOUSBMessageHubIsDeviceConnected while isInactive() or _hubIsDead", this);
err = kIOReturnNoDevice;
break;
}
USBLog(6, "AppleUSBHub[%p]::message(kIOUSBMessageHubIsDeviceConnected) - calling IncrementOutstandingIO", this);
IncrementOutstandingIO();
err = GetPortStatus(&status, * (UInt32 *) argument );
if ( err != kIOReturnSuccess )
{
err = kIOReturnNoDevice;
}
else
{
USBLog(5,"AppleUSBHub[%p]::kIOUSBMessageHubIsDeviceConnected - port %d - status(%8x)/change(%8x), _ignoreDisconnectOnWakeup = %d", this, * (uint32_t *) argument, status.statusFlags, status.changeFlags, _ignoreDisconnectOnWakeup);
if ( (status.statusFlags & kHubPortConnection) && (_ignoreDisconnectOnWakeup || !(status.changeFlags & kHubPortConnection)) )
{
if ( _ignoreDisconnectOnWakeup )
{
USBLog(6, "AppleUSBHub[%p]::message(kIOUSBMessageHubIsDeviceConnected) - _ignoreDisconnectOnWakeup is true", this);
}
err = kIOReturnSuccess;
}
else
err = kIOReturnNoDevice;
}
USBLog(6, "AppleUSBHub[%p]::message(kIOUSBMessageHubIsDeviceConnected) - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
break;
case kIOUSBMessageHubSuspendPort:
case kIOUSBMessageHubResumePort:
case kIOUSBMessageHubResetPort:
USBLog(5, "AppleUSBHub[%p]::message(%s) - calling EnsureUsability", this, HubMessageToString(type));
EnsureUsability();
err = DoPortAction( type, * (UInt32 *) argument, 0 );
break;
case kIOUSBMessageHubPortClearTT:
if ( _hsHub )
{
ttParams = (IOUSBHubPortClearTTParam *) argument;
err = DoPortAction( type, ttParams->portNumber, ttParams->options );
}
else
{
err = kIOReturnUnsupported;
}
break;
case kIOUSBMessageHubSetPortRecoveryTime:
{
params = (IOUSBHubPortReEnumerateParam *) argument;
AppleUSBHubPort *port = _ports ? _ports[params->portNumber-1] : NULL;
if (port)
{
USBLog(5, "AppleUSBHub[%p]::message(kIOUSBMessageHubSetPortRecoveryTime) - port %d, setting _portResumeRecoveryTime to %d", this, (uint32_t)params->portNumber, (uint32_t)params->options);
port->_portResumeRecoveryTime = params->options;
}
}
break;
case kIOUSBMessageHubReEnumeratePort:
params = (IOUSBHubPortReEnumerateParam *) argument;
err = DoPortAction( type, params->portNumber, params->options );
break;
case kIOMessageServiceIsTerminated:
USBLog(3,"AppleUSBHub[%p] : Received kIOMessageServiceIsTerminated - ignoring", this);
break;
case kIOUSBMessagePortHasBeenReset:
if ( isInactive() )
{
USBLog(5,"AppleUSBHub[%p] : got kIOUSBMessagePortHasBeenReset while isInactive() or _hubIsDead", this);
err = kIOReturnSuccess;
break;
}
if (!_inStartMethod)
{
_inStartMethod = true;
USBLog(6, "AppleUSBHub[%p]::message(kIOUSBMessagePortHasBeenReset) - calling RaisePowerState and IncrementOutstandingIO", this);
RaisePowerState();
IncrementOutstandingIO(); USBLog(3, "AppleUSBHub[%p] Received kIOUSBMessagePortHasBeenReset -- reconfiguring hub", this);
if ( _interruptPipe )
{
_interruptPipe->Abort();
_interruptPipe = NULL;
}
if(_hubInterface)
{
_hubInterface->close(this);
_hubInterface->release();
_hubInterface = NULL;
}
if (_buffer)
{
_buffer->release();
_buffer = NULL;
}
err = ConfigureHub();
if ( err )
{
USBLog(3, "AppleUSBHub[%p] Reconfiguring hub returned: 0x%x", this, err);
}
else
{
USBLog(1, "[%p] (Reset) USB Generic Hub @ %d (0x%x)", this, _address, (uint32_t)_locationID);
}
_inStartMethod = false;
USBLog(6, "AppleUSBHub[%p]::message(kIOUSBMessagePortHasBeenReset) - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
LowerPowerState();
if ( err == kIOReturnSuccess)
{
makeUsable();
}
}
USBLog(3, "-AppleUSBHub[%p] Received kIOUSBMessagePortHasBeenReset -- finished reconfiguring hub", this);
break;
case kIOUSBMessagePortHasBeenResumed:
case kIOUSBMessagePortWasNotSuspended:
_portSuspended = false;
_abortExpected = false;
USBLog(5, "AppleUSBHub[%p]: received kIOUSBMessagePortHasBeenResumed or kIOUSBMessagePortWasNotSuspended (%p) - _myPowerState(%d) - ensuring usability", this, (void*)type, (int)_myPowerState);
_needInterruptRead = true;
EnsureUsability();
break;
default:
break;
}
return err;
}
bool
AppleUSBHub::finalize(IOOptionBits options)
{
return(super::finalize(options));
}
bool
AppleUSBHub::requestTerminate( IOService * provider, IOOptionBits options )
{
int retries = 600;
USBLog(3, "AppleUSBHub[%p]::requestTerminate - _myPowerState(%d) _powerStateChangingTo(%d)", this, (int)_myPowerState, (int)_powerStateChangingTo);
if ((_myPowerState != kIOUSBHubPowerStateOn) || (_powerStateChangingTo != kIOUSBHubPowerStateStable))
changePowerStateTo(kIOUSBHubPowerStateOn);
while ((_myPowerState != kIOUSBHubPowerStateOn) && (_powerStateChangingTo != kIOUSBHubPowerStateStable) && (retries-- > 0))
{
USBLog(3, "AppleUSBHub[%p]::requestTerminate - still waiting - _myPowerState(%d) _powerStateChangingTo(%d) retries left(%d)", this, (int)_myPowerState, (int)_powerStateChangingTo, retries);
IOSleep(100);
}
return super::requestTerminate(provider, options);
}
bool
AppleUSBHub::willTerminate( IOService * provider, IOOptionBits options )
{
IOReturn err;
int portIndex, portNum;
AppleUSBHubPort * port;
USBLog(3, "AppleUSBHub[%p]::willTerminate isInactive = %d", this, isInactive());
if ( _interruptPipe )
{
err = _interruptPipe->Abort();
if ( err != kIOReturnSuccess )
{
USBLog(1, "AppleUSBHub[%p]::willTerminate interruptPipe->Abort returned 0x%x", this, err);
}
}
if ( _ports)
{
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex + 1;
port = _ports ? _ports[portIndex] : NULL;
if (port)
{
if (port->_devZero)
{
USBLog(1, "AppleUSBHub[%p]::willTerminate - port %d had the dev zero lock", this, portNum);
}
port->ReleaseDevZeroLock();
if (port->_portPMState == usbHPPMS_pm_suspended)
{
IOUSBControllerV3 *v3Bus = NULL;
USBLog(5, "AppleUSBHub[%p]::willTerminate - port %d was suspended by the power manager - re-enabling the endpoints", this, portNum);
if (_device)
v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
if (v3Bus && port->_portDevice)
{
USBLog(5, "AppleUSBHub[%p]::willTerminate - Enabling endpoints for device at address (%d)", this, (int)port->_portDevice->GetAddress());
err = v3Bus->EnableAddressEndpoints(port->_portDevice->GetAddress(), true);
if (err)
{
USBLog(5, "AppleUSBHub[%p]::willTerminate - EnableAddressEndpoints returned (%p)", this, (void*)err);
}
}
port->_portPMState = usbHPPMS_active;
}
}
}
}
if (_timerSource)
{
_timerSource->cancelTimeout();
}
USBLog(3, "AppleUSBHub[%p]::willTerminate - calling super::willTerminate", this);
return super::willTerminate(provider, options);
}
bool
AppleUSBHub::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
USBLog(3, "AppleUSBHub[%p]::didTerminate isInactive[%s] _outstandingIO[%d]", this, isInactive() ? "true" : "false", (int)_outstandingIO);
if (!_outstandingIO && (_powerStateChangingTo == kIOUSBHubPowerStateStable) && !_doPortActionLock)
{
USBLog(5, "AppleUSBHub[%p]::didTerminate - closing _device(%p)", this, _device);
StopPorts();
_device->close(this);
}
else
{
USBLog(5, "AppleUSBHub[%p]::didTerminate - _device(%p) - setting needToClose - _outstandingIO(%d) _powerStateChangingTo(%d)", this, _device, (int)_outstandingIO, (int)_powerStateChangingTo);
_needToClose = true;
}
return super::didTerminate(provider, options, defer);
}
bool
AppleUSBHub::terminate( IOOptionBits options )
{
USBLog(3, "AppleUSBHub[%p]::terminate isInactive = %d", this, isInactive());
return super::terminate(options);
}
void
AppleUSBHub::free( void )
{
USBLog(6, "AppleUSBHub[%p]::free isInactive = %d", this, isInactive());
if (_timerSource)
{
_timerSource->release();
_timerSource = NULL;
}
if (_gate)
{
_gate->release();
_gate = NULL;
}
if (_workLoop)
{
_workLoop->release();
_workLoop = NULL;
}
super::free();
}
bool
AppleUSBHub::terminateClient( IOService * client, IOOptionBits options )
{
USBLog(3, "AppleUSBHub[%p]::terminateClient isInactive = %d", this, isInactive());
return super::terminateClient(client, options);
}
IOReturn
AppleUSBHub::powerStateWillChangeTo ( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
IOReturn ret;
USBLog(5, "+AppleUSBHub[%p]::powerStateWillChangeTo - from State(%d) to state(%d) _needInterruptRead (%s) _outstandingIO(%d) isInactive(%s)", this, (int)_myPowerState, (int)stateNumber, _needInterruptRead ? "true" : "false", (int)_outstandingIO, isInactive() ? "true" : "false");
ret = super::powerStateWillChangeTo( capabilities, stateNumber, whatDevice);
if (_powerStateChangingTo < kIOUSBHubPowerStateOn)
{
int retries = 300;
_abandonCheckPorts = true;
if ( _interruptPipe && !_isRootHub)
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - aborting pipe", this);
_abortExpected = true;
_needInterruptRead = false;
_interruptPipe->Abort();
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - done aborting pipe", this);
}
while (retries-- && (IsPortInitThreadActiveForAnyPort() || IsStatusChangedThreadActiveForAnyPort()))
{
USBLog(1, "AppleUSBHub[%p]::powerStateWillChangeTo - an init thread or status changed thread is still active for some port - waiting 100ms (retries=%d)", this, retries);
IOSleep(100);
}
}
USBLog(5, "-AppleUSBHub[%p]::powerStateWillChangeTo - DONE from State(%d) to state(%d) _needInterruptRead (%s) _outstandingIO(%d) isInactive(%s) ret(%p)", this, (int)_myPowerState, (int)stateNumber, _needInterruptRead ? "true" : "false", (int)_outstandingIO, isInactive() ? "true" : "false", (void*)ret);
return ret;
}
IOReturn
AppleUSBHub::setPowerState ( unsigned long powerStateOrdinal, IOService* whatDevice )
{
if (_myPowerState != powerStateOrdinal)
{
USBLog(6, "AppleUSBHub[%p]::setPowerState - calling IncrementOutstandingIO", this);
IncrementOutstandingIO(); }
return super::setPowerState(powerStateOrdinal, whatDevice);
}
IOReturn
AppleUSBHub::powerStateDidChangeTo ( IOPMPowerFlags capabilities, unsigned long stateNumber, IOService* whatDevice)
{
unsigned long oldState = _myPowerState;
IOReturn ret;
USBLog(5, "AppleUSBHub[%p]::+powerStateDidChangeTo - from State(%d) to state(%d) _needInterruptRead (%s)", this, (int)oldState, (int)stateNumber, _needInterruptRead ? "true" : "false");
ret = super::powerStateDidChangeTo( capabilities, stateNumber, whatDevice);
if (oldState != stateNumber)
{
USBLog(6, "AppleUSBHub[%p]::powerStateDidChangeTo - calling DecrementOutstandingIO", this);
DecrementOutstandingIO(); }
USBLog(5, "AppleUSBHub[%p]::-powerStateDidChangeTo - from State(%d) to state(%d) _needInterruptRead (%s) ret[%p]", this, (int)oldState, (int)stateNumber, _needInterruptRead ? "true" : "false", (void*)ret);
return ret;
}
void
AppleUSBHub::powerChangeDone ( unsigned long fromState)
{
USBLog((fromState == _myPowerState) ? 7 : 5, "AppleUSBHub[%p]::powerChangeDone - device(%s) from State(%d) to state(%d) _needInterruptRead (%s)", this, _device->getName(), (int)fromState, (int)_myPowerState, _needInterruptRead ? "true" : "false");
super::powerChangeDone(fromState);
if (isInactive() && _needToClose)
{
IncrementOutstandingIO();
DecrementOutstandingIO();
}
if (!isInactive() && !_hubIsDead && !_checkPortsThreadActive && (_myPowerState == kIOUSBHubPowerStateOn))
{
_abandonCheckPorts = false;
_checkPortsThreadActive = true;
retain(); USBLog(5,"AppleUSBHub[%p]::powerChangeDone - spawning _checkForActivePortsThread", this);
if ( thread_call_enter(_checkForActivePortsThread) == TRUE )
{
USBLog(1,"AppleUSBHub[%p]::powerChangeDone - _checkForActivePortsThread already queued", this);
release();
}
}
if ( _needToCallResetDevice and _myPowerState == kIOUSBHubPowerStateOff)
{
_needToCallResetDevice = false;
USBLog(1, "AppleUSBHub[%p]::powerChangeDone - calling ResetDevice()", this);
IOReturn err = _device->ResetDevice();
if ( err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHub[%p]::powerChangeDone - ResetDevice returned 0x%x", this, err);
}
USBLog(1, "AppleUSBHub[%p]::powerChangeDone - calling changePowerStateToPriv(kIOUSBHubPowerStateOn)", this);
changePowerStateToPriv(kIOUSBHubPowerStateOn);
powerOverrideOffPriv();
}
}
#pragma mark ееееееее Configuration ееееееее
IOReturn
AppleUSBHub::ConfigureHub()
{
IOReturn err = kIOReturnSuccess;
IOUSBFindInterfaceRequest req;
const IOUSBConfigurationDescriptor *cd;
OSBoolean *expressCardCantWakeRef;
_busPowerGood = false;
_powerForCaptive = 0;
_numCaptive = 0;
_retryCount = kHubDriverRetryCount;
if (_device->GetNumConfigurations() < 1)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub No hub configurations", this);
err = kIOReturnNoResources; goto ErrorExit;
}
cd = _device->GetFullConfigurationDescriptor(0);
if (!cd)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub No config descriptor", this);
err = kIOUSBConfigNotFound;
goto ErrorExit;
}
err = _device->SetConfiguration(this, cd->bConfigurationValue, false);
if (err)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub SetConfiguration failed. Error 0x%x", this, err);
goto ErrorExit;
}
if (cd->bmAttributes & kUSBAtrRemoteWakeup)
{
USBLog(3,"AppleUSBHub[%p]::ConfigureHub Setting kUSBFeatureDeviceRemoteWakeup for Hub device (%p)", this, _device);
err = _device->SetFeature(kUSBFeatureDeviceRemoteWakeup);
if ( err)
USBError(1,"AppleUSBHub[%p]::ConfigureHub SetFeature(kUSBFeatureDeviceRemoteWakeup) failed. Error 0x%x", this, err);
}
expressCardCantWakeRef = OSDynamicCast( OSBoolean, _device->getProperty(kUSBExpressCardCantWake) );
if ( expressCardCantWakeRef && expressCardCantWakeRef->isTrue() )
{
USBLog(3, "%s[%p](%s) found an express card device which will disconnect across sleep", getName(), this, _device->getName() );
_device->GetBus()->retain();
_device->GetBus()->message(kIOUSBMessageExpressCardCantWake, this, _device);
_device->GetBus()->release();
}
req.bInterfaceClass = kUSBHubClass;
req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
_hubInterface = _device->FindNextInterface(NULL, &req);
if (_hubInterface == 0)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub no interface found, trying again", this);
IOSleep(100);
req.bInterfaceClass = kUSBHubClass;
req.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
req.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
_hubInterface = _device->FindNextInterface(NULL, &req);
if (_hubInterface == 0)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub no interface found", this);
err = kIOUSBInterfaceNotFound;
goto ErrorExit;
}
}
_hubInterface->retain();
_busPowered = (cd->bmAttributes & kUSBAtrBusPowered) ? TRUE : FALSE; _selfPowered = (cd->bmAttributes & kUSBAtrSelfPowered) ? TRUE : FALSE;
if( !(_busPowered || _selfPowered) )
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub illegal device config - no power", this);
err = kIOReturnNoPower; goto ErrorExit;
}
if ( (err = GetHubDescriptor(&_hubDescriptor)) )
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub could not get hub descriptor (0x%x)", this, err);
goto ErrorExit;
}
if(_hubDescriptor.numPorts < 1)
{
USBLog(1,"AppleUSBHub[%p]::ConfigureHub there are no ports on this hub", this);
}
if(_hubDescriptor.numPorts > 7)
{
USBLog(3,"AppleUSBHub[%p]::ConfigureHub there are an awful lot of ports (%d) on this hub", this, _hubDescriptor.numPorts);
}
_readBytes = ((_hubDescriptor.numPorts + 1) / 8) + 1;
_buffer = IOBufferMemoryDescriptor::withCapacity(_readBytes, kIODirectionIn);
if (!_hubInterface->open(this))
{
USBError(1," AppleUSBHub[%p]::ConfigureHub could not open hub interface", this);
err = kIOReturnNotOpen;
goto ErrorExit;
}
_multiTTs = false;
_hsHub = false;
if (_device->GetbcdUSB() >= 0x200)
{
if (_bus)
{
switch (_device->GetProtocol())
{
case 0:
USBLog(5, "AppleUSBHub[%p]::ConfigureHub - found FS/LS only hub", this);
break;
case 1:
USBLog(5, "AppleUSBHub[%p]::ConfigureHub - found single TT hub", this);
_bus->AddHSHub(_address, 0);
_hsHub = true;
break;
case 2:
USBLog(5, "AppleUSBHub[%p]::ConfigureHub - found multi TT hub", this);
_hsHub = true;
if ((err = _hubInterface->SetAlternateInterface(this, 1))) {
USBError(1, "AppleUSBHub[%p]::ConfigureHub - err (%x) setting alt interface", this, err);
_bus->AddHSHub(_address, 0);
}
else
_bus->AddHSHub(_address, kUSBHSHubFlagsMultiTT);
_multiTTs = true;
break;
default:
USBError(1, "AppleUSBHub[%p]::ConfigureHub - unknown protocol (%d)", this, _device->GetProtocol());
break;
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::ConfigureHub - not on a V2 controller", this);
}
}
IOUSBFindEndpointRequest request;
request.type = kUSBInterrupt;
request.direction = kUSBIn;
_interruptPipe = _hubInterface->FindNextPipe(NULL, &request);
if(!_interruptPipe)
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub could not find interrupt pipe", this);
err = kIOUSBNotEnoughPipesErr; goto ErrorExit;
}
UnpackPortFlags();
CountCaptivePorts();
err = CheckPortPowerRequirements();
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub CheckPortPowerRequirements failed with 0x%x", this, err);
goto ErrorExit;
}
err = AllocatePortMemory();
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBHub[%p]::ConfigureHub AllocatePortMemory failed with 0x%x", this, err);
goto ErrorExit;
}
if (_hsHub)
{
if (!_multiTTs)
setProperty("High Speed", (unsigned long long)1, 8); else
setProperty("High Speed", (unsigned long long)_hubDescriptor.numPorts, 8); }
clock_get_uptime(&_wakeupTime);
setProperty("IOUserClientClass", "AppleUSBHSHubUserClient");
_hubIsDead = FALSE;
ErrorExit:
return err;
}
void
AppleUSBHub::UnpackPortFlags(void)
{
int i;
int numFlags = ((_hubDescriptor.numPorts + 1) / 8) + 1;
for(i = 0; i < numFlags; i++)
{
_hubDescriptor.pwrCtlPortFlags[i] = _hubDescriptor.removablePortFlags[numFlags+i];
_hubDescriptor.removablePortFlags[numFlags+i] = 0;
}
}
void
AppleUSBHub::CountCaptivePorts(void)
{
int portMask = 2;
int portByte = 0;
int currentPort;
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
if ((_hubDescriptor.removablePortFlags[portByte] & portMask) != 0)
_numCaptive++;
portMask <<= 1;
if(portMask > 0x80)
{
portMask = 1;
portByte++;
}
}
}
IOReturn
AppleUSBHub::CheckPortPowerRequirements(void)
{
IOReturn err = kIOReturnSuccess;
UInt32 hubPower = _hubDescriptor.hubCurrent/2;
UInt32 busPower = _device->GetBusPowerAvailable();
UInt32 powerAvailForPorts = 0;
UInt32 powerNeededForPorts = 0;
bool startExternal;
OSNumber * hubWakePowerReserved;
do
{
if (hubPower > busPower)
{
USBLog(3, "AppleUSBHub [%p] Hub claims to need more power (%d > %d) than available", this, (uint32_t)hubPower, (uint32_t)busPower);
_busPowerGood = false;
_powerForCaptive = 0;
}
else
{
powerAvailForPorts = busPower - hubPower;
powerNeededForPorts = (_hubDescriptor.numPorts - _numCaptive) * kUSB100mA;
_busPowerGood = (powerAvailForPorts >= powerNeededForPorts);
if(_numCaptive > 0)
{
if(_busPowerGood)
_powerForCaptive =
(powerAvailForPorts - powerNeededForPorts) / _numCaptive;
else
_powerForCaptive = powerAvailForPorts / _numCaptive;
}
if( (_errataBits & kErrataCaptiveOKBit) != 0)
_powerForCaptive = kUSB100mAAvailable;
}
_selfPowerGood = false;
if (_selfPowered)
{
USBStatus status = 0;
IOReturn localErr;
_powerForCaptive = kUSB100mAAvailable;
localErr = _device->GetDeviceStatus(&status);
if ( localErr != kIOReturnSuccess )
{
err = localErr;
break;
}
status = USBToHostWord(status);
_selfPowerGood = ((status & 1) != 0); }
if(_selfPowered && _busPowered)
{
if(_selfPowerGood)
{
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - Hub attached - Self/Bus powered, power supply good", this);
if (!_isRootHub && !_dontAllowSleepPower)
{
OSObject * anObj = _device->copyProperty(kAppleCurrentInSleep);
if ( anObj == NULL )
{
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - setting Extra Power in sleep to %d", this, (int)(_hubDescriptor.numPorts * kUSB500mAAvailable * 2));
_device->setProperty(kAppleCurrentInSleep, _hubDescriptor.numPorts * kUSB500mAAvailable * 2, 32);
}
else
{
anObj->release();
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - device already had a kAppleCurrentInSleep property", this);
}
}
}
else
{
USBLog(3,"AppleUSBHub[%p] Hub attached - Self/Bus powered, no external power", this);
}
}
else
{
if(_selfPowered)
{
if(_selfPowerGood)
{
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - Hub attached - Self powered, power supply good", this);
if (!_isRootHub && !_dontAllowSleepPower)
{
OSObject * anObj = _device->copyProperty(kAppleCurrentInSleep);
if ( anObj == NULL )
{
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - setting Extra Power in sleep to %d", this, (int)_hubDescriptor.numPorts * kUSB500mAAvailable * 2);
_device->setProperty(kAppleCurrentInSleep, _hubDescriptor.numPorts * kUSB500mAAvailable * 2, 32);
}
else
{
anObj->release();
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - device already had a kAppleCurrentInSleep property", this);
}
}
}
else
{
USBLog(3,"AppleUSBHub[%p] Hub attached - Self powered, no external power", this);
}
}
else
{
USBLog(3,"AppleUSBHub[%p] Hub attached - Bus powered", this);
}
}
#if defined (__i386__)
if (_isRootHub && (_device->GetHubCharacteristics() & kIOUSBHubDeviceCanSleep))
{
OSObject * anObj = _device->copyProperty(kAppleCurrentInSleep);
if ( anObj == NULL )
{
_device->setProperty(kAppleCurrentInSleep, _hubDescriptor.numPorts * kUSB500mAAvailable * 2, 32);
}
else
{
anObj->release();
}
}
#endif
startExternal = (_busPowerGood || _selfPowerGood);
if( !startExternal )
{
err = kIOReturnNoPower;
_device->DisplayUserNotification(kUSBNotEnoughPowerNotificationType);
IOLog("USB Low Power Notice: The hub \"%s\" cannot be used because there is not enough power for all its ports\n", _device->getName());
USBLog(1,"AppleUSBHub[%p]: insufficient power to turn on ports", this);
if(!_busPowered)
{
break;
}
}
hubWakePowerReserved = OSDynamicCast(OSNumber, _device->getProperty("HubWakePowerReserved"));
if ( hubWakePowerReserved && _selfPowerGood )
{
UInt32 wakePowerReserved = hubWakePowerReserved->unsigned32BitValue();
USBLog(3,"AppleUSBHub[%p]::CheckPowerPowerRequirements - returning %ld power because we actually have a self-powered hub", this, wakePowerReserved);
_device->IOUSBDevice::ReturnExtraPower(kUSBPowerDuringWake, wakePowerReserved);
wakePowerReserved = 0;
_device->setProperty("HubWakePowerReserved", wakePowerReserved, 32);
}
} while (false);
return err;
}
IOReturn
AppleUSBHub::AllocatePortMemory(void)
{
AppleUSBHubPort *port;
UInt32 power;
UInt32 portMask = 2;
UInt32 portByte = 0;
UInt32 currentPort;
bool captive;
AppleUSBHubPort **cachedPorts;
cachedPorts = (AppleUSBHubPort **) IOMalloc(sizeof(AppleUSBHubPort *) * _hubDescriptor.numPorts);
if (!cachedPorts)
return kIOReturnNoMemory;
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
if ((_hubDescriptor.removablePortFlags[portByte] & portMask) != 0)
{
power = _selfPowerGood ? (UInt32)kUSB500mAAvailable : _powerForCaptive;
captive = true;
}
else
{
power = _selfPowerGood ? kUSB500mAAvailable : kUSB100mAAvailable;
captive = false;
}
port = new AppleUSBHubPort;
if (port->init(self, currentPort, power, captive) != kIOReturnSuccess)
{
port->release();
cachedPorts[currentPort-1] = NULL;
}
else
cachedPorts[currentPort-1] = port;
portMask <<= 1;
if(portMask > 0x80)
{
portMask = 1;
portByte++;
}
}
_ports = cachedPorts;
return kIOReturnSuccess;
}
#pragma mark ееее Power Management ееее
IOReturn
AppleUSBHub::HubPowerChange(unsigned long powerStateOrdinal)
{
IOReturn err = kIOReturnSuccess;
UInt32 retries;
IOReturn ret = kIOPMAckImplied;
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - powerStateOrdinal(%d) _needInterruptRead(%s) isInactive(%s)", this, (int)powerStateOrdinal, _needInterruptRead ? "true" : "false", isInactive() ? "true" : "false");
if ( (_myPowerState == kIOUSBHubPowerStateSleep) && ( powerStateOrdinal > kIOUSBHubPowerStateSleep) )
{
USBLog(6, "AppleUSBHub[%p]::HubPowerChange - We are waking up _myPowerState(%d), powerStateOrdinal(%d)", this, (int)_myPowerState, (int)powerStateOrdinal);
clock_get_uptime(&_wakeupTime);
}
switch (powerStateOrdinal)
{
case kIOUSBHubPowerStateOn:
if (_portSuspended && _device)
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - hub going to ON - my port is suspended, waking up onThread(%s)", this, _workLoop->onThread() ? "true" : "false");
_device->SuspendDevice(false);
retries = 20;
do {
IOSleep(20);
} while (_portSuspended && (retries-- > 0));
IOSleep(_hubResumeRecoveryTime); if (retries == 0)
{
USBError(1, "AppleUSBHub[%p]::HubPowerChange - hub going to ON - my port is suspended, could not wake it up! onThread(%s)", this, _workLoop->onThread() ? "true" : "false");
}
}
if (!_ports)
{
err = AllocatePortMemory();
if (err)
{
USBError(1,"AppleUSBHub[%p]::HubPowerChange - AllocatePortMemory failed with %p", this, (void*)err);
}
}
if (_myPowerState < kIOUSBHubPowerStateLowPower)
{
err = StartPorts();
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBHub[%p]::HubPowerChange - StartPorts failed with 0x%x", this, err);
break;
}
}
if (_timerSource)
{
_timerSource->setTimeoutMS(kWatchdogTimerPeriod);
}
if ( !_isRootHub && _interruptPipe)
_interruptPipe->ClearPipeStall(true);
_abortExpected = false;
_needInterruptRead = true;
break;
case kIOUSBHubPowerStateLowPower:
if ( _dontAllowLowPower )
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange - hub going to doze - but this hub does NOT allow it", this);
break;
}
if (_myPowerState > kIOUSBHubPowerStateLowPower) {
if (_portSuspended)
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange ((hub @ 0x%x) - hub going to doze - my port is suspended! UNEXPECTED", this, (uint32_t)_locationID);
break;
}
if (!HubAreAllPortsDisconnectedOrSuspended())
{
UInt32 portIndex, portNum;
IOUSBHubPortStatus portStatus;
bool realError = false;
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
IOReturn kr;
portNum = portIndex + 1;
kr = GetPortStatus(&portStatus, portNum);
if ( kr == kIOReturnSuccess )
{
if ( (portStatus.changeFlags == 0) && (portStatus.statusFlags & kHubPortConnection) && (portStatus.statusFlags & kHubPortEnabled) && !(portStatus.statusFlags & kHubPortSuspend))
{
USBLog(1, "AppleUSBHub[%p](0x%x)::HubPowerChange - port %d (status: 0x%x change: 0x%x) connected, enabled and not suspended - UNEXPECTED", this, (uint32_t)_locationID, (uint32_t)portNum, portStatus.statusFlags, portStatus.changeFlags);
realError = true;
break;
}
}
}
if (!realError)
{
USBLog(2, "AppleUSBHub[%p]::HubPowerChange (hub @ 0x%x) - hub going to doze - some port has a recent status change - we will pick it up later. Calling EnsureUsability()", this, (uint32_t)_locationID);
EnsureUsability();
}
}
else
{
if ( _device && !_isRootHub)
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - calling SuspendDevice", this);
err = _device->SuspendDevice(true);
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - done with SuspendDevice", this);
if ( err == kIOReturnSuccess )
{
_portSuspended = true;
}
else
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange SuspendDevice returned %p", this, (void*)err );
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange _isRootHub or _device was NULL", this );
}
}
}
_needInterruptRead = false;
break;
case kIOUSBHubPowerStateSleep:
if (_hubIsDead)
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange - hub is dead, so just acknowledge the HubPowerChange", this);
break;
}
if (!(_device->GetHubCharacteristics() & kIOUSBHubDeviceCanSleep))
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange - hub doesn't support sleep, don't do anything on Suspend", this);
break;
}
if (_timerSource)
{
_timerSource->cancelTimeout();
}
if (!_portSuspended)
{
err = SuspendPorts();
if ( err != kIOReturnSuccess )
{
USBError(1,"AppleUSBHub[%p]::HubPowerChange - SuspendPorts failed with 0x%x", this, err);
break;
}
if ( _device && !_isRootHub)
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - calling SuspendDevice", this);
err = _device->SuspendDevice(true);
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - done with SuspendDevice", this);
if ( err == kIOReturnSuccess )
{
_portSuspended = true;
}
else
{
USBLog(1, "AppleUSBHub[%p]::HubPowerChange SuspendDevice returned %p", this, (void*)err );
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange _isRootHub or _device was NULL - not suspending", this );
if ( _interruptPipe )
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - aborting pipe!!", this);
_abortExpected = true;
_interruptPipe->Abort();
}
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - device already suspended - no need to do it again", this );
}
_needInterruptRead = false;
break;
case kIOUSBHubPowerStateOff:
case kIOUSBHubPowerStateRestart:
StopPorts();
_needInterruptRead = false;
break;
default:
USBError(1, "AppleUSBHub[%p]::HubPowerChange - unknown ordinal (%d)", this, (int)powerStateOrdinal);
}
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - done _needInterruptRead(%s) _outstandingResumes(%d)", this, _needInterruptRead ? "true" : "false", (int)_outstandingResumes);
if (_outstandingResumes)
{
USBLog(5, "AppleUSBHub[%p]::HubPowerChange - with outstanding resumes - spawning thread and returning kIOPMWillAckLater", this);
_needToAckSetPowerState = true;
IncrementOutstandingIO();
if (thread_call_enter(_waitForPortResumesThread) == TRUE)
{
USBLog(1,"AppleUSBHub[%p]::HubPowerChange - _waitForPortResumesThread already queued", this);
DecrementOutstandingIO();
}
ret = kIOPMWillAckLater;
}
return ret;
}
bool
AppleUSBHub::HubAreAllPortsDisconnectedOrSuspended()
{
UInt32 portIndex, portNum;
IOUSBHubPortStatus portStatus;
IOReturn kr;
AppleUSBHubPort *port;
bool returnValue = true;
USBLog(7, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - _myPowerState(%d)", this, (int)_myPowerState);
if (!_ports)
{
USBLog(3, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - no _ports - returning false", this);
return false;
}
if (_hubHasBeenDisconnected || isInactive() || _hubIsDead || (_myPowerState < kIOUSBHubPowerStateLowPower))
{
USBLog(3, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - hub has been disconnected or is inActive or dead or sleeping - returning false", this);
return false;
}
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex + 1;
if (!_ports)
{
USBLog(1, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - the _ports went away - bailing", this);
returnValue = false;
break;
}
port = _ports ? _ports[portIndex] : NULL;
if (!port)
{
USBLog(3, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - no port at index (%d) - returning false", this, (int)portIndex);
returnValue = false;
break;
}
if ((port->_initThreadActive) || (port->_statusChangedThreadActive))
{
USBLog(3, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - port %d still initing or status changing", this, (uint32_t)portNum);
returnValue = false;
break;
}
kr = GetPortStatus( &portStatus, portNum);
if ( kr == kIOReturnSuccess )
{
USBLog(4, "AppleUSBHub[%p]::HubAreAllPortsDisconnectedOrSuspended - _ports(%p) port(%d) status(%p) change(%p) portDevice(%p)", this, _ports, (uint32_t)portNum, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags, port->_portDevice);
if ((portStatus.statusFlags & kHubPortPower) == 0)
{
USBLog(1, "AppleUSBHub[%p](0x%x)::HubAreAllPortsDisconnectedOrSuspended - port %d is not powered on! portPMState=%d", this, (uint32_t)_locationID, (uint32_t)portNum, port->_portPMState);
port->start();
port->_portPMState = usbHPPMS_active;
}
if ( (portStatus.statusFlags & kHubPortConnection) && !(portStatus.statusFlags & kHubPortSuspend) || (portStatus.changeFlags))
{
USBLog(7, "AppleUSBHub[%p](0x%x)::HubAreAllPortsDisconnectedOrSuspended - port %d enabled and not suspended or there is a change", this, (uint32_t)_locationID, (uint32_t)portNum);
returnValue = false;
break;
}
if (portStatus.statusFlags & kHubPortOverCurrent)
{
USBLog(5, "AppleUSBHub[%p](0x%x)::HubAreAllPortsDisconnectedOrSuspended - port %d as an active overcurrent condition. returning FALSE", this, (uint32_t)_locationID, (uint32_t)portNum);
returnValue = false;
break;
}
}
else
{
USBLog(1,"AppleUSBHub[%p](0x%x)::HubAreAllPortsDisconnectedOrSuspended GetPortStatus for port %d returned 0x%x", this, (uint32_t)_locationID, (uint32_t)portNum, kr);
returnValue = false;
break;
}
}
Exit:
USBLog(7, "AppleUSBHub[%p](0x%x)::HubAreAllPortsDisconnectedOrSuspended - returning (%s)", this, (uint32_t)_locationID, returnValue ? "true" : "false");
return returnValue;
}
bool
AppleUSBHub::IsPortInitThreadActiveForAnyPort()
{
UInt32 currentPort;
IOUSBHubPortStatus portStatus;
IOReturn kr;
AppleUSBHubPort *port;
bool returnValue = false;
if (!_ports)
{
USBLog(3, "AppleUSBHub[%p]::IsPortInitThreadActiveForAnyPort - no _ports - returning false", this);
return false;
}
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort-1] : NULL;
if (!port)
{
USBLog(3, "AppleUSBHub[%p]::IsPortInitThreadActiveForAnyPort - no port object[index: %d]", this, (int)currentPort-1);
continue;
}
if ( port->_initThreadActive)
{
USBLog(4, "AppleUSBHub[%p]::IsPortInitThreadActiveForAnyPort - port(%d) had the initThreadActive(%d)", this, (int)currentPort, port->_initThreadActive);
returnValue = true;
break;
}
}
USBLog(6, "AppleUSBHub[%p](0x%x)::IsPortInitThreadActiveForAnyPort - %s", this, (uint32_t)_locationID, returnValue ? "true" : "false");
return returnValue;
}
bool
AppleUSBHub::IsStatusChangedThreadActiveForAnyPort()
{
UInt32 currentPort;
IOUSBHubPortStatus portStatus;
IOReturn kr;
AppleUSBHubPort *port;
bool returnValue = false;
if (!_ports)
{
USBLog(3, "AppleUSBHub[%p]::IsStatusChangedThreadActiveForAnyPort - no _ports - returning false", this);
return false;
}
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort-1] : NULL;
if (!port)
{
USBLog(3, "AppleUSBHub[%p]::IsStatusChangedThreadActiveForAnyPort - no port object[index: %d]", this, (int)currentPort-1);
continue;
}
if ( port->_statusChangedThreadActive)
{
USBLog(4, "AppleUSBHub[%p]::IsStatusChangedThreadActiveForAnyPort - port(%d) had the _statusChangedThreadActive(%d)", this, (int)currentPort, port->_statusChangedThreadActive);
returnValue = true;
break;
}
}
USBLog(6, "AppleUSBHub[%p](0x%x)::IsStatusChangedThreadActiveForAnyPort - %s", this, (uint32_t)_locationID, returnValue ? "true" : "false");
return returnValue;
}
#pragma mark ееееееее Ports ееееееее
IOReturn
AppleUSBHub::StartPorts(void)
{
AppleUSBHubPort *port;
int portIndex, portNum;
IOReturn err;
bool resumedOneAlready = false;
bool workToDo = true; bool needsPowerSequencingDelay = false;
bool needsInitialDelay = true;
USBLog(5, "AppleUSBHub[%p]::StartPorts - _bus[%p] starting (%d) ports isInactive(%s)", this, _bus, _hubDescriptor.numPorts, isInactive() ? "true" : "false");
if (!_ports)
{
USBError(1, "AppleUSBHub[%p]::StartPorts - no memory for ports!!", this);
return kIOReturnNoMemory;
}
if (isInactive())
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - we are inactive. Nothing to do.", this);
return kIOReturnSuccess;
}
OSBoolean * boolObj = OSDynamicCast( OSBoolean, _device->getProperty("kHubPowerSequencingDelay") );
needsPowerSequencingDelay = ( boolObj && boolObj->isTrue() );
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex+1;
port = _ports ? _ports[portIndex] : NULL;
if (port)
{
port->retain();
if (port->_portPMState == usbHPPMS_uninitialized)
{
if (needsInitialDelay)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts _bus[%p] -at least one unititialized port, calling RaisePowerState and spawning initialDelayThread", this, _bus);
needsInitialDelay = false;
RaisePowerState();
IncrementOutstandingIO();
if (thread_call_enter(_initialDelayThread) == TRUE)
{
USBLog(1, "AppleUSBHub[%p]::StartPorts - InitialDelayThread already queued - UNEXPECTED!", this);
LowerPowerState();
DecrementOutstandingIO();
}
}
if (needsPowerSequencingDelay)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - _bus[%p] port (%d) power sequence delay for %d ms", this, _bus, portNum, _hubDescriptor.powerOnToGood *2);
IOSleep(_hubDescriptor.powerOnToGood*2); }
USBLog(5, "AppleUSBHub[%p]::StartPorts - _bus[%p] port (%d) uninitialized - calling port->start", this, _bus, portNum);
port->start();
port->_portPMState = usbHPPMS_active;
USBLog(5, "AppleUSBHub[%p]::StartPorts - _bus[%p] port[%p] now in state[%d]", this, _bus, port, port->_portPMState);
}
else if (port->_portPMState == usbHPPMS_pm_suspended)
{
IOUSBHubPortStatus portStatus;
bool enableEndpoints = false;
USBLog(5, "AppleUSBHub[%p]::StartPorts - port[%p] number (%d) suspended by PM - calling GetPortStatus", this, port, portNum);
portStatus.statusFlags = 0;
portStatus.changeFlags = 0;
err = GetPortStatus(&portStatus, portNum);
if (err)
{
USBLog((err == kIOReturnNoDevice) ? 5 : 1, "AppleUSBHub[%p]::StartPorts - err (%p) from GetPortStatus for port (%d) isInactive(%s) - reneabling endpoints anyway", this, (void*)err, portNum, isInactive() ? "true" : "false");
enableEndpoints = true;
}
else if ((portStatus.changeFlags & kHubPortSuspend) || (portStatus.changeFlags & kHubPortConnection))
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - port[%p], which is number[%d] has the kHubPortSuspendChange bit or kHubPortConnectionChange already set (probably unplugged) status[%p] change[%p] - won't have to wait! YAY!", this, port, portNum, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
if (portStatus.changeFlags & kHubPortSuspend)
ClearPortFeature(kUSBHubPortSuspendChangeFeature, portNum);
enableEndpoints = true;
}
else if (!(portStatus.statusFlags & kHubPortSuspend))
{
USBLog(3, "AppleUSBHub[%p]::StartPorts - port %d marked as suspended, but the suspend status bit is not set status[%p] change[%p] _portDevice name[%s]", this, (int)portNum, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags, port->_portDevice ? port->_portDevice->getName() : "no device");
enableEndpoints = true; }
else
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - port[%p] number (%d) suspended by PM statusFlags[%p] - calling SuspendPort(false)", this, port, portNum, (void*)portStatus.statusFlags);
if (!resumedOneAlready)
{
err = port->SuspendPort(false, false);
resumedOneAlready = true;
}
else
err = kIOReturnSuccess;
if (err == kIOReturnNotResponding)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - got err kIOReturnNotResponding from SuspendPort- we must be dead! aborting StartPorts", this);
break;
}
if (err != kIOReturnSuccess)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - got err %p from SuspendPort- perhaps we need to deal with this!", this, (void*)err);
}
else
{
USBLog(6, "AppleUSBHub[%p]::StartPorts - calling IncrementOutstandingIO and IncrementOutstandingResumes", this);
IncrementOutstandingIO();
IncrementOutstandingResumes();
}
}
if (enableEndpoints)
{
IOUSBControllerV3 *v3Bus = NULL;
IOReturn err;
IOSleep(port->_portResumeRecoveryTime);
if (_device)
v3Bus = OSDynamicCast(IOUSBControllerV3, _device->GetBus());
if (v3Bus && port->_portDevice)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - Enabling endpoints for device at address (%d)", this, (int)port->_portDevice->GetAddress());
err = v3Bus->EnableAddressEndpoints(port->_portDevice->GetAddress(), true);
if (err)
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - EnableAddressEndpoints returned (%p)", this, (void*)err);
}
}
port->_portPMState = usbHPPMS_active;
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::StartPorts - port[%p] number (%d) in PMState (%d) _portDevice[%p] - nothing to do", this, port, portNum, port->_portPMState, port->_portDevice);
}
port->release();
}
else
{
USBError(1, "AppleUSBHub[%p]::StartPorts - port (%d) unexpectedly missing", this, portNum);
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBHub::SuspendPorts(void)
{
AppleUSBHubPort *port;
int currentPort;
IOReturn err;
IOUSBControllerV3 *v3Bus;
USBLog(5, "AppleUSBHub[%p]::SuspendPorts - (%d) ports", this, _hubDescriptor.numPorts);
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort-1] : NULL;
if (port)
{
port->retain();
if ((port->_portPMState == usbHPPMS_active) && (port->_portDevice))
{
USBLog(5, "AppleUSBHub[%p]::SuspendPorts - suspending port[%p] number (%d) - need to disable device (%p) named(%s)", this, port, currentPort, port->_portDevice, port->_portDevice ? port->_portDevice->getName() : "NULL");
v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
if (v3Bus)
{
err = v3Bus->EnableAddressEndpoints(port->_portDevice->GetAddress(), false);
if (err)
{
USBLog(2, "AppleUSBHub[%p]::SuspendPorts - EnableAddressEndpoints returned (%p)", this, (void*)err);
}
}
err = port->SuspendPort(true, false);
if (err)
{
USBLog(1, "AppleUSBHub[%p]::SuspendPorts - err [%p] suspending port (%d)", this, (void*)err, currentPort);
}
else
{
port->_portPMState = usbHPPMS_pm_suspended;
USBLog(5, "AppleUSBHub[%p]::SuspendPorts - port[%p] now in state[%d]", this, port, port->_portPMState);
}
}
else
{
USBLog(5, "AppleUSBHub[%p]::SuspendPorts - port (%d) in _portPMState (%d) _portDevice(%p) - not calling port->SuspendPort", this, currentPort, port->_portPMState, port->_portDevice);
}
port->release();
}
else
{
USBError(1, "AppleUSBHub[%p]::SuspendPorts - port (%d) unexpectedly missing", this, currentPort);
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBHub::StopPorts(void)
{
AppleUSBHubPort * port;
AppleUSBHubPort ** cachedPorts;
int currentPort;
USBLog(5, "AppleUSBHub[%p]::+StopPorts - (%d) ports total", this, _hubDescriptor.numPorts);
if ( _interruptPipe )
{
USBLog(5, "AppleUSBHub[%p]::StopPorts - aborting pipe", this);
_abortExpected = true;
_needInterruptRead = false;
_interruptPipe->Abort();
USBLog(5, "AppleUSBHub[%p]::StopPorts - done aborting pipe", this);
}
if( _ports)
{
cachedPorts = _ports;
_ports = NULL;
for (currentPort = 0; currentPort < _hubDescriptor.numPorts; currentPort++)
{
port = cachedPorts[currentPort];
if (port)
{
cachedPorts[currentPort] = NULL;
USBLog(5, "AppleUSBHub[%p]::StopPorts - calling stop on port (%p)", this, port);
port->stop();
USBLog(5, "AppleUSBHub[%p]::StopPorts - calling release on port (%p)", this, port);
port->release();
}
}
IOFree(cachedPorts, sizeof(AppleUSBHubPort *) * _hubDescriptor.numPorts);
}
return kIOReturnSuccess;
}
bool
AppleUSBHub::HubStatusChanged(void)
{
IOReturn err = kIOReturnSuccess;
USBLog(6,"+AppleUSBHub[%p]::HubStatusChanged - calling IncrementOutstandingIO", this);
IncrementOutstandingIO();
do
{
if ((err = GetHubStatus(&_hubStatus)))
{
FatalError(err, "get status (first in hub status change)");
break;
}
_hubStatus.statusFlags = USBToHostWord(_hubStatus.statusFlags);
_hubStatus.changeFlags = USBToHostWord(_hubStatus.changeFlags);
USBLog(3,"AppleUSBHub[%p]::HubStatusChanged - _isRootHub(%s) hub status = %x/%x", this, _isRootHub ? "true" : "false", _hubStatus.statusFlags, _hubStatus.changeFlags);
if (_hubStatus.changeFlags & kHubLocalPowerStatusChange)
{
USBLog(3, "AppleUSBHub[%p]: Hub Local Power Status Change detected", this);
if ((err = ClearHubFeature(kUSBHubLocalPowerChangeFeature)))
{
FatalError(err, "clear hub power status feature");
break;
}
if ((err = GetHubStatus(&_hubStatus)))
{
FatalError(err, "get status (second in hub status change)");
break;
}
_hubStatus.statusFlags = USBToHostWord(_hubStatus.statusFlags);
_hubStatus.changeFlags = USBToHostWord(_hubStatus.changeFlags);
USBLog(3,"AppleUSBHub[%p]: hub status after clearing LocalPowerChange = %x/%x", this, _hubStatus.statusFlags, _hubStatus.changeFlags);
}
if (_hubStatus.changeFlags & kHubOverCurrentIndicatorChange)
{
_device->DisplayUserNotification(kUSBGangOverCurrentNotificationType);
USBLog(3, "AppleUSBHub[%p]: Hub OverCurrent detected", this);
if ((err = ClearHubFeature(kUSBHubOverCurrentChangeFeature)))
{
FatalError(err, "clear hub over-current feature");
break;
}
IOSleep(3000); if ((err = GetHubStatus(&_hubStatus)))
{
FatalError(err, "get status (second in hub status change)");
break;
}
_hubStatus.statusFlags = USBToHostWord(_hubStatus.statusFlags);
_hubStatus.changeFlags = USBToHostWord(_hubStatus.changeFlags);
USBLog(3,"AppleUSBHub[%p]: hub status after clearing HubOvercurrent = %x/%x", this, _hubStatus.statusFlags, _hubStatus.changeFlags);
}
OSBoolean * boolObj = OSDynamicCast( OSBoolean, _device->getProperty("kResetOnPowerStatusChange") );
if ( boolObj && boolObj->isTrue() )
{
if ( _hubStatus.statusFlags & ( kUSBHubLocalPowerChangeFeature || kHubOverCurrentIndicatorChange ) )
{
USBLog(3,"AppleUSBHub[%p]::HubStatusChanged - change to ON (0x%x)", this, _hubStatus.statusFlags);
err = kIOReturnBusy;
}
}
} while(false);
if ( err != kIOReturnSuccess )
{
USBLog(1, "AppleUSBHub[%p]::HubStatusChanged - err (%p) - reseting my port", this, (void*)err);
retain();
ResetMyPort();
release();
}
USBLog(6,"-AppleUSBHub[%p]::HubStatusChanged calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
USBLog(6,"-AppleUSBHub[%p]::HubStatusChanged returning %s", this, err == kIOReturnSuccess ? "true" : "false");
return (err == kIOReturnSuccess);
}
UInt32
AppleUSBHub::GetHubErrataBits()
{
UInt16 vendID, deviceID, revisionID;
ErrataListEntry *entryPtr;
UInt32 i, errata = 0;
vendID = _device->GetVendorID();
deviceID = _device->GetProductID();
revisionID = _device->GetDeviceRelease();
for(i=0, entryPtr = errataList; i < errataListLength; i++, entryPtr++)
{
if (vendID == entryPtr->vendID
&& deviceID == entryPtr->deviceID
&& revisionID >= entryPtr->revisionLo
&& revisionID <= entryPtr->revisionHi)
{
errata |= entryPtr->errata; }
}
return(errata);
}
void
AppleUSBHub::FatalError(IOReturn err, const char *str)
{
USBError(1, "AppleUSBHub[%p]::FatalError 0x%x: %s", this, err, str);
}
IOReturn
AppleUSBHub::GetHubDescriptor(IOUSBHubDescriptor *desc)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
if (!desc) return (kIOReturnBadArgument);
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBDevice);
request.bRequest = kUSBRqGetDescriptor;
request.wValue = (kUSBHubDescriptorType << 8) + 0; request.wIndex = 0;
request.wLength = sizeof(IOUSBHubDescriptor);
request.pData = desc;
err = DoDeviceRequest(&request);
if (err)
{
USBLog(5,"AppleUSBHub[%p]: GetHubDescriptor w/ type = %X returned error: 0x%x", this, kUSBHubDescriptorType, err);
request.wValue = 0;
request.wLength = sizeof(IOUSBHubDescriptor);
err = DoDeviceRequest(&request);
}
if (err)
{
USBLog(3, "AppleUSBHub [%p] GetHubDescriptor error = 0x%x", this, err);
}
return(err);
}
IOReturn
AppleUSBHub::GetHubStatus(IOUSBHubStatus *status)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBDevice);
request.bRequest = kUSBRqGetStatus;
request.wValue = 0;
request.wIndex = 0;
request.wLength = sizeof(IOUSBHubStatus);
request.pData = status;
err = DoDeviceRequest(&request);
if (err)
{
USBLog(3, "AppleUSBHub [%p] GetHubStatus error = 0x%x", this, err);
}
return(err);
}
IOReturn
AppleUSBHub::GetPortState(UInt8 *state, UInt16 port)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBOther);
request.bRequest = kUSBRqGetState;
request.wValue = 0;
request.wIndex = port;
request.wLength = sizeof(*state);
request.pData = state;
USBLog(7, "AppleUSBHub[%p]::GetPortState - issuing DeviceRequest", this);
err = DoDeviceRequest(&request);
if (err)
{
USBLog(3, "AppleUSBHub [%p] GetPortState error = 0x%x", this, err);
}
return(err);
}
IOReturn
AppleUSBHub::ClearHubFeature(UInt16 feature)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBDevice);
request.bRequest = kUSBRqClearFeature;
request.wValue = feature;
request.wIndex = 0;
request.wLength = 0;
request.pData = NULL;
USBLog(7, "AppleUSBHub[%p]::ClearHubFeature - issuing DeviceRequest", this);
err = DoDeviceRequest(&request);
if (err)
{
USBLog(3, "AppleUSBHub [%p] ClearHubFeature error = 0x%x", this, err);
}
return(err);
}
IOReturn
AppleUSBHub::GetPortStatus(IOUSBHubPortStatus *status, UInt16 port)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
int i = 0;
request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBClass, kUSBOther);
request.bRequest = kUSBRqGetStatus;
request.wValue = 0;
request.wIndex = port;
request.wLength = sizeof(IOUSBHubPortStatus);
request.pData = status;
request.wLenDone = 0;
USBLog(7, "AppleUSBHub[%p]::GetPortStatus - issuing DeviceRequest", this);
err = DoDeviceRequest(&request);
while ((i++ < 30) && !err && (request.wLenDone != sizeof(IOUSBHubPortStatus)))
{
USBLog(2, "AppleUSBHub[%p]::GetPortStatus - request came back with only %d bytes - retrying", this, (int)request.wLenDone);
err = DoDeviceRequest(&request);
}
if (!err && (request.wLenDone != sizeof(IOUSBHubPortStatus)))
{
USBLog(2, "AppleUSBHub[%p]::GetPortStatus - request never returned bytes in %d tries - returning kIOReturnUnderrun", this, i);
err = kIOReturnUnderrun;
}
if (err)
{
USBLog(3, "AppleUSBHub[%p]::GetPortStatus, error (%x) returned from DoDeviceRequest", this, err);
}
if ( err == kIOReturnSuccess)
{
status->statusFlags = USBToHostWord(status->statusFlags);
status->changeFlags = USBToHostWord(status->changeFlags);
USBLog( 7, "AppleUSBHub[%p]::GetPortStatus for port %d, status: 0x%8x, change: 0x%8x - returning kIOReturnSuccess", this, port, status->statusFlags, status->changeFlags);
}
return(err);
}
IOReturn
AppleUSBHub::SetPortFeature(UInt16 feature, UInt16 port)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
USBLog(5, "AppleUSBHub[%p]::SetPortFeature port/feature (%x) - setting", this, (port << 16) | feature);
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBOther);
request.bRequest = kUSBRqSetFeature;
request.wValue = feature;
request.wIndex = port;
request.wLength = 0;
request.pData = NULL;
err = DoDeviceRequest(&request);
if (err && (err != kIOUSBDeviceNotHighSpeed))
{
USBLog(1, "AppleUSBHub[%p]::SetPortFeature (%d) to port %d got error (%x) from DoDeviceRequest", this, feature, port, err);
}
return(err);
}
IOReturn
AppleUSBHub::ClearPortFeature(UInt16 feature, UInt16 port)
{
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
USBLog(5, "AppleUSBHub[%p]::ClearPortFeature port/feature (%x) - clearing", this, (port << 16) | feature);
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBClass, kUSBOther);
request.bRequest = kUSBRqClearFeature;
request.wValue = feature;
request.wIndex = port;
request.wLength = 0;
request.pData = NULL;
err = DoDeviceRequest(&request);
if (err)
{
USBLog(1, "AppleUSBHub[%p]::ClearPortFeature got error (%x) to DoDeviceRequest", this, err);
}
return err;
}
IOReturn
AppleUSBHub::DoPortAction(UInt32 type, UInt32 portNumber, UInt32 options )
{
AppleUSBHubPort *port;
IOReturn err = kIOReturnSuccess;
bool tryWakingUp = true;
UInt32 portIndex = portNumber - 1;
if (isInactive() || _hubIsDead)
{
USBLog(3, "AppleUSBHub[%p]::DoPortAction - isInactive(%s) _hubIsDead(%s) - returning kIOReturnNotResponding", this, isInactive() ? "true" : "false", _hubIsDead ? "true" : "false");
err = kIOReturnNotResponding;
}
else
{
if (_myPowerState < kIOUSBHubPowerStateOn)
{
if (_powerStateChangingTo != kIOUSBHubPowerStateStable)
{
if ((unsigned long)_powerStateChangingTo != kIOUSBHubPowerStateOn)
{
USBLog(5,"AppleUSBHub[%p]::DoPortAction - we are already in the process of changing to state (%d) - unable to wake up - returning not responding", this, (int)_powerStateChangingTo);
tryWakingUp = false;
}
}
else if (_myPowerState < kIOUSBHubPowerStateLowPower)
{
USBLog(5,"AppleUSBHub[%p]::DoPortAction - not while we are asleep - _myPowerState(%d) - returning not responding", this, (int)_myPowerState);
tryWakingUp = false;
}
if (!tryWakingUp)
{
USBLog(2, "AppleUSBHub[%p]::DoPortAction - _myPowerState(%d) _powerStateChangingTo(%d) - returning kIOReturnNotResponding", this, (int)_myPowerState, (int)_powerStateChangingTo);
err = kIOReturnNotResponding;
port = _ports ? _ports[portIndex] : NULL;
if (port && port->_portDevice)
{
USBLog(5,"AppleUSBHub[%p]::DoPortAction - _portDevice name is %s", this, port->_portDevice->getName());
}
}
}
}
if (err == kIOReturnSuccess)
{
SInt32 retries = 200;
USBLog(6,"AppleUSBHub[%p]::DoPortAction - calling RaisePowerState", this);
RaisePowerState();
while (((_myPowerState < kIOUSBHubPowerStateOn) || (_powerStateChangingTo == kIOUSBHubPowerStateLowPower)) && retries--)
{
USBLog(5,"AppleUSBHub[%p]::DoPortAction - waiting for power state to go up (onThread is %s)", this, _workLoop->onThread() ? "true" : "false");
IOSleep(10);
}
if (retries <= 0)
{
USBLog(3,"AppleUSBHub[%p]::DoPortAction - waited 2 seconds - _myPowerState(%d) _powerStateChangingTo(%d)", this, (int)_myPowerState, (int)_powerStateChangingTo);
}
if (_myPowerState < kIOUSBHubPowerStateOn)
{
USBLog(3,"AppleUSBHub[%p]::DoPortAction - could not get power state up - returning kIOReturnNotResponding", this);
err = kIOReturnNotResponding;
}
else if ( _portSuspended && _device )
{
USBLog(5,"AppleUSBHub[%p]::DoPortAction(%s) for port (%d), unsuspending port", this, HubMessageToString(type), (uint32_t)portNumber);
err = _device->SuspendDevice(false);
if ( err == kIOReturnSuccess )
{
IOSleep(_hubResumeRecoveryTime); }
}
if ( err != kIOReturnSuccess )
{
USBLog(3,"AppleUSBHub[%p]::DoPortAction - err(%p) calling LowerPowerState", this, (void*)err);
LowerPowerState();
}
}
if ((_ports == NULL ) && (err == kIOReturnSuccess))
{
USBLog(1,"AppleUSBHub[%p]::DoPortAction _ports is NULL! - calling LowerPowerState and returning kIOReturnNoDevice", this);
LowerPowerState(); err = kIOReturnNoDevice;
}
if (err != kIOReturnSuccess)
{
USBLog(5, "AppleUSBHub[%p]::DoPortAction - unable to find success in the setup - err(%p)", this, (void*)err);
if ((type == kIOUSBMessageHubResumePort) || (type == kIOUSBMessageHubSuspendPort))
{
IOUSBDevice *cachedDevice; USBLog(2, "AppleUSBHub[%p]::DoPortAction - err(%p) message was %s - need to send a message", this, (void*)err, HubMessageToString(type));
port = _ports ? _ports[portIndex] : NULL;
cachedDevice = port ? port->_portDevice : NULL;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortWasNotSuspended, cachedDevice, NULL);
cachedDevice->release();
}
else
{
USBLog(2, "AppleUSBHub[%p]::DoPortAction - err(%p) - message was %s - no portDevice to send message to", this, (void*)err, HubMessageToString(type));
}
}
return err;
}
USBLog(5,"+AppleUSBHub[%p]::DoPortAction(%s) for port (%d), options (0x%x) _myPowerState(%d), getting _doPortActionLock", this, HubMessageToString(type), (uint32_t)portNumber, (uint32_t)options, (uint32_t)_myPowerState);
err = TakeDoPortActionLock();
if (err != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHub[%p]::DoPortAction - unable to take the DoPortAction lock (err %p)", this, (void*)err);
return err;
}
port = _ports ? _ports[portIndex] : NULL;
if (port)
{
port->retain();
USBLog(5,"AppleUSBHub[%p]::DoPortAction(%s) for port (%d), options (0x%x) _portPMState (%d)", this, HubMessageToString(type), (uint32_t)portNumber, (uint32_t)options, port->_portPMState);
switch ( type )
{
case kIOUSBMessageHubSuspendPort:
err = port->SuspendPort( true, true );
USBLog(5, "AppleUSBHub[%p]::DoPortAction - port[%p] now in state[%d]", this, port, port->_portPMState);
break;
case kIOUSBMessageHubResumePort:
EnsureUsability();
err = port->SuspendPort( false, true );
USBLog(5, "AppleUSBHub[%p]::DoPortAction - port[%p] now in state[%d]", this, port, port->_portPMState);
if (!err && (_myPowerState == kIOUSBHubPowerStateLowPower))
{
if (!_isRootHub)
{
USBError(1, "AppleUSBHub[%p]::DoPortAction - resuming port, but we are not a root hub - shouldn't be here", this);
}
else
{
int retries = 5000;
IOUSBHubPortStatus portStatus;
USBLog(5, "AppleUSBHub[%p]::DoPortAction - sleeping 20ms for the resume - onThread(%s)", this, _workLoop->onThread() ? "true" : "false");
IOSleep(20);
err = GetPortStatus(&portStatus, portNumber);
while (!err && retries-- > 0)
{
USBLog(5, "AppleUSBHub[%p]::DoPortAction - got statusFlags(%p) changeFlags(%p)", this, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
if (portStatus.changeFlags & kHubPortSuspend)
{
ClearPortFeature(kUSBHubPortSuspendChangeFeature, portNumber);
USBLog(3, "AppleUSBHub[%p]::DoPortAction - port[%p], which is number[%d] has the suspend change bit set- good - statusFlags[%p] and changeFlags[%p]", this, port, (int)portNumber, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
port->_portPMState = usbHPPMS_active;
port->_resumePending = false;
if ( port->_portDevice)
{
IOUSBDevice *cachedDevice = port->_portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenResumed, cachedDevice, NULL);
cachedDevice->release();
}
}
break;
}
USBLog(3, "AppleUSBHub[%p]::DoPortAction - port still not resumed - sleeping 1ms before trying again - retries left (%d)", this, retries);
IOSleep(1);
err = GetPortStatus(&portStatus, portNumber);
}
}
}
break;
case kIOUSBMessageHubReEnumeratePort:
err = port->ReEnumeratePort(options);
break;
case kIOUSBMessageHubResetPort:
err = port->ResetPort();
break;
case kIOUSBMessageHubPortClearTT:
if ( _hsHub )
err = port->ClearTT(_multiTTs, options);
else
err = kIOReturnUnsupported;
break;
case kIOUSBMessageHubSetPortRecoveryTime:
break;
}
port->release();
}
IncrementOutstandingIO();
ReleaseDoPortActionLock();
DecrementOutstandingIO();
USBLog(6,"AppleUSBHub[%p]::DoPortAction - calling LowerPowerState", this);
LowerPowerState();
if (!isInactive() && !_hubIsDead && !_checkPortsThreadActive && (type == kIOUSBMessageHubSuspendPort))
{
_abandonCheckPorts = false;
_checkPortsThreadActive = true;
retain(); USBLog(5,"AppleUSBHub[%p]::DoPortAction - spawning _checkForActivePortsThread", this);
if ( thread_call_enter(_checkForActivePortsThread) == TRUE )
{
USBLog(1,"AppleUSBHub[%p]::DoPortAction - _checkForActivePortsThread already queued", this);
release();
}
}
USBLog(5,"-AppleUSBHub[%p]::DoPortAction(%s) for port (%d), returning 0x%x", this, HubMessageToString(type), (uint32_t)portNumber, err);
return err;
}
void
AppleUSBHub::InterruptReadHandlerEntry(OSObject *target, void *param, IOReturn status, UInt32 bufferSizeRemaining)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
USBLog(7, "AppleUSBHub[%p]::InterruptReadHandlerEntry", me);
me->InterruptReadHandler(status, bufferSizeRemaining);
USBLog(6, "AppleUSBHub[%p]::InterruptReadHandlerEntry - calling DecrementOutstandingIO", me);
me->DecrementOutstandingIO();
}
void
AppleUSBHub::InterruptReadHandler(IOReturn status, UInt32 bufferSizeRemaining)
{
bool queueAnother = TRUE;
IOReturn err = kIOReturnSuccess;
_interruptReadPending = false;
switch (status)
{
case kIOReturnOverrun:
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler kIOReturnOverrun error", this);
if (!isInactive())
{
if ( _interruptPipe )
{
_interruptPipe->ClearStall();
IncrementOutstandingIO();
if ( thread_call_enter(_clearFeatureEndpointHaltThread) == TRUE )
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler _clearFeatureEndpointHaltThread already queued - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
}
}
}
case kIOReturnSuccess:
_retryCount = kHubDriverRetryCount;
if (!_ports)
{
USBLog(1, "AppleUSBHub[%p]::InterruptReadHandler - avoiding NULL _ports - unlike before!!", this);
}
if ( !_hubIsDead && (_ports != NULL))
{
USBLog(6, "AppleUSBHub[%p]::InterruptReadHandler - calling IncrementOutstandingIO", this);
IncrementOutstandingIO();
USBLog(6, "AppleUSBHub[%p]::InterruptReadHandler - calling EnsureUsability", this);
EnsureUsability(); if ( thread_call_enter(_workThread) == TRUE )
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler _workThread already queued - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
}
}
queueAnother = FALSE;
break;
case kIOReturnNotResponding:
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler error kIOReturnNotResponding", this);
if ( _hubHasBeenDisconnected || isInactive() )
{
queueAnother = false;
}
else
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler Checking to see if hub is still connected", this);
CallCheckForDeadHub();
queueAnother = false;
}
break;
case kIOReturnAborted:
if (isInactive() || _hubIsDead || _abortExpected )
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler error kIOReturnAborted (expected)", this);
queueAnother = false;
}
else
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler error kIOReturnAborted. Try again.", this);
}
break;
case kIOReturnUnderrun:
case kIOUSBPipeStalled:
case kIOUSBLinkErr:
case kIOUSBNotSent2Err:
case kIOUSBNotSent1Err:
case kIOUSBBufferUnderrunErr:
case kIOUSBBufferOverrunErr:
case kIOUSBWrongPIDErr:
case kIOUSBPIDCheckErr:
case kIOUSBDataToggleErr:
case kIOUSBBitstufErr:
case kIOUSBCRCErr:
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler OHCI error (0x%x) reading interrupt pipe", this, status);
if (!isInactive())
{
if ( _interruptPipe )
{
_interruptPipe->ClearStall();
_needInterruptRead = true;
IncrementOutstandingIO();
if ( thread_call_enter(_clearFeatureEndpointHaltThread) == TRUE )
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler _clearFeatureEndpointHaltThread already queued - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
}
}
}
queueAnother = false;
break;
case kIOUSBHighSpeedSplitError:
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler error kIOUSBHighSpeedSplitError", this);
if ( _hubHasBeenDisconnected || isInactive() )
{
queueAnother = false;
}
else
{
USBLog(3, "AppleUSBHub[%p]::InterruptReadHandler Checking to see if hub is still connected", this);
CallCheckForDeadHub();
queueAnother = false;
}
break;
default:
USBLog(3,"AppleUSBHub[%p]::InterruptReadHandler error 0x%x reading interrupt pipe", this, status);
if (isInactive() || ((_powerStateChangingTo != kIOUSBHubPowerStateStable) && (_powerStateChangingTo < kIOUSBHubPowerStateLowPower)) )
queueAnother = false;
else
{
if ( _interruptPipe )
_interruptPipe->ClearStall();
}
break;
}
if ( queueAnother )
{
_needInterruptRead = true;
}
}
void
AppleUSBHub::ResetPortZeroEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
me->ResetPortZero();
me->DecrementOutstandingIO();
}
void
AppleUSBHub::ResetPortZero()
{
AppleUSBHubPort *port;
UInt32 currentPort;
if( _ports)
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort-1] : NULL;
if (port)
{
Boolean locked;
port->retain();
locked = port->GetDevZeroLock();
if ( locked )
{
if ( ((_timeoutFlag & (1 << (currentPort-1))) != 0) && (_portTimeStamp[currentPort-1] == port->GetPortTimeStamp()) )
{
USBLog(1, "AppleUSBHub[%p]::ResetPortZero: - port %d - Releasing devZero lock", this, (uint32_t)currentPort);
_timeoutFlag &= ~( 1<<(currentPort-1));
port->ReleaseDevZeroLock();
}
}
port->release();
}
}
}
void
AppleUSBHub::ProcessStatusChangedEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
me->ProcessStatusChanged();
USBLog(6, "AppleUSBHub[%p]::ProcessStatusChangedEntry - calling DecrementOutstandingIO", me);
me->DecrementOutstandingIO();
}
void
AppleUSBHub::ProcessStatusChanged()
{
const UInt8 * statusChangedBitmapPtr = 0;
int portMask;
int portByte;
int portIndex, portNum;
AppleUSBHubPort *port;
bool portSuccess = false;
bool hubStatusSuccess = true;
if (isInactive() || !_buffer || !_ports)
return;
portMask = 2;
portByte = 0;
statusChangedBitmapPtr = (const UInt8*)_buffer->getBytesNoCopy();
if (statusChangedBitmapPtr == NULL)
{
USBError(1, "AppleUSBHub[%p]::ProcessStatusChanged: No interrupt pipe buffer!", this);
}
else
{
if ( statusChangedBitmapPtr[0] == 0xff)
{
USBLog(5,"AppleUSBHub[%p]::ProcessStatusChanged found (FF) in statusChangedBitmap", this);
}
else
{
_needInterruptRead = true;
if ((statusChangedBitmapPtr[0] & 1) != 0)
{
hubStatusSuccess = HubStatusChanged();
}
if ( hubStatusSuccess )
{
if (isInactive() || !_buffer || !_ports)
{
USBLog(1,"AppleUSBHub[%p]::ProcessStatusChanged - in inner loop - we seem to have gone away. bailing", this);
return;
}
USBLog(6,"AppleUSBHub[%p]::ProcessStatusChanged - calling IncrementOutstandingIO", this);
IncrementOutstandingIO(); USBLog(5,"AppleUSBHub[%p]::ProcessStatusChanged found (0x%8.8x) in statusChangedBitmap", this, statusChangedBitmapPtr[0]);
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex + 1;
if ((statusChangedBitmapPtr[portByte] & portMask) != 0)
{
port = _ports ? _ports[portIndex] : NULL;
if ( port )
{
SInt32 retries = 200;
USBLog(6,"AppleUSBHub[%p]::ProcessStatusChanged. Calling wakeFromDoze", this);
getPMRootDomain()->wakeFromDoze();
USBLog(6,"AppleUSBHub[%p]::ProcessStatusChanged port number %d, calling IncrementOutstandingIO and port->StatusChanged", this, portNum);
IncrementOutstandingIO(); RaisePowerState(); while (((_myPowerState < kIOUSBHubPowerStateOn) || (_powerStateChangingTo == kIOUSBHubPowerStateLowPower)) && retries--)
{
USBLog(5,"AppleUSBHub[%p]::ProcessStatusChanged - waiting for power state to go up (onThread is %s)", this, _workLoop->onThread() ? "true" : "false");
IOSleep(10);
}
if (retries <= 0)
{
USBLog(3,"AppleUSBHub[%p]::ProcessStatusChanged - waited 2 seconds - _myPowerState(%d) _powerStateChangingTo(%d)", this, (int)_myPowerState, (int)_powerStateChangingTo);
}
portSuccess = port->StatusChanged();
if (! portSuccess )
{
USBLog(1,"AppleUSBHub[%p]::ProcessStatusChanged port->StatusChanged() returned false", this);
}
}
}
portMask <<= 1;
if (portMask > 0x80)
{
portMask = 1;
portByte++;
}
}
USBLog(6,"AppleUSBHub[%p]::ProcessStatusChanged - calling DecrementOutstandingIO", this);
DecrementOutstandingIO(); }
else
{
USBLog(1,"AppleUSBHub[%p]::ProcessStatusChanged - hubStatusSuccess(FALSE) - this is weird", this);
}
}
}
}
IOReturn
AppleUSBHub::RearmInterruptRead()
{
IOReturn err = kIOReturnSuccess;
IOUSBCompletion comp;
USBLog(6,"+AppleUSBHub[%p]::RearmInterruptRead", this);
if (_myPowerState < kIOUSBHubPowerStateOn)
{
USBLog(1,"AppleUSBHub[%p]::RearmInterruptRead - unexpected power state (%d)", this, (int)_myPowerState);
_needInterruptRead = true;
return err;
}
USBLog(6,"+AppleUSBHub[%p]::RearmInterruptRead - calling IncrementOutstandingIO", this);
IncrementOutstandingIO();
if (!_ports)
{
USBLog(1, "AppleUSBHub[%p]::RearmInterruptRead - avoiding NULL _ports - unlike before!!", this);
}
if ( isInactive() || (_buffer == NULL) || ( _interruptPipe == NULL ) || (_ports == NULL))
{
DecrementOutstandingIO();
return err;
}
comp.target = this;
comp.action = (IOUSBCompletionAction) InterruptReadHandlerEntry;
comp.parameter = NULL;
_buffer->setLength(_readBytes);
_interruptReadPending = true;
if ((err = _interruptPipe->Read(_buffer, &comp)))
{
USBLog(1,"AppleUSBHub[%p]::RearmInterruptRead error %x reading interrupt pipe - calling DecrementOutstandingIO", this, err);
_interruptReadPending = false;
DecrementOutstandingIO();
}
USBLog(6,"-AppleUSBHub[%p]::RearmInterruptRead", this);
return err;
}
void
AppleUSBHub::PrintHubDescriptor(IOUSBHubDescriptor *desc)
{
int i = 0;
const char *characteristics[] =
{ "ppsw", "nosw", "comp", "ppoc", "nooc", 0 };
if (desc->length == 0) return;
IOLog("hub descriptor: (%d bytes)\n", desc->length);
IOLog("\thubType = %d\n", desc->hubType);
IOLog("\tnumPorts = %d\n", desc->numPorts);
IOLog("\tcharacteristics = %x ( ",
USBToHostWord(desc->characteristics));
do
{
if (USBToHostWord(desc->characteristics) & (1 << i))
IOLog("%s ", characteristics[i]);
} while (characteristics[++i]);
IOLog(")\n");
IOLog("\tpowerOnToGood = %d ms\n", desc->powerOnToGood * 2);
IOLog("\thubCurrent = %d\n", desc->hubCurrent);
IOLog("\tremovablePortFlags = %p %p\n", &desc->removablePortFlags[1], &desc->removablePortFlags[0]);
IOLog("\tpwrCtlPortFlags = %p %p\n", &desc->pwrCtlPortFlags[1], &desc->removablePortFlags[0]);
}
IOReturn
AppleUSBHub::DoDeviceRequest(IOUSBDevRequest *request)
{
IOReturn err;
#if 0
if (_myPowerState < kIOUSBHubPowerStateLowPower)
{
char* bt[8];
OSBacktrace((void**)bt, 8);
USBLog(4, "AppleUSBHub[%p]::DoDeviceRequest - while _myPowerState(%d) _powerStateChangingTo(%d), bt:[%p][%p][%p][%p][%p][%p][%p]", this, (int)_myPowerState, (int)_powerStateChangingTo, bt[1], bt[2], bt[3], bt[4], bt[5], bt[6], bt[7]);
}
#endif
USBLog(5, "AppleUSBHub[%p]::DoDeviceRequest - _device[%p](%s) _myPowerState[%d] _powerStateChangingTo[%d] _portSuspended[%s]", this, _device, _device->getName(), (int)_myPowerState, (int)_powerStateChangingTo, _portSuspended ? "true" : "false");
if ( !_device || _device->isInactive() || !_device->isOpen(this))
{
USBLog(1, "AppleUSBHub[%p]::DoDeviceRequest - _device(%p) isInactive(%s) isOpen(%s) - returning kIOReturnNoDevice", this, _device, (_device && !_device->isInactive()) ? "false" : "true", (_device && _device->isOpen(this)) ? "true" : "false");
err = kIOReturnNoDevice;
}
else
{
if ( _portSuspended )
{
USBLog(5,"+AppleUSBHub[%p]::DoDeviceRequest, unsuspending port", this);
err = _device->SuspendDevice(false);
IOSleep(_hubResumeRecoveryTime); if ( err != kIOReturnSuccess )
return err;
}
err = _device->DeviceRequest(request, 5000, 0);
}
USBLog(5, "AppleUSBHub[%p]::DoDeviceRequest - returning err(%p)", this, (void*)err);
return err;
}
void
AppleUSBHub::TimeoutOccurred(OSObject *owner, IOTimerEventSource *sender)
{
AppleUSBHub *me;
AppleUSBHubPort *port;
UInt32 currentPort;
IOReturn kr = kIOReturnSuccess;
bool checkPorts = false;
me = OSDynamicCast(AppleUSBHub, owner);
if (!me)
return;
me->retain();
if ( --me->_devZeroLockedTimeoutCounter == 0 )
{
checkPorts = true;
me->_devZeroLockedTimeoutCounter = kDevZeroTimeoutCount;
}
if ( checkPorts && me->_ports)
{
for (currentPort = 1; currentPort <= me->_hubDescriptor.numPorts; currentPort++)
{
port = me->_ports ? me->_ports[currentPort-1] : NULL;
if (port)
{
Boolean locked;
port->retain();
locked = port->GetDevZeroLock();
if ( locked )
{
if ( ((me->_timeoutFlag & (1 << (currentPort-1))) != 0) && (me->_portTimeStamp[currentPort-1] == port->GetPortTimeStamp()) )
{
USBLog(3,"AppleUSBHub[%p]::TimeoutOccurred error - calling IncrementOutstandingIO", me);
me->IncrementOutstandingIO();
if ( thread_call_enter(me->_resetPortZeroThread) == TRUE )
{
USBLog(3, "AppleUSBHub[%p]::TimeoutOccurred _resetPortZeroThread already queued - calling DecrementOutstandingIO", me);
me->DecrementOutstandingIO();
}
}
else
{
me->_timeoutFlag |= (1<<(currentPort-1));
me->_portTimeStamp[currentPort-1] = port->GetPortTimeStamp();
}
}
else
{
me->_timeoutFlag &= ~( 1<<(currentPort-1));
me->_portTimeStamp[currentPort-1] = 0;
}
port->release();
}
}
}
if (me->_timerSource && !me->isInactive() )
{
me->_timerSource->setTimeoutMS(kWatchdogTimerPeriod);
}
me->release();
}
void
AppleUSBHub::CallCheckForDeadHub(void)
{
IncrementOutstandingIO();
if ( thread_call_enter(_hubDeadCheckThread) == TRUE )
{
USBLog(3, "AppleUSBHub[%p]::CallCheckForDeadHub _hubDeadCheckThread already queued - calling DecrementOutstandingIO", this);
DecrementOutstandingIO();
}
}
void
AppleUSBHub::CheckForDeadHubEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
me->CheckForDeadHub();
USBLog(6, "AppleUSBHub[%p]::CheckForDeadHubEntry - calling DecrementOutstandingIO", me);
me->DecrementOutstandingIO();
}
void
AppleUSBHub::CheckForDeadHub()
{
IOReturn err = kIOReturnSuccess;
if ( _device && !_hubIsDead)
{
err = _device->message(kIOUSBMessageHubIsDeviceConnected, NULL, 0);
if ( kIOReturnSuccess == err)
{
_needInterruptRead = true;
if ( --_retryCount == 0 )
{
retain();
ResetMyPort();
release();
}
else
{
USBLog(3, "AppleUSBHub[%p]::CheckForDeadHub - Still connected but retry count (%d) not reached, clearing stall and retrying", this, (uint32_t)_retryCount);
if ( _interruptPipe )
{
_interruptPipe->ClearPipeStall(true);
}
}
}
else
{
_hubHasBeenDisconnected = TRUE;
USBLog(3, "AppleUSBHub[%p]::CheckForDeadHub - device has been unplugged", this);
}
}
else
{
USBLog(3,"AppleUSBHub[%p]::CheckForDeadHub -- already resetting hub", this);
}
}
void
AppleUSBHub::ClearFeatureEndpointHaltEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
me->ClearFeatureEndpointHalt();
USBLog(6, "AppleUSBHub[%p]::ClearFeatureEndpointHaltEntry - calling DecrementOutstandingIO", me);
me->DecrementOutstandingIO();
}
void
AppleUSBHub::ClearFeatureEndpointHalt( )
{
IOReturn status = kIOReturnSuccess;
IOUSBDevRequest request;
UInt32 retries = 2;
bzero( &request, sizeof(IOUSBDevRequest));
while ( (retries > 0) && (_interruptPipe) )
{
retries--;
request.bmRequestType = USBmakebmRequestType(kUSBNone, kUSBStandard, kUSBEndpoint);
request.bRequest = kUSBRqClearFeature;
request.wValue = kUSBFeatureEndpointStall;
request.wIndex = _interruptPipe->GetEndpointNumber() | 0x80 ; request.wLength = 0;
request.pData = NULL;
status = _device->DeviceRequest(&request, 5000, 0);
if ( status != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHub[%p]::ClearFeatureEndpointHalt - DeviceRequest returned: 0x%x, retries = %d", this, status, (uint32_t)retries);
IOSleep(100);
}
else
break;
}
}
void
AppleUSBHub::CheckForActivePortsEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
USBLog(6, "+AppleUSBHub[%p]::CheckForActivePortsEntry", me);
if (!me)
return;
me->CheckForActivePorts();
USBLog(6, "AppleUSBHub[%p]::CheckForActivePortsEntry - setting _checkPortsThreadActive to false ", me);
me->_checkPortsThreadActive = false;
me->release();
}
void
AppleUSBHub::CheckForActivePorts( )
{
int msToDelay = kRootHubPollingInterval;
if ( _dontAllowLowPower )
{
USBLog(4, "AppleUSBHub[%p]::CheckForActivePorts - this hub does not allow low power, so abandoning", this);
return;
}
if (_powerStateChangingTo != kIOUSBHubPowerStateStable)
{
USBLog(4, "AppleUSBHub[%p]::CheckForActivePorts - in the middle of a power change, so abandoning", this);
return;
}
while (msToDelay--)
{
if (_abandonCheckPorts)
{
USBLog(4, "AppleUSBHub[%p]::CheckForActivePorts - abandoning ship before checking ports!!", this);
_abandonCheckPorts = false;
return;
}
IOSleep(1); }
USBLog(7, "AppleUSBHub[%p]::CheckForActivePorts - checking for disconnected ports", this);
if (HubAreAllPortsDisconnectedOrSuspended())
{
if (_abandonCheckPorts)
{
USBLog(4, "AppleUSBHub[%p]::CheckForActivePorts - abandoning ship!!", this);
_abandonCheckPorts = false;
return;
}
USBLog(4, "AppleUSBHub[%p]::CheckForActivePorts - lowering power state", this);
_dozeEnabled = true;
changePowerStateToPriv(kIOUSBHubPowerStateLowPower);
}
}
void
AppleUSBHub::WaitForPortResumesEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
me->WaitForPortResumes();
me->DecrementOutstandingIO();
}
void
AppleUSBHub::WaitForPortResumes( )
{
int portIndex;
int portNum;
bool needToWait = true;
AppleUSBHubPort * port;
IOUSBHubPortStatus portStatus;
IOReturn kr;
int innerRetries = 30; int outerRetries = 100; bool dealWithPort[_hubDescriptor.numPorts];
bool recoveryNeeded = true;
if (!_ports)
return;
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
dealWithPort[portIndex] = false;
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - checking for ports which need to be resumed", this);
while (needToWait && (outerRetries-- > 0))
{
innerRetries = 30;
while (needToWait && (innerRetries-- > 0))
{
needToWait = false; for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex+1;
port = _ports ? _ports[portIndex] : NULL;
if (port)
{
if (port->_portPMState == usbHPPMS_pm_suspended)
{
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port[%p] which is port number (%d) still waiting", this, port, portNum);
portStatus.statusFlags = 0;
portStatus.changeFlags = 0;
kr = GetPortStatus(&portStatus, portNum);
if (kr)
{
USBLog(1, "AppleUSBHub[%p]::WaitForPortResumes - err (%p) from GetPortStatus for port (%d) - setting port to active", this, (void*)kr, portNum);
dealWithPort[portIndex] = true;
port->_portPMState = usbHPPMS_active;
port->_resumePending = false;
}
if (portStatus.changeFlags & kHubPortSuspend)
{
ClearPortFeature(kUSBHubPortSuspendChangeFeature, portNum);
dealWithPort[portIndex] = true;
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port[%p], which is number[%d] has the suspend change bit set- good - statusFlags[%p] and changeFlags[%p]", this, port, portNum, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
port->_portPMState = usbHPPMS_active;
if (port->_resumePending)
{
port->_resumePending = false;
if (port->_lowerPowerStateOnResume)
{
port->_lowerPowerStateOnResume = false;
USBLog(5, "AppleUSBHub[%p]::WaitForPortResumes - calling LowerPowerState after clearing _lowerPowerStateOnResume for port %p", this, port);
LowerPowerState();
}
}
}
else
{
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port[%p], which is number(%d) has statusFlags[%p] and changeFlags[%p]", this, port, portNum, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
needToWait = true;
}
}
}
}
if (needToWait)
IOSleep(1);
}
if (needToWait)
{
needToWait = false;
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex+1;
port = _ports[portIndex];
if (port)
{
if (port->_portPMState == usbHPPMS_pm_suspended)
{
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port[%p] which is port number (%d) still waiting", this, port, portNum);
portStatus.statusFlags = 0;
portStatus.changeFlags = 0;
kr = GetPortStatus(&portStatus, portNum);
if (kr)
{
USBLog(1, "AppleUSBHub[%p]::WaitForPortResumes - err (%p) from GetPortStatus for port (%d) - setting port to active", this, (void*)kr, portNum);
dealWithPort[portIndex] = true;
port->_portPMState = usbHPPMS_active;
port->_resumePending = false;
}
else
{
if (portStatus.changeFlags & kHubPortSuspend)
{
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port[%p] which is port number (%d) has the suspend change set in the OUTER loop", this, port, portNum);
needToWait = true; }
else if (portStatus.statusFlags & kHubPortSuspend)
{
kr = port->SuspendPort(false, false);
if (kr)
{
USBLog(1, "AppleUSBHub[%p]::WaitForPortResumes - err (%p) from SuspendPort for port (%d)", this, (void*)kr, portNum);
dealWithPort[portIndex] = true;
port->_portPMState = usbHPPMS_active; port->_resumePending = false;
}
else
{
needToWait = true; }
}
else if (port->_resumePending)
{
USBLog(3, "AppleUSBHub[%p]::WaitForPortResumes - port number %d still has a pending resume in OUTER loop - going around again", this, portNum);
needToWait = true;
}
else
{
USBLog(1, "AppleUSBHub[%p]::WaitForPortResumes - not sure what is going on with port number %d in OUTER loop - terminating", this, portNum);
}
}
}
}
}
}
}
for (portIndex = 0; portIndex < _hubDescriptor.numPorts; portIndex++)
{
portNum = portIndex + 1;
port = _ports[portIndex];
if (port && dealWithPort[portIndex])
{
IOUSBControllerV3 *v3Bus = NULL;
IOReturn err;
if (recoveryNeeded)
{
recoveryNeeded = false;
IOSleep(port->_portResumeRecoveryTime);
}
if (_device)
v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
if (v3Bus && port->_portDevice)
{
USBLog(5, "AppleUSBHub[%p]::WaitForPortResumes - Enabling endpoints for device at address (%d)", this, (int)port->_portDevice->GetAddress());
err = v3Bus->EnableAddressEndpoints(port->_portDevice->GetAddress(), true);
if (err)
{
USBLog(2, "AppleUSBHub[%p]::WaitForPortResumes - EnableAddressEndpoints returned (%p)", this, (void*)err);
}
}
USBLog(6, "AppleUSBHub[%p]::WaitForPortResumes - calling DecrementOutstandingIO", this);
DecrementOutstandingResumes();
DecrementOutstandingIO();
}
}
}
void
AppleUSBHub::ResetMyPort()
{
IOReturn err;
int currentPort;
AppleUSBHubPort * port;
USBLog(3, "AppleUSBHub[%p]::ResetMyPort - marking hub as dead", this);
_hubIsDead = TRUE;
if ( _interruptPipe )
{
err = _interruptPipe->Abort();
if ( err != kIOReturnSuccess )
{
USBLog(1, "AppleUSBHub[%p]::ResetMyPort interruptPipe->Abort returned %p", this, (void*)err);
}
}
if ( _ports)
{
for (currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort-1] : NULL;
if (port)
{
if (port->_devZero)
{
USBLog(1, "AppleUSBHub[%p]::StopPorts - port %d had the dev zero lock", this, currentPort);
}
port->ReleaseDevZeroLock();
}
}
}
if (_timerSource)
{
_timerSource->cancelTimeout();
}
USBLog(3, "AppleUSBHub[%p]::ResetMyPort calling changePowerStateToPriv(kIOUSBHubPowerStateOff) %d", this, kIOUSBHubPowerStateOff);
_needToCallResetDevice = true;
changePowerStateToPriv(kIOUSBHubPowerStateOn);
powerOverrideOnPriv();
changePowerStateToPriv(kIOUSBHubPowerStateOff);
}
bool
AppleUSBHub::IsHSRootHub()
{
if (_hsHub && _isRootHub)
return true;
else
return false;
}
IOReturn
AppleUSBHub::GetPortInformation(UInt32 portNum, UInt32 *info)
{
AppleUSBHubPort * port;
UInt32 portIndex = portNum -1;
IOUSBHubPortStatus portStatus;
UInt32 information = 0;
IOReturn kr = kIOReturnSuccess;
USBLog(5, "AppleUSBHub[%p]::GetPortInformation for port[%d]", this, (uint32_t)portNum);
if ( _isRootHub )
information |= ( 1 << kUSBInformationDeviceIsAttachedToRootHubBit);
if ( _ports)
{
port = _ports ? _ports[portIndex] : NULL;
if (port)
{
if ( port->IsCaptive() )
information |= (1 << kUSBInformationDeviceIsCaptiveBit);
}
portStatus.statusFlags = 0;
portStatus.changeFlags = 0;
kr = GetPortStatus(&portStatus, portNum);
if (kr != kIOReturnSuccess)
{
USBLog(3, "AppleUSBHub[%p]::GetPortInformation - error 0x%x getting port status for port %d", this, kr, (uint32_t)portNum);
}
else
{
USBLog(6, "AppleUSBHub[%p]::GetPortInformation - got statusFlags(%p) changeFlags(%p)", this, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
if ( (portStatus.statusFlags & kHubPortConnection) && !(portStatus.changeFlags & kHubPortConnection) )
information |= ( 1 << kUSBInformationDeviceIsConnectedBit);
if (portStatus.statusFlags & kHubPortEnabled)
information |= ( 1 << kUSBInformationDeviceIsEnabledBit);
if (portStatus.statusFlags & kHubPortSuspend)
information |= ( 1 << kUSBInformationDeviceIsSuspendedBit);
if (portStatus.statusFlags & kHubPortOverCurrent)
information |= ( 1 << kUSBInformationDeviceOvercurrentBit);
if (portStatus.statusFlags & kHubPortBeingReset)
information |= ( 1 << kUSBInformationDeviceIsInResetBit);
if (portStatus.statusFlags & kHubPortTestMode)
information |= ( 1 << kUSBInformationDevicePortIsInTestModeBit);
}
}
*info = information;
return kr;
}
IOReturn
AppleUSBHub::ResetPort(UInt32 portNum)
{
USBLog(5, "AppleUSBHub[%p]::ResetPort for port[%d]", this, (uint32_t)portNum);
return kIOReturnUnsupported;
}
IOReturn
AppleUSBHub::SuspendPort(UInt32 portNum, bool suspend)
{
USBLog(5, "AppleUSBHub[%p]::SuspendPort %s for port[%d]", this, suspend ? "SUSPEND" : "RESUME", (uint32_t)portNum);
return kIOReturnUnsupported;
}
IOReturn
AppleUSBHub::ReEnumeratePort(UInt32 portNum, UInt32 options)
{
USBLog(5, "AppleUSBHub[%p]::ReEnumeratePort for port[%d], options %d", this, (uint32_t)portNum, (uint32_t) options);
return kIOReturnUnsupported;
}
#pragma mark ееееееее Bookkeeping ееееееее
void
AppleUSBHub::DecrementOutstandingIO(void)
{
UInt32 outstandingIO;
IOReturn err;
static int gSerial = 0;
int localSerial;
localSerial = gSerial++;
if (!_gate)
{
USBLog(6, "+AppleUSBHub[%p]::DecrementOutstandingIO(%d) isInactive(%d), outstandingIO(%d), _needInterruptRead(%d) - no gate", this, localSerial, isInactive(), (uint32_t)_outstandingIO, _needInterruptRead);
outstandingIO = --_outstandingIO;
}
else
{
err = _gate->runAction(ChangeOutstandingIO, (void*)-1, &outstandingIO);
USBLog(6, "AppleUSBHub[%p]::DecrementOutstandingIO(%d) isInactive(%s), _interruptReadPending(%s), gated call returned err (%p) count (%d), _needInterruptRead(%d)", this, localSerial, isInactive() ? "true" : "false", _interruptReadPending ? "true" : "false", (void*)err, (int)outstandingIO, _needInterruptRead);
}
if ( IsPortInitThreadActiveForAnyPort() )
{
if ((_myPowerState == kIOUSBHubPowerStateOn) && _needInterruptRead)
{
USBLog(5, "AppleUSBHub[%p]::DecrementOutstandingIO(%d), rearming read because devZero lock was held by a port", this, localSerial);
_needInterruptRead = false;
RearmInterruptRead();
}
}
else if (_needToClose)
{
if (!outstandingIO && (_myPowerState == kIOUSBHubPowerStateOn) && !_doPortActionLock)
{
_needToClose = false; USBLog(3, "AppleUSBHub[%p]::DecrementOutstandingIO(%d) isInactive(%s) outstandingIO(%d) _powerStateChangingTo(%d) - closing device", this, localSerial, isInactive() ? "true" : "false", (int)outstandingIO, (int)_powerStateChangingTo);
StopPorts();
_device->close(this);
}
else
{
USBLog(3, "AppleUSBHub[%p]::DecrementOutstandingIO(%d) _needToClose(true) but waiting for outstandingIO OR _myPowerState == kIOUSBHubPowerStateOn(%d) OR for the _doPortActionLock", this, localSerial, (int)_myPowerState);
}
}
else if ((outstandingIO == 0) || ((outstandingIO == 1) && _interruptReadPending))
{
if ( (_myPowerState == kIOUSBHubPowerStateOn) && !_hubIsDead && !isInactive())
{
if (_needInterruptRead)
{
_needInterruptRead = false;
if (!_interruptReadPending)
{
USBLog(3, "AppleUSBHub[%p]::DecrementOutstandingIO(%d), outstandingIO(%d), _interruptReadPending(%s) - rearming read", this, localSerial, (uint32_t)outstandingIO, _interruptReadPending ? "true" : "false");
RearmInterruptRead();
}
}
if (!_checkPortsThreadActive)
{
_abandonCheckPorts = false;
_checkPortsThreadActive = true;
retain();
USBLog(5,"AppleUSBHub[%p]::DecrementOutstandingIO(%d) - spawning _checkForActivePortsThread", this, localSerial);
if ( thread_call_enter(_checkForActivePortsThread) == TRUE )
{
USBLog(1,"AppleUSBHub[%p]::DecrementOutstandingIO - _checkForActivePortsThread already queued", this);
release();
}
}
}
}
USBLog(6, "-AppleUSBHub[%p]::DecrementOutstandingIO(%d)", this, localSerial);
}
void
AppleUSBHub::IncrementOutstandingIO(void)
{
if (!_gate)
{
USBLog(6, "AppleUSBHub[%p]::IncrementOutstandingIO isInactive = %d, outstandingIO = %d - no gate", this, isInactive(), (uint32_t)_outstandingIO);
_outstandingIO++;
return;
}
_gate->runAction(ChangeOutstandingIO, (void*)1);
}
IOReturn
AppleUSBHub::ChangeOutstandingIO(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
AppleUSBHub *me = OSDynamicCast(AppleUSBHub, target);
UInt32 direction = (uintptr_t)param1;
UInt32 *retCount = (UInt32*)param2;
IOReturn ret = kIOReturnSuccess;
if (!me)
{
USBLog(1, "AppleUSBHub::ChangeOutstandingIO - invalid target");
return kIOReturnBadArgument;
}
switch (direction)
{
case 1:
me->_outstandingIO++;
USBLog(6, "AppleUSBHub[%p]::ChangeOutstandingIO(+) now (%d)", me, (int)me->_outstandingIO);
break;
case -1:
--me->_outstandingIO;
USBLog(6, "AppleUSBHub[%p]::ChangeOutstandingIO(-) now (%d)", me, (int)me->_outstandingIO);
break;
default:
USBLog(1, "AppleUSBHub[%p]::ChangeOutstandingIO - invalid direction", me);
ret = kIOReturnBadArgument;
}
if (retCount)
*retCount = me->_outstandingIO;
return ret;
}
void
AppleUSBHub::LowerPowerState(void)
{
UInt32 raisedPowerStateCount;
IOReturn err;
static int gSerial = 0;
int localSerial;
localSerial = gSerial++;
if (!_gate)
{
USBLog(6, "+AppleUSBHub[%p]::LowerPowerState(%d) isInactive = %d, _raisedPowerStateCount = %d - no gate", this, localSerial, isInactive(), (uint32_t)_raisedPowerStateCount);
raisedPowerStateCount = --_raisedPowerStateCount;
}
else
{
err = _gate->runAction(ChangeRaisedPowerState, (void*)-1, &raisedPowerStateCount);
USBLog(6, "AppleUSBHub[%p]::LowerPowerState(%d) isInactive(%s), gated call returned err (%p) count (%d)", this, localSerial, isInactive() ? "true" : "false", (void*)err, (uint32_t)raisedPowerStateCount);
}
if (!raisedPowerStateCount)
{
changePowerStateTo(kIOUSBHubPowerStateLowPower);
}
USBLog(6, "-AppleUSBHub[%p]::LowerPowerState(%d)", this, localSerial);
}
void
AppleUSBHub::RaisePowerState(void)
{
IOReturn err;
UInt32 raisedPowerStateCount;
if (!_gate)
{
USBLog(6, "AppleUSBHub[%p]::RaisePowerState isInactive = %d, outstandingIO = %d - no gate", this, isInactive(), (uint32_t)_outstandingIO);
raisedPowerStateCount = _raisedPowerStateCount++;
}
else
{
err = _gate->runAction(ChangeRaisedPowerState, (void*)1, &raisedPowerStateCount);
USBLog(6, "AppleUSBHub[%p]::RaisePowerState isInactive(%s), gated call returned err (%p) count (%d)", this, isInactive() ? "true" : "false", (void*)err, (uint32_t)raisedPowerStateCount);
}
if (raisedPowerStateCount == 1) {
changePowerStateTo(kIOUSBHubPowerStateOn);
}
}
IOReturn
AppleUSBHub::ChangeRaisedPowerState(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
AppleUSBHub *me = OSDynamicCast(AppleUSBHub, target);
UInt32 direction = (uintptr_t)param1;
UInt32 *retCount = (UInt32*)param2;
IOReturn ret = kIOReturnSuccess;
if (!me)
{
USBLog(1, "AppleUSBHub::ChangeRaisedPowerState - invalid target");
return kIOReturnBadArgument;
}
switch (direction)
{
case 1:
me->_raisedPowerStateCount++;
USBLog(3, "AppleUSBHub[%p]::ChangeRaisedPowerState(+) now (%d)", me, (int)me->_raisedPowerStateCount);
break;
case -1:
--me->_raisedPowerStateCount;
USBLog(3, "AppleUSBHub[%p]::ChangeRaisedPowerState(-) now (%d)", me, (int)me->_raisedPowerStateCount);
break;
default:
USBLog(1, "AppleUSBHub[%p]::ChangeRaisedPowerState - invalid direction", me);
ret = kIOReturnBadArgument;
}
if (retCount)
*retCount = me->_raisedPowerStateCount;
return ret;
}
void
AppleUSBHub::DecrementOutstandingResumes(void)
{
UInt32 outstandingResumes;
IOReturn err;
static int gSerial = 0;
int localSerial;
localSerial = gSerial++;
if (!_gate)
{
USBLog(5, "AppleUSBHub[%p]::+DecrementOutstandingResumes(%d) isInactive = %d, outstandingIO = %d, _needInterruptRead: %d - no gate", this, localSerial, isInactive(), (uint32_t)_outstandingIO, _needInterruptRead);
outstandingResumes = --_outstandingResumes;
}
else
{
err = _gate->runAction(ChangeOutstandingResumes, (void*)-1, &outstandingResumes);
USBLog(5, "AppleUSBHub[%p]::DecrementOutstandingResumes(%d) isInactive(%s), gated call returned err (%p) count (%d)", this, localSerial, isInactive() ? "true" : "false", (void*)err, (int)outstandingResumes);
}
if (!outstandingResumes)
{
USBLog(5, "AppleUSBHub[%p]::DecrementOutstandingResumes(%d) - resumes down to zero", this, localSerial);
if (_needToAckSetPowerState)
{
USBLog(5, "AppleUSBHub[%p]::DecrementOutstandingResumes(%d) - calling acknowledgeSetPowerState", this, localSerial);
_needToAckSetPowerState = false;
acknowledgeSetPowerState();
}
}
USBLog(5, "AppleUSBHub[%p]::-DecrementOutstandingResumes(%d)", this, localSerial);
}
void
AppleUSBHub::IncrementOutstandingResumes(void)
{
if (!_gate)
{
USBLog(5, "AppleUSBHub[%p]::IncrementOutstandingResumes isInactive = %d, outstandingIO = %d - no gate", this, isInactive(), (uint32_t)_outstandingResumes);
_outstandingResumes++;
return;
}
_gate->runAction(ChangeOutstandingResumes, (void*)1);
}
IOReturn
AppleUSBHub::ChangeOutstandingResumes(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
AppleUSBHub *me = OSDynamicCast(AppleUSBHub, target);
UInt32 direction = (uintptr_t)param1;
UInt32 *retCount = (UInt32*)param2;
IOReturn ret = kIOReturnSuccess;
if (!me)
{
USBLog(1, "AppleUSBHub::ChangeOutstandingResumes - invalid target");
return kIOReturnBadArgument;
}
switch (direction)
{
case 1:
me->_outstandingResumes++;
USBLog(3, "AppleUSBHub[%p]::ChangeOutstandingResumes(+) now (%d)", me, (int)me->_outstandingResumes);
break;
case -1:
--me->_outstandingResumes;
USBLog(3, "AppleUSBHub[%p]::ChangeOutstandingResumes(-) now (%d)", me, (int)me->_outstandingResumes);
break;
default:
USBLog(1, "AppleUSBHub[%p]::ChangeOutstandingResumes - invalid direction", me);
ret = kIOReturnBadArgument;
}
if (retCount)
*retCount = me->_outstandingResumes;
return ret;
}
IOReturn
AppleUSBHub::TakeDoPortActionLock(void)
{
if (!_workLoop || !_gate)
{
USBLog(1, "AppleUSBHub[%p]::TakeDoPortActionLock - no WorkLoop or no gate!", this);
return kIOReturnNotPermitted;
}
if (_workLoop->onThread())
{
USBLog(1, "AppleUSBHub[%p]::TakeDoPortActionLock - called onThread -- not allowed!", this);
return kIOReturnNotPermitted;
}
USBLog(2, "AppleUSBHub[%p]::TakeDoPortActionLock - calling through to ChangeDoPortActionLock", this);
return _gate->runAction(ChangeDoPortActionLock, (void*)true);
}
IOReturn
AppleUSBHub::ReleaseDoPortActionLock(void)
{
if (!_workLoop || !_gate)
{
USBLog(1, "AppleUSBHub[%p]::TakeDoPortActionLock - no WorkLoop or no gate!", this);
return kIOReturnNotPermitted;
}
USBLog(2, "AppleUSBHub[%p]::ReleaseDoPortActionLock - calling through to ChangeDoPortActionLock", this);
return _gate->runAction(ChangeDoPortActionLock, (void*)false);
}
#define DO_PORT_ACTION_DEADLINE_IN_SECONDS 30
IOReturn
AppleUSBHub::ChangeDoPortActionLock(OSObject *target, void *param1, void *param2, void *param3, void *param4)
{
AppleUSBHub *me = OSDynamicCast(AppleUSBHub, target);
bool takeLock = (bool)param1;
IOReturn retVal = kIOReturnSuccess;
if (takeLock)
{
while (me->_doPortActionLock and (retVal == kIOReturnSuccess))
{
IOReturn kr;
USBLog(2, "AppleUSBHub[%p]::ChangeDoPortActionLock - _doPortActionLock held by someone else - calling commandSleep to wait for lock", me);
kr = me->_gate->commandSleep(&me->_doPortActionLock, THREAD_ABORTSAFE);
switch (kr)
{
case THREAD_AWAKENED:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock commandSleep woke up normally (THREAD_AWAKENED) _doPortActionLock(%s)", me, me->_doPortActionLock ? "true" : "false");
break;
case THREAD_TIMED_OUT:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock commandSleep timeout out (THREAD_TIMED_OUT) _doPortActionLock(%s)", me, me->_doPortActionLock ? "true" : "false");
retVal = kIOReturnNotPermitted;
break;
case THREAD_INTERRUPTED:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock commandSleep interrupted (THREAD_INTERRUPTED) _doPortActionLock(%s)", me, me->_doPortActionLock ? "true" : "false");
retVal = kIOReturnNotPermitted;
break;
case THREAD_RESTART:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock commandSleep restarted (THREAD_RESTART) _doPortActionLock(%s)", me, me->_doPortActionLock ? "true" : "false");
retVal = kIOReturnNotPermitted;
break;
case kIOReturnNotPermitted:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock woke up with status (kIOReturnNotPermitted) - we do not hold the WL!", me);
retVal = kr;
break;
default:
USBLog(2,"AppleUSBHub[%p]::ChangeDoPortActionLock woke up with unknown status %p", me, (void*)kr);
retVal = kIOReturnNotPermitted;
}
}
if (retVal == kIOReturnSuccess)
{
USBLog(2, "AppleUSBHub[%p]::ChangeDoPortActionLock - setting _doPortActionLock to true", me);
me->_doPortActionLock = true;
}
}
else
{
USBLog(2, "AppleUSBHub[%p]::ChangeDoPortActionLock - setting _doPortActionLock to false and calling commandWakeup", me);
me->_doPortActionLock = false;
me->_gate->commandWakeup(&me->_doPortActionLock, true);
}
return retVal;
}
#pragma mark ееееееее User Client ееееееее
IOReturn
AppleUSBHub::EnterTestMode()
{
IOUSBControllerV2 *con;
int currentPort;
AppleUSBHubPort *port;
if (!_hsHub)
return kIOReturnBadArgument;
if (_isRootHub)
{
con = OSDynamicCast(IOUSBControllerV2, _bus);
if (!con)
return kIOReturnBadArgument;
USBLog(1, "AppleUSBHub[%p]::EnterTestMode - root hub", this);
_inTestMode = true;
return con->SetTestMode(kEHCITestMode_Start, 0);
}
_inTestMode = true;
if ( _ports)
{
USBLog(1, "AppleUSBHub[%p]::EnterTestMode - external hub - suspending ports", this);
for (currentPort = 0; currentPort < _hubDescriptor.numPorts; currentPort++)
{
port = _ports ? _ports[currentPort] : NULL;
if (port)
{
port->SuspendPort(true, false);
}
}
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBHub::LeaveTestMode()
{
IOUSBControllerV2 *con;
if (!_hsHub)
return kIOReturnBadArgument;
if (_isRootHub)
{
con = OSDynamicCast(IOUSBControllerV2, _bus);
if (!con)
return kIOReturnBadArgument;
USBLog(1, "AppleUSBHub[%p]::LeaveTestMode - root hub", this);
return con->SetTestMode(kEHCITestMode_End, 0);
}
USBLog(1, "AppleUSBHub[%p]::LeaveTestMode - external hub", this);
retain();
ResetMyPort();
release();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHub::PutPortIntoTestMode(UInt32 port, UInt32 mode)
{
IOUSBDevRequest request;
if (!_hsHub || !_inTestMode)
return kIOReturnBadArgument;
if (_isRootHub)
{
USBLog(1, "AppleUSBHub[%p]::PutPortIntoTestMode - putting root hub port %d into mode %x", this, (uint32_t)port, (uint32_t)mode);
return _bus->SetTestMode(mode, port);
}
USBLog(1, "AppleUSBHub[%p]::PutPortIntoTestMode - putting external hub port %d into mode %x", this, (uint32_t)port, (uint32_t)mode);
return SetPortFeature(kUSBHubPortTestFeature, (mode << 8) + port);
}
IOReturn
AppleUSBHub::SetIndicatorForPort(UInt16 port, UInt16 selector)
{
IOReturn kr = kIOReturnUnsupported;
IOUSBDevRequest request;
USBLog(5, "AppleUSBHub[%p](0x%x)::SetIndicatorForPort port %d, selector %d", this, (uint32_t)_locationID, port, selector);
return SetPortFeature(kUSBHubPortIndicatorFeature, (selector << 8) + port);
}
IOReturn
AppleUSBHub::GetPortIndicatorControl(UInt16 port, UInt32 *defaultColors)
{
IOReturn kr = kIOReturnUnsupported;
IOUSBHubPortStatus portStatus;
kr = GetPortStatus(&portStatus, port);
if ( kIOReturnSuccess != kr )
{
USBLog(1, "AppleUSBHub[%p](0x%x)::GetPortIndicatorControl GetPortStatus to port %d got error (0x%x) from DoDeviceRequest", this, (uint32_t)_locationID, port, kr);
}
else
{
if ( portStatus.statusFlags & kHubPortIndicator )
{
USBLog(6, "AppleUSBHub[%p](0x%x)::GetPortIndicatorControl - port %d indicators are under software control", this, (uint32_t)_locationID, port);
*defaultColors = 1;
}
else
{
USBLog(6, "AppleUSBHub[%p](0x%x)::GetPortIndicatorControl - port %d indicators display default colors", this, (uint32_t)_locationID, port);
*defaultColors = 0;
}
}
return kr;
}
IOReturn
AppleUSBHub::SetIndicatorsToAutomatic()
{
IOReturn kr = kIOReturnUnsupported;
USBLog(5, "AppleUSBHub[%p](0x%x)::SetIndicatorsToAutomatic", this, (uint32_t)_locationID);
for (int currentPort = 1; currentPort <= _hubDescriptor.numPorts; currentPort++)
{
kr = SetIndicatorForPort(currentPort, kHubPortIndicatorAutomatic);
if ( kIOReturnSuccess != kr )
{
USBLog(1, "AppleUSBHub[%p](0x%x)::SetIndicatorForPort to port %d got error (0x%x)", this, (uint32_t)_locationID, currentPort, kr);
}
}
return kr;
}
IOReturn
AppleUSBHub::GetPortPower(UInt16 port, UInt32 *on)
{
IOReturn kr = kIOReturnUnsupported;
IOUSBHubPortStatus portStatus;
kr = GetPortStatus(&portStatus, port);
if ( kIOReturnSuccess != kr )
{
USBLog(1, "AppleUSBHub[%p](0x%x)::GetPortPower GetPortStatus to port %d got error (0x%x) from DoDeviceRequest", this, (uint32_t)_locationID, port, kr);
}
else
{
if ( portStatus.statusFlags & kHubPortPower )
{
USBLog(6, "AppleUSBHub[%p](0x%x)::GetPortIndicatorControl - port %d is NOT in the Powered-off state", this, (uint32_t)_locationID, port);
*on = 1;
}
else
{
USBLog(6, "AppleUSBHub[%p](0x%x)::GetPortIndicatorControl - port %d is in the Powered-off state", this, (uint32_t)_locationID, port);
*on = 0;
}
}
USBLog(5, "AppleUSBHub[%p](0x%x)::GetPortPower port %d returning on = %d", this, (uint32_t)_locationID, (uint32_t)port, (uint32_t)*on);
return kr;
}
IOReturn
AppleUSBHub::SetPortPower(UInt16 port, UInt32 on)
{
IOReturn kr = kIOReturnUnsupported;
USBLog(5, "AppleUSBHub[%p](0x%x)::SetPortPower to %s, for port %d", this, (uint32_t)_locationID, on ? "ON" : "OFF", port);
if ( on == 1 )
return SetPortFeature(kUSBHubPortPowerFeature, port);
else
return ClearPortFeature(kUSBHubPortPowerFeature, port);
}
const char *
AppleUSBHub::HubMessageToString(UInt32 message)
{
switch (message)
{
case kIOUSBMessageHubResetPort: return "kIOUSBMessageHubResetPort";
case kIOUSBMessageHubSuspendPort: return "kIOUSBMessageHubSuspendPort";
case kIOUSBMessageHubResumePort: return "kIOUSBMessageHubResumePort";
case kIOUSBMessageHubIsDeviceConnected: return "kIOUSBMessageHubIsDeviceConnected";
case kIOUSBMessageHubIsPortEnabled: return "kIOUSBMessageHubIsPortEnabled";
case kIOUSBMessageHubReEnumeratePort: return "kIOUSBMessageHubReEnumeratePort";
case kIOUSBMessagePortHasBeenReset: return "kIOUSBMessagePortHasBeenReset";
case kIOUSBMessagePortHasBeenResumed: return "kIOUSBMessagePortHasBeenResumed";
case kIOUSBMessageHubPortClearTT: return "kIOUSBMessageHubPortClearTT";
case kIOUSBMessagePortHasBeenSuspended: return "kIOUSBMessagePortHasBeenSuspended";
case kIOUSBMessageFromThirdParty: return "kIOUSBMessageFromThirdParty";
case kIOUSBMessagePortWasNotSuspended: return "kIOUSBMessagePortWasNotSuspended";
case kIOUSBMessageExpressCardCantWake: return "kIOUSBMessageExpressCardCantWake";
case kIOUSBMessageCompositeDriverReconfigured: return "kIOUSBMessageCompositeDriverReconfigured";
case kIOUSBMessageHubSetPortRecoveryTime: return "kIOUSBMessageHubSetPortRecoveryTime";
case kIOUSBMessageOvercurrentCondition: return "kIOUSBMessageOvercurrentCondition";
case kIOUSBMessageNotEnoughPower: return "kIOUSBMessageNotEnoughPower";
case kIOMessageServiceIsTerminated:
return "kIOMessageServiceIsTerminated";
case kIOMessageServiceIsRequestingClose:
return "kIOMessageServiceIsRequestingClose";
case kIOMessageServiceIsAttemptingOpen:
return "kIOMessageServiceIsAttemptingOpen";
default:
return "UNKNOWN";
}
}
void
AppleUSBHub::EnsureUsabilityEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
USBLog(7, "AppleUSBHub[%p]::EnsureUsabilityEntry - calling in", me);
me->EnsureUsability();
me->DecrementOutstandingIO();
USBLog(7, "AppleUSBHub[%p]::EnsureUsabilityEntry - done", me);
}
IOReturn
AppleUSBHub::EnsureUsability(void)
{
UInt32 retries = 200;
if (_workLoop->inGate())
{
USBLog(7, "AppleUSBHub[%p]::EnsureUsability - called inGate - spawning thread instead", this);
IncrementOutstandingIO();
if (thread_call_enter(_ensureUsabilityThread) == true)
{
DecrementOutstandingIO();
}
return kIOReturnSuccess;
}
USBLog(7, "AppleUSBHub[%p]::EnsureUsability - setting _abandonCheckPorts, inGate(%s)", this, _workLoop->inGate() ? "true" : "false");
_abandonCheckPorts = true;
while (_checkPortsThreadActive && retries--)
{
USBLog(5, "AppleUSBHub[%p]::EnsureUsability - _checkPortsThreadActive, sleeping 2 ms (retries %d)", this, (int)retries);
IOSleep(2);
}
if (_checkPortsThreadActive)
{
USBLog(1, "AppleUSBHub[%p]::EnsureUsability - _checkPortsThreadActive after delay!", this);
}
USBLog(7, "AppleUSBHub[%p]::EnsureUsability - clearing _abandonCheckPorts, inGate(%s)", this, _workLoop->inGate() ? "true" : "false");
_abandonCheckPorts = false;
return super::EnsureUsability();
}
void
AppleUSBHub::InitialDelayEntry(OSObject *target)
{
AppleUSBHub * me = OSDynamicCast(AppleUSBHub, target);
if (!me)
return;
USBLog(7, "AppleUSBHub[%p]::InitialDelayEntry - calling in", me);
me->InitialDelay();
me->DecrementOutstandingIO();
USBLog(7, "AppleUSBHub[%p]::InitialDelayEntry - done", me);
}
void
AppleUSBHub::InitialDelay(void)
{
USBLog(5, "AppleUSBHub[%p]::InitialDelay - sleeping for %d milliseconds", this, (int)kInitialDelayTime);
IOSleep(kInitialDelayTime); LowerPowerState();
USBLog(5, "AppleUSBHub[%p]::InitialDelay - done", this);
}