AppleUSBHubPort.cpp [plain text]
#include <UserNotification/KUNCUserNotifications.h>
#include <libkern/c++/OSMetaClass.h>
#include <libkern/version.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/usb/USBSpec.h>
#include <IOKit/usb/USBHub.h>
#include <IOKit/usb/IOUSBHubDevice.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include <IOKit/usb/IOUSBLog.h>
#include </usr/include/AssertMacros.h>
#include "AppleUSBHubPort.h"
#include "USBTracepoints.h"
#define super OSObject
#define REMOVE_PORTPOWER_ON_STOP 1
enum
{
kIOWaitTimeBeforeReEnablingPortPowerAfterOvercurrent = 5*1000, kWaitTimeToIgnoreDisconnect = 4000, kMaxDevZeroRetries = 4
};
static CaptiveErrataListEntry gErrataList[] = {
{ 0x05ac, 0x8000, 0x8FFF }, { 0x05ac, 0x020e, 0x021c },
{ 0x05ac, 0x0223, 0x0226 },
{ 0x05ac, 0x0229, 0x022b },
{ 0x05ac, 0x022f, 0x022f },
{ 0x05ac, 0x0230, 0x0238 }, { 0x0a5c, 0x4500, 0x4500 }, { 0x05ac, 0x0201, 0x0206 },
{ 0x05ac, 0x9210, 0x9217 },
};
#define ERRATALISTLENGTH (sizeof(gErrataList)/sizeof(CaptiveErrataListEntry))
static portStatusChangeVector defaultPortVectors[kNumChangeHandlers] =
{
#ifdef SUPPORTS_SS_USB
{ 0, kHubPortOverCurrent, kUSBHubPortOverCurrentChangeFeature },
{ 0, kSSHubPortChangeBHResetMask, kUSBHubPortBHResetChangeFeature },
{ 0, kHubPortBeingReset, kUSBHubPortResetChangeFeature },
{ 0, kSSHubPortChangePortLinkStateMask, kUSBHubPortLinkStateChangeFeature },
{ 0, kHubPortSuspend, kUSBHubPortSuspendChangeFeature },
{ 0, kHubPortEnabled, kUSBHubPortEnableChangeFeature },
{ 0, kHubPortConnection, kUSBHubPortConnectionChangeFeature },
{ 0, kSSHubPortChangePortConfigErrMask, kUSBHubPortConfigErrorChangeFeature }
#else
{ 0, kHubPortOverCurrent, kUSBHubPortOverCurrentChangeFeature },
{ 0, kHubPortBeingReset, kUSBHubPortResetChangeFeature },
{ 0, kHubPortSuspend, kUSBHubPortSuspendChangeFeature },
{ 0, kHubPortEnabled, kUSBHubPortEnableChangeFeature },
{ 0, kHubPortConnection, kUSBHubPortConnectionChangeFeature },
#endif
};
OSDefineMetaClassAndStructors(AppleUSBHubPort, OSObject)
#ifdef SUPPORTS_SS_USB
IOReturn
AppleUSBHubPort::init( AppleUSBHub *parent, int portNum, UInt32 powerAvailable, bool captive, bool hasExternalConnector, bool muxed, char *methodName )
#else
IOReturn
AppleUSBHubPort::init( AppleUSBHub *parent, int portNum, UInt32 powerAvailable, bool captive, bool hasExternalConnector )
#endif
{
_hub = parent;
_bus = parent->_bus;
_hubDesc = &parent->_hubDescriptor;
_portNum = portNum;
_portDevice = NULL;
_portPowerAvailable = powerAvailable;
_captive = captive;
_hasExternalConnector = hasExternalConnector;
_state = hpsNormal;
_retryPortStatus = false;
_statusChangedThreadActive = false;
_initThreadActive = false;
_addDeviceThreadActive = false;
_enablePowerAfterOvercurrentThreadActive = false;
_inCommandSleep = false;
_attachRetry = 0;
_attachRetryFailed = false;
_devZeroCounter = 0;
_attachMessageDisplayed = false;
_overCurrentNoticeDisplayed = false;
_portPMState = usbHPPMS_uninitialized;
_resumePending = false;
_portResumeRecoveryTime = kPortResumeRecoveryTime;
_delayOnStatusChange = false;
#ifdef SUPPORTS_SS_USB
_muxed = muxed;
if(_muxed)
{
strlcpy(_muxedMethod, methodName, kIOUSBMuxMethodNameLength);
}
_portLinkState = 0xFFFF; #endif
clock_get_uptime(&_overCurrentNoticeTimeStamp);
if (!_hub || !_bus || !_hubDesc || (portNum < 1) || (portNum > 64))
{
USBLog(2,"AppleUSBHubPort[%p]::init failure (Parent: %p, Bus: %p, Desc: %p, PortNum: %d", this, parent, _bus, _hubDesc, portNum);
return kIOReturnBadArgument;
}
_runLock = IOLockAlloc();
if (!_runLock)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _runLock", this);
return kIOReturnNoMemory;
}
_initLock = IOLockAlloc();
if (!_initLock)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _initLock", this);
IOLockFree(_runLock);
return kIOReturnNoMemory;
}
_removeDeviceLock = IOLockAlloc();
if (!_removeDeviceLock)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _removeDeviceLock", this);
IOLockFree(_runLock);
IOLockFree(_initLock);
return kIOReturnNoMemory;
}
_initThread = thread_call_allocate((thread_call_func_t)PortInitEntry, (thread_call_param_t)this);
if (!_initThread)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _initThread", this);
IOLockFree(_runLock);
IOLockFree(_initLock);
IOLockFree(_removeDeviceLock);
return kIOReturnNoMemory;
}
_portStatusChangedHandlerThread = thread_call_allocate((thread_call_func_t)PortStatusChangedHandlerEntry, (thread_call_param_t)this);
if (!_portStatusChangedHandlerThread)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _portStatusChangedHandlerThread", this);
thread_call_free(_initThread);
IOLockFree(_runLock);
IOLockFree(_initLock);
IOLockFree(_removeDeviceLock);
return kIOReturnNoMemory;
}
_addDeviceThread = thread_call_allocate((thread_call_func_t)AddDeviceEntry, (thread_call_param_t)this);
if (!_addDeviceThread)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _addDeviceThread", this);
thread_call_free(_initThread);
thread_call_free(_portStatusChangedHandlerThread);
IOLockFree(_runLock);
IOLockFree(_initLock);
IOLockFree(_removeDeviceLock);
return kIOReturnNoMemory;
}
_enablePowerAfterOvercurrentThread = thread_call_allocate((thread_call_func_t)EnablePowerAfterOvercurrentEntry, (thread_call_param_t)this);
if (!_enablePowerAfterOvercurrentThread)
{
USBLog(2,"AppleUSBHubPort[%p]::init Could not allocate the _enablePowerAfterOvercurrentThread", this);
thread_call_free(_initThread);
thread_call_free(_portStatusChangedHandlerThread);
thread_call_free(_addDeviceThread);
IOLockFree(_runLock);
IOLockFree(_initLock);
IOLockFree(_removeDeviceLock);
return kIOReturnNoMemory;
}
_gate = IOCommandGate::commandGate(this);
if (!_gate)
{
USBError(1, "AppleUSBHubPort[%p]::init - unable to create command gate", this);
return kIOReturnNoMemory;
}
_workLoop = _hub->getWorkLoop();
if ( !_workLoop )
{
USBError(1, "AppleUSBHubPort[%p]::init Couldn't get provider's workloop", this);
OSSafeReleaseNULL(_gate);
return kIOReturnNoMemory;
}
_workLoop->retain();
if ( _workLoop->addEventSource( _gate ) != kIOReturnSuccess )
{
USBError(1, "AppleUSBHubPort[%p]::init Couldn't add gate event source", this);
OSSafeReleaseNULL(_gate);
OSSafeReleaseNULL(_workLoop);
return kIOReturnNoMemory;
}
InitPortVectors();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::start(void)
{
if (_hub && _initThread)
{
USBLog(5, "AppleUSBHubPort[%p]::start: forking init thread", this);
retain(); _hub->retain();
USBLog(6, "AppleUSBHubPort[%p]::start - calling RaisePowerState and IncrementOutstandingIO on hub[%p] port %d", this, _hub, _portNum);
_hub->RaisePowerState(); _hub->IncrementOutstandingIO();
if ( thread_call_enter(_initThread) == TRUE )
{
USBLog(6, "AppleUSBHubPort[%p]::start - calling DecrementOutstandingIO on hub[%p] port %d", this, _hub, _portNum);
_hub->DecrementOutstandingIO();
_hub->release();
USBLog(6, "AppleUSBHubPort[%p]::start - calling LowerPowerState on hub[%p] port %d", this, _hub, _portNum);
_hub->LowerPowerState();
release();
}
USBLog(5, "AppleUSBHubPort[%p]::start: fork complete", this);
}
else
{
USBLog(1, "AppleUSBHubPort[%p]::start: missing _hub or _initThread. Bailing quietly.", this);
}
return kIOReturnSuccess;
}
void
AppleUSBHubPort::free(void)
{
if (_runLock)
{
IOLockFree(_runLock);
_runLock = NULL;
}
if (_initLock)
{
IOLockFree(_initLock);
_initLock = NULL;
}
if (_removeDeviceLock)
{
IOLockFree(_removeDeviceLock);
_removeDeviceLock = NULL;
}
super::free();
}
void
AppleUSBHubPort::stop(void)
{
IOReturn err;
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
retain();
USBLog(3, "AppleUSBHubPort[%p]::stop called, _devZero = (%d).", this, _devZero);
if ( _statusChangedThreadActive || _initThreadActive || _addDeviceThreadActive || _enablePowerAfterOvercurrentThread)
{
UInt32 retries = 0;
IOWorkLoop *myWL = NULL;
IOCommandGate *gate = NULL;
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 1 );
if (_bus)
myWL = _bus->getWorkLoop();
if (!myWL)
{
USBLog(2, "AppleUSBHubPort[%p]::stop called, no workloop.", this);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 2 );
}
else
{
gate = _bus->GetCommandGate();
if (!gate)
{
USBLog(2, "AppleUSBHubPort[%p]::stop - i got the WL but there is no gate.", this);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 3 );
}
if (myWL->onThread())
{
USBLog(2, "AppleUSBHubPort[%p]::stop - i am on the main thread. DANGER AHEAD.", this);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 4 );
}
}
while ( retries < 600 && ( _statusChangedThreadActive || _initThreadActive || _addDeviceThreadActive || _enablePowerAfterOvercurrentThreadActive) )
{
if (!myWL || !gate || myWL->onThread() || !myWL->inGate())
{
USBTrace( kUSBTHubPort, kTPHubPortStop, _portNum, _hub->_locationID, retries, 5 );
IOSleep( 100 );
}
else
{
IOReturn kr = kIOReturnSuccess;
USBLog(2, "AppleUSBHubPort[%p]::stop - trying command sleep (%d/%d/%d/%d).", this, _statusChangedThreadActive, _initThreadActive, _addDeviceThreadActive, _enablePowerAfterOvercurrentThreadActive);
USBTrace( kUSBTHubPort, kTPHubPortStop, _portNum, _hub->_locationID, (_statusChangedThreadActive<<3 || _initThreadActive<<2 || _addDeviceThreadActive<< 1 || _enablePowerAfterOvercurrentThreadActive), 13 );
_inCommandSleep = true;
if (_statusChangedThreadActive)
{
kr = gate->commandSleep(&_statusChangedThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _statusChangedThreadActive commandSleep returned %d", this, kr);
USBTrace( kUSBTHubPort, kTPHubPortStop, kr, _portNum, _hub->_locationID, 6 );
}
}
else if (_initThreadActive)
{
kr = gate->commandSleep(&_initThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _initThreadActive commandSleep returned %d", this, kr);
USBTrace( kUSBTHubPort, kTPHubPortStop, kr, _portNum, _hub->_locationID, 7 );
}
}
else if (_addDeviceThreadActive)
{
kr = gate->commandSleep(&_addDeviceThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _addDeviceThreadActive commandSleep returned %d", this, kr);
USBTrace( kUSBTHubPort, kTPHubPortStop, kr, _portNum, _hub->_locationID, 8 );
}
}
else if (_enablePowerAfterOvercurrentThreadActive)
{
kr = gate->commandSleep(&_enablePowerAfterOvercurrentThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _enablePowerAfterOvercurrentThreadActive commandSleep returned %d", this, kr);
USBTrace( kUSBTHubPort, kTPHubPortStop, kr, _portNum, _hub->_locationID, 9 );
}
}
_inCommandSleep = false;
USBLog(2, "AppleUSBHubPort[%p]::stop - returned from command sleep (%d,%d/%d/%d)!!", this, _statusChangedThreadActive, _initThreadActive, _addDeviceThreadActive, _enablePowerAfterOvercurrentThreadActive);
USBTrace( kUSBTHubPort, kTPHubPortStop, _portNum, _hub->_locationID, (_statusChangedThreadActive<<3 || _initThreadActive<<2 || _addDeviceThreadActive<< 1 || _enablePowerAfterOvercurrentThreadActive), 10 );
}
retries++;
}
}
if ( _statusChangedThreadActive || _initThreadActive || _addDeviceThreadActive || _enablePowerAfterOvercurrentThreadActive)
{
USBLog(2, "AppleUSBHubPort[%p]::stop - not quiesced - just returning", this);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 11 );
release();
return;
}
_isInactive = true;
if (_devZero)
{
USBLog(2, "AppleUSBHubPort[%p]::stop - had devZero, releasing", this);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, _portNum, _hub->_locationID, 12 );
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "AppleUSBHubPort[%p]::stop - calling RemoveDevice", this);
RemoveDevice();
if (v3Bus && (v3Bus->IsControllerAvailable()) && !_hub->isInactive() && !_hub->_portSuspended)
{
#if REMOVE_PORTPOWER_ON_STOP
#if 0
if (_hub->_ssHub && _hub->_isRootHub) {
err = _hub->GetPortStatus(&_portStatus, _portNum);
if (err == kIOReturnSuccess)
{
if (GETLINKSTATE(_portStatus.statusFlags) == kSSHubPortLinkStateU0)
{
err = _hub->SetPortLinkState(kSSHubPortLinkStateU3, _portNum);
if (err != kIOReturnSuccess)
{
USBLog(5, "AppleUSBHubPort[%p]::stop - Port %d of Hub at 0x%x SetPortLinkState(kSSHubPortLinkStateU3)", this, _portNum, (uint32_t)_hub->_locationID);
}
}
}
}
#endif
USBLog(5, "AppleUSBHubPort[%p]::stop - removing port power", this);
if ( (err = _hub->SetPortPower(_portNum, kHubPortPowerOff)) )
{
USBLog(1, "AppleUSBHubPort[%p]::stop - err (%p) from ClearPortFeature(kUSBHubPortPowerFeature)", this, (void*)err);
USBTrace( kUSBTHubPort, kTPHubPortStop, (uintptr_t)this, err, kUSBHubPortPowerFeature, 0 );
}
#endif
}
if (_initThread)
{
thread_call_cancel(_initThread);
thread_call_free(_initThread);
_initThread = 0;
}
if (_portStatusChangedHandlerThread)
{
thread_call_cancel(_portStatusChangedHandlerThread);
thread_call_free(_portStatusChangedHandlerThread);
_portStatusChangedHandlerThread = 0;
}
if (_addDeviceThread)
{
thread_call_cancel(_addDeviceThread);
thread_call_free(_addDeviceThread);
_addDeviceThread = 0;
}
if (_enablePowerAfterOvercurrentThread)
{
thread_call_cancel(_enablePowerAfterOvercurrentThread);
thread_call_free(_enablePowerAfterOvercurrentThread);
_enablePowerAfterOvercurrentThread = 0;
}
if (_gate)
{
if (_workLoop)
_workLoop->removeEventSource(_gate);
OSSafeReleaseNULL(_gate);
}
OSSafeReleaseNULL(_workLoop);
release();
}
void
AppleUSBHubPort::PortInitEntry(OSObject *target)
{
AppleUSBHubPort *me = OSDynamicCast(AppleUSBHubPort, target);
if (!me)
return;
me->PortInit();
me->_hub->release();
me->release();
}
void
AppleUSBHubPort::PortInit()
{
IOUSBHubPortStatus status;
IOReturn err;
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x beginning INIT (getting _initLock)", this, _portNum, (uint32_t) _hub->_locationID);
_initThreadActive = true;
IOLockLock(_initLock);
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x enabling port power", this, _portNum, (uint32_t) _hub->_locationID);
if ((err = _hub->SetPortPower(_portNum, kHubPortPowerOn)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x could not (err = %x) enable port power", this, _portNum, (uint32_t)_hub->_locationID, err);
FatalError(err, "setting port power");
goto errorExit;
}
if (!_captive && !_hub->_treatAllPortsAsCaptive)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x non-captive device - leaving PortInit", this, _portNum, (uint32_t) _hub->_locationID);
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x waiting %d ms for power on", this, _portNum, (uint32_t)_hub->_locationID, _hubDesc->powerOnToGood * 2);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::PortInit - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(_hubDesc->powerOnToGood * 2);
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x about to get port status #1", this, _portNum, (uint32_t) _hub->_locationID);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x could not get (err = %x) port status #1", this, _portNum, (uint32_t)_hub->_locationID, err);
FatalError(err, "getting port status (2)");
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x - status(%04x), change(%04x) bits detected", this, _portNum, (uint32_t)_hub->_locationID, status.statusFlags, status.changeFlags);
if (status.changeFlags & kHubPortConnection)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x - clearing connection change feature", this, _portNum, (uint32_t) _hub->_locationID);
if ((err = _hub->ClearPortFeature(kUSBHubPortConnectionChangeFeature, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x could not (err = %x) clear connection change", this, _portNum, (uint32_t)_hub->_locationID, err);
FatalError(err, "clearing port connection change");
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x about to get port status #2", this, _portNum, (uint32_t) _hub->_locationID);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x could not (err = %x) get port status #2", this, _portNum, (uint32_t)_hub->_locationID, err);
FatalError(err, "getting port status (3)");
goto errorExit;
}
}
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x device detected calling LaunchAddDeviceThread", this, _portNum, (uint32_t) _hub->_locationID);
USBTrace(kUSBTEnumeration, kTPEnumerationCallAddDevice, (uintptr_t)this, _portNum, _hub->_locationID, 0);
LaunchAddDeviceThread();
}
errorExit:
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub at 0x%x - done - releasing _initLock", this, _portNum, (uint32_t) _hub->_locationID);
IOLockUnlock(_initLock);
_initThreadActive = false;
USBLog(6, "AppleUSBHubPort[%p]::PortInit - calling LowerPowerState and DecrementOutstandingIO on hub[%p] port %d", this, _hub, _portNum);
_hub->LowerPowerState();
_hub->DecrementOutstandingIO();
if (_inCommandSleep)
{
IOCommandGate *gate = NULL;
if (_bus)
gate = _bus->GetCommandGate();
if (gate)
{
USBLog(2,"AppleUSBHubPort[%p]::PortInit - calling commandWakeup", this);
gate->commandWakeup(&_initThreadActive, true);
}
}
}
void
AppleUSBHubPort::AddDeviceEntry(OSObject *target)
{
AppleUSBHubPort *me;
if (!target)
{
USBLog(5, "AppleUSBHubPort::AddDeviceEntry - no target!");
return;
}
me = OSDynamicCast(AppleUSBHubPort, target);
if (!me)
{
USBLog(5, "AppleUSBHubPort::AddDeviceEntry - target is not really me!");
return;
}
me->AddDevice();
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceEntry - calling LowerPowerState and release on hub[%p] port %d", me, me->_hub, me->_portNum);
me->_hub->LowerPowerState();
me->_hub->release();
me->_addDeviceThreadActive = false;
if (me->_inCommandSleep)
{
IOCommandGate *gate = NULL;
if (me->_bus)
gate = me->_bus->GetCommandGate();
if (gate)
{
USBLog(2,"AppleUSBHubPort[%p]::AddDeviceEntry - calling commandWakeup", me);
gate->commandWakeup(&me->_addDeviceThreadActive, true);
}
}
me->release();
}
void
AppleUSBHubPort::AddDevice(void)
{
IOReturn err = kIOReturnSuccess;
bool checkingForDeadHub = false;
IOUSBHubPortStatus status;
int i, j;
bool resetActive;
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - start", this, _portNum, (uint32_t) _hub->_locationID);
USBTrace_Start(kUSBTEnumeration, kTPEnumerationAddDevice, (uintptr_t)this, _portNum, _hub->_locationID, 0);
if (_hub->isInactive() || !_hub->_device || _hub->_device->isInactive())
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - hub[%p] is inactive or hub device[%p] is missing or inactive - aborting AddDevice", this, _portNum, (uint32_t) _hub->_locationID, _hub, _hub->_device);
return;
}
if ((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable))
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - hub[%p] changing to power state[%d] - aborting AddDevice", this, _portNum, (uint32_t) _hub->_locationID, _hub, (int)_hub->_powerStateChangingTo);
return;
}
err = _hub->GetPortStatus(&status, _portNum);
if (err)
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - hub[%p] err[%p] getting port status - aborting AddDevice", this, _portNum, (uint32_t) _hub->_locationID, _hub, (void*)err);
return;
}
if (!(status.statusFlags & kHubPortConnection))
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - port no longer connected - aborting AddDevice", this, _portNum, (uint32_t) _hub->_locationID);
return;
}
do
{
if ( !_devZero )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - bus %p - acquiring dev zero lock", this, _portNum, (uint32_t)_hub->_locationID, _bus);
_devZero = AcquireDeviceZero();
if (!_devZero)
{
USBLog(2, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - bus %p - unable to get devZero lock", this, _portNum, (uint32_t)_hub->_locationID, _bus);
FatalError(kIOReturnCannotLock, "acquiring device zero");
break;
}
err = _hub->GetPortStatus(&status, _portNum);
if (err)
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - err[%p] getting port status - aborting AddDevice", this, _portNum, (uint32_t)_hub->_locationID, (void*)err);
break;
}
if (!(status.statusFlags & kHubPortConnection))
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - port no longer connected - aborting AddDevice", this, _portNum, (uint32_t)_hub->_locationID);
err = kIOReturnNotResponding;
break;
}
}
else
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - bus %p - already owned devZero lock", this, _portNum, (uint32_t)_hub->_locationID, _bus);
}
#ifdef SUPPORTS_SS_USB
if(_hub->_ssHub && !_hub->IsHSRootHub()) {
if ( !_getDeviceDescriptorFailed && GETLINKSTATE(status.statusFlags) == kSSHubPortLinkStateU0 )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - External Superspeed hub, skipping reset", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_portStatus = status;
err = CallAddDeviceResetChangeHandlerDirectly(_portStatus.changeFlags, _portStatus.statusFlags);
break;
}
else
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - External Superspeed hub, but link is not in U0 (it is in %s) or _getDeviceDescriptorFailed (%d), so issuing a reset", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, _hub->LinkStateName(GETLINKSTATE(status.statusFlags)), _getDeviceDescriptorFailed);
}
}
#endif
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - resetting port", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
USBTrace(kUSBTEnumeration, kTPEnumerationResetPort, (uintptr_t)this, _portNum, _hub->_locationID, 0);
SetPortVector(&AppleUSBHubPort::AddDeviceResetChangeHandler, kHubPortBeingReset);
_delayOnStatusChange = true;
if ( _hub->_ssHub && _getDeviceDescriptorFailed )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - issuing a Warm Reset", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
err = _hub->SetPortFeature(kUSBHubPortBHPortResetFeature, _portNum);
}
else
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - resetting port", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
}
if (err)
{
if ( err != kIOUSBDeviceNotHighSpeed)
{
USBLog(1, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - unable (err = %x) to reset port (set feature (resetting port)", this, _portNum, (uint32_t)_hub->_locationID, err);
USBTrace( kUSBTHubPort, kTPHubPortAddDevice, _portNum, (uintptr_t)_hub, err, 1 );
}
if (_portDevice)
{
USBLog(1,"AppleUSBHubPort: Removing %s from Port %d of Hub at 0x%x", _portDevice->getName(), _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortAddDevice, _portNum, (uintptr_t)_hub, _hub->_locationID, 2 );
RemoveDevice();
}
if (err == kIOUSBTransactionTimeout)
{
_hub->CallCheckForDeadHub(); checkingForDeadHub = true;
}
break;
}
IOSleep(1);
err = _hub->GetPortStatus(&status, _portNum);
j=0;
resetActive = false;
if ((status.statusFlags & kHubPortBeingReset) || (status.changeFlags & kHubPortBeingReset) || (_state == hpsSetAddress))
resetActive = true;
if (!(status.statusFlags & kHubPortConnection))
err = kIOReturnInternalError;
while (j++ < 5 && !resetActive && !err)
{
i = 0;
while ((i++ < 50) && !err)
{
err = _hub->GetPortStatus(&status, _portNum);
if (!_devZero || (status.statusFlags & kHubPortBeingReset) || (status.changeFlags & kHubPortBeingReset) || (_state == hpsSetAddress))
{
if (!_devZero)
{
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - in loop (j:%d i:%d) and devZero is false. bailing", this, (int)j, (int)i);
}
resetActive = true;
break; }
if (!(status.statusFlags & kHubPortConnection))
{
err = kIOReturnInternalError;
break;
}
USBLog(2, "AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - port not in reset after %d ms", this, _portNum, (uint32_t)_hub->_locationID, i);
if (i == 50)
{
if (!_devZero)
{
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - got to second SetPortFeature and devZero is false. bailing", this);
err = kIOReturnInternalError;
break;
}
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - retrying SetPortReset loop (j:%d i:%d), _state: %d !!", this, (int)j, (int)i, _state);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDevice - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(10);
}
}
if ( !resetActive)
{
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - port not in reset after 5 retries", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortAddDevice, (uintptr_t)this, _portNum, 0, 3 );
err = kIOReturnInternalError;
}
} while(false);
if (err && _devZero)
{
USBLog(3, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - got error (%x) - releasing devZero lock", this, _portNum, (uint32_t)_hub->_locationID, err);
if (!checkingForDeadHub)
{
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice ClearPortFeature for Port %d returned 0x%x", this, _portNum, err);
FatalError(err, "clearing port feature (1)");
if (err == kIOUSBTransactionTimeout)
{
_hub->CallCheckForDeadHub(); checkingForDeadHub = true;
}
}
}
_bus->ReleaseDeviceZero();
_devZero = false;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
}
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub at 0x%x - (err = %x) done - (0x%04x, 0x%04x), returning", this, _portNum, (uint32_t)_hub->_locationID, err, status.statusFlags, status.changeFlags);
USBTrace_End(kUSBTEnumeration, kTPEnumerationAddDevice, (uintptr_t)this, _portNum, _hub->_locationID, err);
}
IOReturn
AppleUSBHubPort::LaunchAddDeviceThread()
{
IOReturn err = kIOReturnNotPermitted;
if (_gate && _workLoop)
{
IOCommandGate * gate = _gate;
IOWorkLoop * workLoop = _workLoop;
retain();
_hub->retain();
workLoop->retain();
gate->retain();
USBLog(6, "AppleUSBHubPort[%p]::LaunchAddDeviceThread - calling runAction(LaunchAddDeviceThreadGated) for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
err = gate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleUSBHubPort::LaunchAddDeviceThreadGated));
if ( err != kIOReturnSuccess )
{
USBLog(2,"AppleUSBHubPort[%p]::LaunchAddDeviceThread _LaunchAddDeviceThreadGated runAction failed (0x%x)", this, err);
}
gate->release();
workLoop->release();
_hub->release();
release();
}
return err;
}
IOReturn
AppleUSBHubPort::LaunchAddDeviceThreadGated()
{
if ( IsInactive() )
{
USBLog(6, "AppleUSBHubPort[%p]::LaunchAddDeviceThreadGated - port object is inActive() for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
return kIOReturnNotPermitted;
}
if ( _addDeviceThreadActive )
{
USBLog(6, "AppleUSBHubPort[%p]::LaunchAddDeviceThreadGated - already running _addDeviceThreadActive for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
return kIOReturnSuccess;
}
retain();
_hub->retain();
_hub->RaisePowerState(); USBLog(6, "AppleUSBHubPort[%p]::LaunchAddDeviceThreadGated - calling AddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
_addDeviceThreadActive = true;
if (thread_call_enter(_addDeviceThread) == true)
{
USBLog(1, "AppleUSBHubPort[%p]::LaunchAddDeviceThreadGated - cannot call out to AddDevice for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
_hub->LowerPowerState();
_hub->release();
release();
_addDeviceThreadActive = false;
}
return kIOReturnSuccess;
}
#ifdef SUPPORTS_SS_USB
IOReturn
AppleUSBHubPort::CallAddDeviceResetChangeHandlerDirectly(UInt16 portChange, UInt16 portStatus)
{
IOReturn err = kIOReturnSuccess;
int retries = 10;
while (retries > 0 && !IOLockTryLock(_runLock))
{
USBLog(5, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly: port %d already had _runlock, setting waiting 50ms (retries %d)", this, _portNum, retries);
retries--;
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly - IOSleep in gate: %d", this, 1);}}
#endif
IOSleep(50);
}
if (retries == 0)
{
USBLog(3, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly: port %d @ 0x%x, was not able to get _runLock. Possible problems ahead", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
}
if ( !IOLockTryLock(_initLock) )
{
USBLog(3, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly: _initLock for port %d @ 0x%x held! Waiting...", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
IOLockLock(_initLock);
USBLog(3, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly: _initLock for port %d released!", this, _portNum);
}
USBLog(5, "AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly: port %d obtained _initLock", this, _portNum);
_statusChangedState = 0;
_statusChangedThreadActive = true;
err = AddDeviceResetChangeHandler(portChange, portStatus);
if ( err != kIOReturnSuccess )
{
if ( _attachMessageDisplayed )
{
{
USBError(1,"[%p] The IOUSBFamily was not able to enumerate a device.", this);
}
_attachMessageDisplayed = false;
}
if ( _devZero )
{
USBLog(5,"AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly - port %d - err = %x - done, releasing Dev Zero lock", this, _portNum, err);
_bus->ReleaseDeviceZero();
_devZero = false;
}
}
USBLog(5,"AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly - port %d - err = %x - done, releasing _runLock", this, _portNum, err);
IOLockUnlock(_runLock);
IOLockUnlock(_initLock);
_statusChangedThreadActive = false;
if (_inCommandSleep)
{
IOCommandGate *gate = NULL;
if (_bus)
gate = _bus->GetCommandGate();
if (gate)
{
USBLog(3,"AppleUSBHubPort[%p]::CallAddDeviceResetChangeHandlerDirectly - calling commandWakeup", this);
gate->commandWakeup(&_statusChangedThreadActive, true);
}
}
return err;
}
#endif
void
AppleUSBHubPort::RemoveDevice(void)
{
bool ok;
const IORegistryPlane *usbPlane;
IOUSBDevice *cachedPortDevice;
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
IOLockLock(_removeDeviceLock);
cachedPortDevice = _portDevice;
_portDevice = NULL;
bzero(&_desc, sizeof(_desc));
IOLockUnlock(_removeDeviceLock);
if (cachedPortDevice)
{
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice start (%s) port %d @ 0x%x", this, cachedPortDevice->getName(), (uint32_t)_portNum, (uint32_t)_hub->_locationID);
usbPlane = cachedPortDevice->getPlane(kIOUSBPlane);
if (v3Bus)
{
v3Bus->CheckPMAssertions(cachedPortDevice, false);
}
if ( _usingExtraPortPower )
{
#ifdef SUPPORTS_SS_USB
#endif
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice returning _portPowerAvailable to kUSB100mAAvailable", this);
_portPowerAvailable = kUSB100mAAvailable;
_usingExtraPortPower = false;
}
if ( _hasExternalConnector )
{
USBLog(6, "AppleUSBHubPort[%p]::RemoveDevice - Port %d of Hub at 0x%x on an external connector, increasing unconnected port count on hub", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_hub->_device->UpdateUnconnectedExternalPorts(1);
}
if ( usbPlane )
cachedPortDevice->detachAll(usbPlane);
if (_hub && !_hub->isInactive())
{
UInt32 retries = 100;
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice - hub still active - terminating device[%p] synchronously", this, cachedPortDevice);
while (cachedPortDevice->getBusyState() && retries--)
{
USBLog(2, "AppleUSBHubPort[%p]::RemoveDevice - device(%p)[%s] busy - waiting 100ms (retries remaining: %d)", this, cachedPortDevice, cachedPortDevice->getName(), (int)retries);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::RemoveDevice - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(100);
}
if (cachedPortDevice->getBusyState())
{
USBError(1, "AppleUSBHubPort: Port %d of Hub at 0x%x about to terminate a busy device (%s) after waiting 10 seconds", _portNum, (uint32_t)_hub->_locationID, cachedPortDevice->getName());
}
cachedPortDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
}
else
{
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice - hub no longer active - terminating device[%p] aynchronously", this, cachedPortDevice);
cachedPortDevice->terminate(kIOServiceRequired);
}
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice releasing(%p)", this, cachedPortDevice);
cachedPortDevice->release();
}
else
{
USBLog(3, "AppleUSBHubPort[%p]::RemoveDevice - looks like someone beat us to it", this);
}
InitPortVectors();
}
IOReturn
AppleUSBHubPort::Suspend( bool fromDevice, bool portStatusSuspended )
{
IOReturn status = kIOReturnSuccess;
if ( fromDevice and _portPMState == usbHPPMS_pm_suspended )
{
USBLog(3, "AppleUSBHubPort[%p]::Suspend - converting suspend state from pm_suspended to drvr_suspended portStatusSuspended(%d)", this, portStatusSuspended);
if ( portStatusSuspended )
{
IOUSBControllerV3 *v3Bus = NULL;
if (_hub)
{
if (_hub->_device)
v3Bus = OSDynamicCast(IOUSBControllerV3, _hub->_device->GetBus());
if (v3Bus && _portDevice)
{
USBLog(5, "AppleUSBHub[%p]::Suspend - Enabling endpoints for device at address (%d)", this, (int)_portDevice->GetAddress());
status = v3Bus->EnableAddressEndpoints(_portDevice->GetAddress(), true);
if (status)
{
USBLog(2, "AppleUSBHub[%p]::Suspend - EnableAddressEndpoints returned (%p)", this, (void*)status);
}
}
}
}
else
{
USBError(1, "AppleUSBHub[%p]::Suspend - expected port to be suspended for conversion, but it is not!!", this);
}
}
_portPMState = ( fromDevice ) ? usbHPPMS_drvr_suspended : usbHPPMS_pm_suspended ;
status = _hub->SetPortFeature(kUSBHubPortSuspendFeature, _portNum);
if ( status != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHubPort[%p]::Suspend Could not SetPortFeature (%d) (kUSBHubPortSuspendFeature): (0x%x)", this, _portNum, status);
}
else
{
WaitForSuspendCommand( &_portPMState, 10 );
}
return status;
}
IOReturn
AppleUSBHubPort::Resume( )
{
IOReturn status = kIOReturnSuccess;
USBLog(5, "AppleUSBHubPort[%p]::Resume - calling ClearPortFeature", this);
status = _hub->ClearPortFeature(kUSBHubPortSuspendFeature, _portNum);
if ( status != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHubPort[%p]::Resume Could not ClearPortFeature (%d) (kUSBHubPortSuspendFeature): (0x%x)", this, _portNum, status);
SetPortVector(&AppleUSBHubPort::DefaultSuspendChangeHandler, kHubPortSuspend);
}
else
{
_resumePending = true;
USBLog(2, "AppleUSBHubPort[%p]::Resume - RESUME - calling RaisePowerState on hub[%p] port %d and setting _lowerPowerStateOnResume", this, _hub, _portNum);
_hub->RaisePowerState();
if (_lowerPowerStateOnResume)
{
USBLog(1, "AppleUSBHubPort[%p]::Resume - _lowerPowerStateOnResume already set (hub %p port %d)- UNEXPECTED!", this, _hub, _portNum);
}
USBLog(5, "AppleUSBHubPort[%p]::Resume - setting _lowerPowerStateOnResume - (hub %p port %d)", this, _hub, _portNum);
_lowerPowerStateOnResume = true;
WaitForSuspendCommand( &_portPMState, 100 );
}
return status;
}
void
AppleUSBHubPort::MessageDeviceClients( UInt32 type, void * argument, vm_size_t argSize )
{
IOUSBDevice *cachedDevice = _portDevice; if ( cachedDevice )
{
cachedDevice->retain();
cachedDevice->messageClients( type, argument, argSize );
cachedDevice->release();
}
}
IOReturn
AppleUSBHubPort::SuspendPort( bool suspend, bool fromDevice )
{
IOReturn status = kIOReturnSuccess;
IOUSBHubPortStatus hubPortStatus;
UInt32 resumeRetries = 10;
OSBoolean *expressCardCantWakeRef;
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort(%s) for port %d fromDevice(%s), _resumePending(%d), isInactive(%s)", this, suspend ? "suspend" : "resume", _portNum, fromDevice ? "true" : "false", _resumePending, _hub->isInactive() ? "true" : "false");
while ( _resumePending and resumeRetries > 0 )
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::SuspendPort - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(10);
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort(%s) for port %d, waiting for _resumePending %d", this, suspend ? "suspend" : "resume", (uint32_t)_portNum, (uint32_t)resumeRetries);
resumeRetries--;
}
if ( resumeRetries == 0 )
{
USBLog(2, "AppleUSBHubPort[%p]::SuspendPort(%s) for port %d, did not clear the resumePending flag", this, suspend ? "suspend" : "resume", _portNum);
}
if (_hub->isInactive())
{
if ( not suspend && (_portPMState == usbHPPMS_drvr_suspended) )
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort(resume) on port(%d)- Inactive hub, doing for free!", this, _portNum);
_portPMState = usbHPPMS_active;
}
else
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort on port(%d) - not doing anything (%s) _portDevice(%p) _portPMState(%d) !", this, _portNum, suspend ? "suspend" : "resume", _portDevice, (int)_portPMState);
}
}
else
{
status = _hub->GetPortStatus(&hubPortStatus, _portNum);
if ( status != kIOReturnSuccess )
{
USBLog(3,"AppleUSBHubPort[%p]::SuspendPort Could not get Port Status: 0x%x", this, status);
return status;
}
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort - GetPortStatus returned status[%p] change[%p]", this, (void*)hubPortStatus.statusFlags, (void*)hubPortStatus.changeFlags );
USBLog(7, "AppleUSBHubPort[%p]::SuspendPort - setting vector to HandleSuspendPortHandler", this);
SetPortVector(&AppleUSBHubPort::HandleSuspendPortHandler, kHubPortSuspend);
if ( suspend )
{
status = Suspend( fromDevice, hubPortStatus.statusFlags & kHubPortSuspend );
if( HasExpressCardCantWake() || _detectedExpressCardCantWake )
{
USBLog(1, "AppleUSBHubPort[%p]::SuspendPort - (%s) has kUSBExpressCardCantWake disabling port", this, _portDevice->getName() );
IOReturn err = kIOReturnSuccess;
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(1, "AppleUSBHubPort[%p]::SuspendPort - port %d, unable (err = %x) to disable port", this, _portNum, err);
}
}
}
else
{
if ( not (hubPortStatus.statusFlags & kHubPortSuspend) )
{
USBLog(5,"AppleUSBHubPort[%p]::SuspendPort Port was NOT suspended", this);
status = kIOUSBDevicePortWasNotSuspended;
}
else
{
status = Resume();
}
}
}
return status;
}
bool
AppleUSBHubPort::HasExpressCardCantWake()
{
bool result = false;
OSBoolean *expressCardCantWakeRef;
if ( _portDevice && _hub->_hubWithExpressCardPort && (_hub->_expressCardPort == _portNum) )
{
expressCardCantWakeRef = OSDynamicCast( OSBoolean, _portDevice->getProperty(kUSBExpressCardCantWake) );
if ( expressCardCantWakeRef && expressCardCantWakeRef->isTrue() )
{
result = true;
}
}
return result;
}
IOReturn
AppleUSBHubPort::ReEnumeratePort(UInt32 options)
{
if ( IsInactive() )
{
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- port %d of hub @ 0x%x: port is inactive",this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
return kIOReturnNotPermitted;
}
retain();
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- reenumerating port %d, options 0x%x",this, (uint32_t)_portNum, (uint32_t)options);
if ( (options & kUSBAddExtraResetTimeMask) )
{
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- reenumerating port %d, options 0x%x",this, (uint32_t)_portNum, (uint32_t)options);
_extraResetDelay = true;
}
else
{
_extraResetDelay = false;
}
RemoveDevice();
if ( IsInactive() )
{
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- port %d of hub @ 0x%x: port is now inactive",this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
release();
return kIOReturnNotPermitted;
}
USBLog(6, "AppleUSBHubPort[%p]::ReEnumeratePort - calling LaunchAddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
_portPMState = usbHPPMS_active; LaunchAddDeviceThread();
release();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::ClearTT(bool multiTTs, UInt32 options)
{
IOReturn err = kIOReturnSuccess;
UInt8 deviceAddress; UInt8 endpointNum; UInt8 endpointType; UInt8 IN; UInt32 opts= options;
UInt16 wValue, wIndex;
IOUSBDevRequest request;
deviceAddress = options & 0xff;
options >>= 8;
endpointNum = options & 0xff;
options >>= 8;
endpointType = options & 0xff;
options >>= 8;
IN = options & 0xff;
options >>= 8;
wValue = 0;
wValue = endpointNum & 0xf;
wValue |= (deviceAddress & 0x7f) << 4;
wValue |= (endpointType & 0x3) << 11;
wValue |= (IN & 0x1) << 15;
if (multiTTs)
{
wIndex = _portNum;
}
else
{
wIndex = 1;
}
request.bmRequestType = 0x23;
request.bRequest = 8;
request.wValue = wValue;
request.wIndex = wIndex;
request.wLength = 0;
request.pData = NULL;
request.wLenDone = 0;
err = _hub->DoDeviceRequestWithRetries(&request);
USBLog(5,"AppleUSBHubPort[%p]::ClearTT -- port %d, options:%X, wValue:%X, wIndex:%X, IOReturn: 0x%x",this, (uint32_t)_portNum, (uint32_t)opts, wValue, wIndex, err);
if ( (err == kIOReturnSuccess) && (endpointType == 0) ) {
wValue ^= (1 << 15); request.wValue = wValue;
err = _hub->DoDeviceRequestWithRetries(&request);
USBLog(5,"AppleUSBHubPort[%p]::ClearTT -- do it again for control transactions, wValue:%X, IOReturn: 0x%x",this, wValue, err);
}
return err;
}
IOReturn
AppleUSBHubPort::ResetPort()
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
IOUSBHubPortStatus portStatus;
bool wait100ms = false;
#ifdef SUPPORTS_SS_USB
UInt16 linkState;
#endif
USBLog(1, "AppleUSBHubPort[%p]::Resetting device %s: port %d of Hub at 0x%x", this, _portDevice ? _portDevice->getName() : "Unknown" , _portNum, (uint32_t)_hub->_locationID);
if ( ShouldApplyDisconnectWorkaround() )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, will wait 500 ms", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::ResetPort - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(500);
wait100ms = true;
}
if (!IOLockTryLock(_runLock))
{
USBLog(1, "AppleUSBHubPort[%p]::ResetPort: port %d is processing a status change, returning kIOReturnBusy", this, _portNum);
_retryPortStatus = true;
return kIOReturnBusy;
}
IOLockUnlock(_runLock);
err = _hub->GetPortStatus(&portStatus, _portNum);
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
linkState = GETLINKSTATE(portStatus.statusFlags);
USBLog(5, "AppleUSBHubPort[%p]::ResetPort port (%d) - link state: 0x%x (%s)", this, _portNum, linkState, _hub->LinkStateName(linkState));
if (linkState == kSSHubPortLinkStateU3)
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort port (%d) - unsuspending", this, _portNum);
(void) _hub->ClearPortFeature(kUSBHubPortSuspendChangeFeature, _portNum);
}
}
else
#endif
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort Port %d of hub @ 0x%x (isRootHub: %d), status = 0x%x, change: 0x%x", this, _portNum, (uint32_t) _hub->_locationID, _hub->_isRootHub, portStatus.statusFlags, portStatus.changeFlags );
}
int retries = 4;
err = kIOReturnBusy;
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
retries = 6;
}
#endif
while ( (retries-- > 0) && ( err != kIOReturnSuccess) )
{
do {
UInt16 feature = kUSBHubPortResetFeature;
_devZero = AcquireDeviceZero();
if (!_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort for port %d could not get devZero lock", this, _portNum);
err = kIOReturnCannotLock;
break;
}
SetPortVector(&AppleUSBHubPort::HandleResetPortHandler, kHubPortBeingReset);
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub && (retries > 2))
{
feature = kUSBHubPortBHPortResetFeature;
}
#endif
USBLog(5, "AppleUSBHubPort[%p]::ResetPort Port (%d) calling SetPortFeature(%d) retries: %d)", this, _portNum, feature, retries);
err = _hub->SetPortFeature(feature, _portNum);
if (err != kIOReturnSuccess)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort Could not SetPortFeature(%d) on port (%d): err = (0x%x)", this, _portNum, feature, err);
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
break;
}
if ( wait100ms )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, waiting for 100ms after reset", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::ResetPort - IOSleep in gate:%d", this, 2);}}
#endif
IOSleep(100);
}
} while (false);
if (err == kIOReturnSuccess)
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, waiting for reset handler to fire", this, _portNum);
_resetPending = true;
_bus->WaitForReleaseDeviceZero();
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, devZero lock was released, reset handler must've occurred (_resetPending = %d)", this, _portNum, _resetPending);
if (_resetPending)
{
err = kIOReturnBusy;
_resetPending = false;
}
}
else if (_devZero)
{
_bus->ReleaseDeviceZero();
_devZero = false;
}
if (err != kIOReturnSuccess)
{
IOReturn kr = _hub->GetPortStatus(&portStatus, _portNum);
if ( kr == kIOReturnSuccess)
{
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
UInt16 linkState = GETLINKSTATE(portStatus.statusFlags);
USBLog(6, "AppleUSBHubPort[%p]::ResetPort - Port %d of Hub at 0x%x status: (0x%04x,0x%04x), LinkState: 0x%x (%s state)", this, _portNum, (uint32_t)_hub->_locationID, portStatus.statusFlags, portStatus.changeFlags, linkState, _hub->LinkStateName(linkState));
if ( linkState == kSSHubPortLinkStateRxDetect )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort - port %d, port in Rx.Detect, so bail", this, _portNum);
retries = 0;
}
}
else
#endif
{
if ( !(portStatus.statusFlags & kHubPortConnection) )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort - port %d, no device attached, so bail", this, _portNum);
retries = 0;
}
}
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort - port %d, could not get PortStatus: 0x%x", this, _portNum, (uint32_t)err);
retries = 0;
}
}
}
if (err && _portDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenReset, cachedDevice, &err);
cachedDevice->release();
}
}
if ( err != kIOReturnSuccess)
{
IOReturn kr = _hub->GetPortStatus(&portStatus, _portNum);
if ( (kr == kIOReturnSuccess) && (portStatus.statusFlags & kHubPortConnection))
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort - port %d, we have a reset error (0x%x), but we still have a connection, call RemoveDevice() and LaunchAddDeviceThread() )", this, _portNum, err);
RemoveDevice();
LaunchAddDeviceThread();
}
}
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, returning 0x%x", this, _portNum, (uint32_t)err);
return err;
}
void
AppleUSBHubPort::FatalError(IOReturn err, const char *str)
{
if (_hub->IsHSRootHub())
{
if (err != kIOUSBDeviceTransferredToCompanion)
{
USBLog(1, "AppleUSBHubPort[%p]:FatalError - Port %d of Hub at 0x%x: error 0x%x: %s", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, err, str);
USBTrace( kUSBTHubPort, kTPHubPortFatalError, err, _portNum, _hub->_locationID, 1 );
}
}
else
{
USBError(1, "AppleUSBHubPort[%p]::FatalError - Port %d of Hub at 0x%x reported error 0x%x while doing %s", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, err, str);
}
if (_portDevice)
{
USBLog(1,"AppleUSBHubPort[%p]::FatalError - Removing %s from Port %d of Hub at 0x%x", this, _portDevice->getName(), _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortFatalError, (uintptr_t)_portDevice, _portNum, _hub->_locationID, 2 );
RemoveDevice();
}
}
static IOReturn DoCreateDevice( IOUSBController *bus,
IOUSBDevice *newDevice,
USBDeviceAddress deviceAddress,
UInt8 maxPacketSize,
UInt8 speed,
UInt32 powerAvailable,
USBDeviceAddress hub,
int port)
{
IOUSBControllerV2 *v2Bus;
v2Bus = OSDynamicCast(IOUSBControllerV2, bus);
if (v2Bus != 0)
{
return(v2Bus->CreateDevice(newDevice, deviceAddress, maxPacketSize, speed, powerAvailable, hub, port));
}
else
{
return(bus->CreateDevice(newDevice, deviceAddress, maxPacketSize, speed, powerAvailable));
}
}
static IOReturn DoConfigureDeviceZero(IOUSBController *bus, UInt8 maxPacketSize, UInt8 speed, USBDeviceAddress hub, int port)
{
IOUSBControllerV2 *v2Bus;
IOReturn kr = kIOReturnSuccess;
v2Bus = OSDynamicCast(IOUSBControllerV2, bus);
USBLog(5, "AppleUSBHubPort[%p]::DoConfigureDeviceZero - maxPacketSize: %d, speed: %d, hub: %d, port: %d", v2Bus, maxPacketSize, speed, hub, port);
if (v2Bus != 0)
{
kr = v2Bus->ConfigureDeviceZero(maxPacketSize, speed, hub, port);
}
else
{
kr = bus->ConfigureDeviceZero(maxPacketSize, speed);
}
return kr;
}
IOReturn
AppleUSBHubPort::AddDeviceResetChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOReturn err = kIOReturnSuccess;
IOReturn err2 = kIOReturnSuccess;
IOUSBDevice * usbDevice;
USBDeviceAddress address;
UInt32 delay = 10;
const IORegistryPlane * usbPlane;
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _bus);
UInt16 packetSize = 8;
USBLog(5, "***** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - start - status(0x%04x) change (0x%04x)", this, _portNum, (uint32_t)_hub->_locationID, (int)statusFlags, (int)changeFlags);
USBTrace_Start(kUSBTEnumeration, kTPEnumerationAddDeviceResetChangeHandler, (uintptr_t)this, _portNum, _hub->_locationID, err);
#ifdef SUPPORTS_SS_USB
_portLinkErrorCount = 0; #endif
if ( _extraResetDelay )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - delaying 100ms workaround", this);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(100);
_extraResetDelay = false;
}
do
{
if (_state != hpsDeadDeviceZero)
{
if (changeFlags & kHubPortEnabled)
{
USBLog(2, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d - enabled bit is set in the change flags", this, _portNum);
}
if ( !(statusFlags & kHubPortConnection) )
{
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d - device has gone away", this, _portNum);
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
break;
}
if (changeFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d - device appears to have gone away and then come back", this, _portNum);
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
break;
}
if (_portStatus.statusFlags & kHubPortBeingReset)
{
USBLog(5, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - leaving (kHubPortBeingReset)", this, _portNum, (uint32_t) _hub->_locationID);
break;
}
if (_getDeviceDescriptorFailed)
{
delay = 300;
USBLog(3, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - new delay %d", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - delaying %d ms", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 2);}}
#endif
IOSleep(delay);
if (_portStatus.statusFlags & kHubPortLowSpeed)
{
_speed = kUSBDeviceSpeedLow;
packetSize = 8;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - found low speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
else if (_portStatus.statusFlags & kHubPortHighSpeed)
{
_speed = kUSBDeviceSpeedHigh;
packetSize = 64;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - found high speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
#ifdef SUPPORTS_SS_USB
else if (_hub->_ssHub && _portStatus.statusFlags & kHubPortSuperSpeed) {
_speed = kUSBDeviceSpeedSuper;
packetSize = 9;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - found super speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
#endif
else
{
_speed = kUSBDeviceSpeedFull;
packetSize = 8;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - found full speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - configuring dev zero", this, _portNum, (uint32_t) _hub->_locationID);
err = DoConfigureDeviceZero(_bus, packetSize, _speed, _hub->_device->GetAddress(), _portNum);
if ( err != kIOReturnSuccess )
{
#ifdef SUPPORTS_SS_USB
if ( err == kIOUSBDeviceCountExceeded)
{
USBLog(1, "AppleUSBHubPort[%p]::DoConfigureDeviceZero Port %d of hub at 0x%x. Cannot create USB device (kIOUSBDeviceCountExceeded)", this, _portNum, (uint32_t)_hub->_locationID);
IOLog("The USB stack is not able to enumerate the device at Port %d of hub at 0x%x because the USB hardware ran out of device slots", _portNum, (uint32_t)_hub->_locationID);
_hub->_device->messageClients(kIOUSBMessageDeviceCountExceeded, &_portNum, sizeof(int) );
}
if ( err == kIOUSBEndpointCountExceeded )
{
_hub->_device->messageClients(kIOUSBMessageEndpointCountExceeded, NULL, 0 );
}
#endif
USBLog(5, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - failed to create device zero, detach'ing device", this, _portNum, (uint32_t) _hub->_locationID);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
FatalError(err, "clearing port feature (2)");
}
_bus->ReleaseDeviceZero();
_devZero = false;
_portDevice = NULL;
return err;
}
_getDeviceDescriptorFailed = true;
bzero(&_desc, sizeof(_desc));
USBLog(5, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - getting dev zero desc", this, _portNum, (uint32_t) _hub->_locationID);
err = GetDevZeroDescriptorWithRetries();
if ( err != kIOReturnSuccess )
{
USBLog(5, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub at 0x%x - failed to get dev zero desc, detach'ing device", this, _portNum, (uint32_t) _hub->_locationID);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
FatalError(err, "clearing port feature (2)");
_bus->ReleaseDeviceZero();
_devZero = false;
_portDevice = NULL;
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
return DetachDevice();
}
USBLog(5,"**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, using %d for maxPacketSize", this, _portNum, _desc.bMaxPacketSize0);
}
if (_setAddressFailed > 0)
{
delay = ((_setAddressFailed) * 30) + (_setAddressFailed * 3);
USBLog(1, "**4** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, previous SetAddress failed, sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 3);}}
#endif
IOSleep(delay);
}
if ( err == kIOReturnSuccess )
_getDeviceDescriptorFailed = false;
_state = hpsSetAddress;
if (_desc.bDeviceClass == kUSBHubClass)
{
if ( (_hub->_locationID) & 0x000000F0 )
{
USBLog(1,"**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Port %d of Hub at 0x%x, we have a hub, but this would be the 6th hub in the bus, which is illegal. Erroring out", this, _portNum, (uint32_t)_hub->_locationID );
USBError(1,"A USB Hub (connected to the hub at 0x%x) has been plugged in but it will result in an illegal configuration. The hub will not be enabled.", (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortAddDeviceResetChangeHandler, (uintptr_t)this, _portNum, _hub->_locationID, 1 );
_bus->ReleaseDeviceZero();
_devZero = false;
_portDevice = NULL;
err = kIOReturnNoDevice;
break;
}
usbDevice = _bus->MakeHubDevice( &address );
}
else
usbDevice = _bus->MakeDevice( &address );
if (usbDevice == NULL || address == 0)
{
USBLog(1,"**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Port %d of Hub at 0x%x, unable to set device %p to address %d - disabling port", this, _portNum, (uint32_t)_hub->_locationID, usbDevice, address );
USBTrace( kUSBTHubPort, kTPHubPortAddDeviceResetChangeHandler, _portNum, _hub->_locationID, (uintptr_t)usbDevice, address);
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
FatalError(err, "clearing port feature (3)");
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
_portDevice = NULL;
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
return DetachDevice();
}
else
{
if ( _addDeviceThreadActive)
{
USBLog(7, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d of hub @ 0x%x, _addDeviceThreadActive after SetAddress(), before IOSleep(2) ", this, _portNum, (uint32_t)_hub->_locationID);
}
IOSleep( 2 );
USBLog(5, "**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, Releasing DeviceZero after successful SetAddress to %d", this, _portNum, address);
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsNormal;
}
if ( _state == hpsDeadDeviceZero )
{
_setAddressFailed++;
USBLog(3, "**6** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, setaddressfailed = %d, disabling port", this, _portNum, _setAddressFailed);
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
}
if (_devZero)
{
USBLog(3, "**6** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, releasing devZero lock", this, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**7** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, setting state to hpsSetAddressFailed", this, _portNum);
_state = hpsSetAddressFailed;
}
else
{
delay = (_setAddressFailed * 30) + (_setAddressFailed * 3);
if ( delay )
{
USBLog(3, "**8** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 4);}}
#endif
IOSleep(delay);
}
}
if ( (err != kIOReturnSuccess) && (_state != hpsNormal) )
{
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, err = %x, disabling port", this, _portNum, err);
_retryPortStatus = true;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
}
if (_devZero)
{
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, releasing devZero lock", this, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, delaying 10 ms and calling AddDevice", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 5);}}
#endif
IOSleep(10);
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - calling LaunchAddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
LaunchAddDeviceThread();
return kIOReturnSuccess;
}
_state = hpsNormal;
err = DoCreateDevice(_bus, usbDevice, address, _desc.bMaxPacketSize0, _speed, _portPowerAvailable, _hub->_device->GetAddress(), _portNum);
if ( err == kIOReturnSuccess )
{
usbDevice->retain();
_portDevice = usbDevice;
if ( _printConnectIOLog )
{
_printConnectIOLog = false;
IOLog("The USB device %s (Port %d of Hub at 0x%x) may have caused a wake by being connected\n", _portDevice ? _portDevice->getName() : "UNKNOWN", _portNum, (uint32_t)GetHub()->_locationID);
}
}
else
{
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, did NOT get _portDevice", this, _portNum);
err = err2;
usbDevice->release();
usbDevice = NULL;
}
if (!_portDevice)
{
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, usbDevice disappeared, cleaning up", this, _portNum);
_retryPortStatus = true;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
}
if (_devZero)
{
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, releasing devZero lock", this, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**9** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, delaying 10 ms and calling AddDevice", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 6);}}
#endif
IOSleep(10); USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - calling LaunchAddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
LaunchAddDeviceThread();
return kIOReturnSuccess;
}
USBLog(5, "**10** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, at addr: %d, Successful", this, _portNum, address);
_attachRetry = 0;
_attachRetryFailed = false;
if ( _attachMessageDisplayed )
{
USBError(1,"[%p] The IOUSBFamily has successfully enumerated the device.", this);
_attachMessageDisplayed = false;
}
usbPlane = usbDevice->getPlane(kIOUSBPlane);
if ( usbPlane )
{
usbDevice->attachToParent( _hub->_device, usbPlane);
}
else
{
USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - we could not get the kIOUSBPlane!! Problems ahead", this);
USBTrace( kUSBTHubPort, kTPHubPortAddDeviceResetChangeHandler, (uintptr_t)this, (uintptr_t)usbPlane, 0, 2);
}
usbDevice->setProperty("PortNum",_portNum,32);
usbDevice->SetProperties();
usbDevice->SetHubParent(_hub);
if ( IsCaptive() || IsCaptiveOverride(usbDevice->GetVendorID(), usbDevice->GetProductID()) )
usbDevice->setProperty("non-removable","yes");
#ifdef SUPPORTS_SS_USB
#endif
if (_hub->_hasExtraPowerRequest && !_captive && _portPowerAvailable == kUSB100mAAvailable)
{
UInt32 extraPowerAllocated = 0;
bool keepExtraPower = false;
SInt32 loops = 3;
while (loops-- > 0 )
{
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Checking to see if our device has 400mA extra (%d)", this, (uint32_t)loops);
extraPowerAllocated = usbDevice->RequestExtraPower(kUSBPowerDuringWake, (kUSB500mAAvailable - kUSB100mAAvailable) * 2);
if ( extraPowerAllocated < 400 )
{
if ( extraPowerAllocated > 0 )
{
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - returning our extraPower because it is not enough (%d)", this, (uint32_t) extraPowerAllocated);
usbDevice->ReturnExtraPower(kUSBPowerDuringWake, extraPowerAllocated);
extraPowerAllocated = 0;
}
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - calling for other devices to release extra power", this);
usbDevice->ReturnExtraPower(kUSBPowerRequestWakeRelease, (kUSB500mAAvailable - kUSB100mAAvailable) * 2);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - IOSleep in gate:%d", this, 7);}}
#endif
IOSleep(100);
}
else
{
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - got the extra power we requested (%d)", this, (uint32_t) extraPowerAllocated);
break;
}
}
if ( extraPowerAllocated >= 400 )
{
if (_desc.bDeviceClass == kUSBHubClass)
{
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d we might use the extra power for hub device - hanging on to it", this, _portNum);
usbDevice->setProperty("HubWakePowerReserved", extraPowerAllocated, 32);
keepExtraPower = true;
}
else
{
int numConfigs = usbDevice->GetNumConfigurations();
int i;
const IOUSBConfigurationDescriptor * cd = NULL;
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d we have extra port power - seeing if we need it with our %d configs", this, _portNum, numConfigs);
for (i=0; i < numConfigs; i++)
{
cd = usbDevice->GetFullConfigurationDescriptor(i);
if (cd && (cd->MaxPower > kUSB100mAAvailable))
{
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d we might use the extra power for config[%d] - hanging on to it", this, _portNum, i);
keepExtraPower = true;
break;
}
}
}
if (keepExtraPower)
{
_usingExtraPortPower = true;
_portPowerAvailable = kUSB500mAAvailable;
usbDevice->SetBusPowerAvailable(_portPowerAvailable);
}
else
{
USBLog(2, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, returning extra power since I don't have a config which needs it", this, _portNum);
usbDevice->ReturnExtraPower(kUSBPowerDuringWake, extraPowerAllocated);
}
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - calling for other devices to reallocate extra power", this);
usbDevice->RequestExtraPower(kUSBPowerRequestWakeReallocate, 0);
}
}
if (v3Bus)
{
v3Bus->CheckPMAssertions(usbDevice, true);
}
if ( _hasExternalConnector )
{
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Port %d of Hub at 0x%x on an external connector, decreasing unconnected port count on hub", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_hub->_device->UpdateUnconnectedExternalPorts(-1);
}
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Port %d of Hub at 0x%x (USB Address: %d), calling registerService for device %s", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)address, usbDevice->getName() );
USBTrace(kUSBTEnumeration, kTPEnumerationRegisterService, (uintptr_t)this, _portNum, _hub->_locationID, 0);
usbDevice->registerService();
if( (_detectedExpressCardCantWake) && (_cachedBadExpressCardVID != usbDevice->GetVendorID() || _cachedBadExpressCardPID != usbDevice->GetProductID()) )
{
_detectedExpressCardCantWake = false;
}
usbDevice->release();
} while(false);
if (err)
{
if (_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, err = %x, releasing devZero lock", this, _portNum, err);
#ifdef SUPPORTS_SS_USB
if ( !_hub->_ssHub )
#endif
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
}
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, err = %x, ALL DONE", this, _portNum, err);
USBTrace_End(kUSBTEnumeration, kTPEnumerationAddDeviceResetChangeHandler, (uintptr_t)this, _portNum, _hub->_locationID, err);
return err;
}
IOReturn
AppleUSBHubPort::HandleResetPortHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (changeFlags, statusFlags)
IOReturn err = kIOReturnSuccess;
UInt32 delay = 10;
UInt16 packetSize = 8;
USBLog(5, "***** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - start (_resetPending = %d)", this, _portNum, (uint32_t) _hub->_locationID, _resetPending);
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
#ifdef SUPPORTS_SS_USB
_portLinkErrorCount = 0; #endif
if ( _extraResetDelay )
{
USBLog(5, "***** AppleUSBHubPort[%p]::HandleResetPortHandler - delaying 100ms workaround", this);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::HandleResetPortHandler - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(100);
_extraResetDelay = false;
}
do
{
if (_state != hpsDeadDeviceZero)
{
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
_portStatus.statusFlags & kHubPortBeingReset)
{
USBLog(5, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - leaving (kHubPortBeingReset)", this, _portNum, (uint32_t) _hub->_locationID);
SetPortVector(&AppleUSBHubPort::HandleResetPortHandler, kHubPortBeingReset);
_resetPending = false;
return kIOReturnSuccess;
}
if (_getDeviceDescriptorFailed)
{
delay = 300;
USBLog(3, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - new delay %d", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - delaying %d ms", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::HandleResetPortHandler - IOSleep in gate:%d", this, 2);}}
#endif
IOSleep(delay);
if (_portStatus.statusFlags & kHubPortLowSpeed)
{
_speed = kUSBDeviceSpeedLow;
packetSize = 8;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - found low speed device", this, (uint32_t)_portNum, (uint32_t) _hub->_locationID);
}
else if (_portStatus.statusFlags & kHubPortHighSpeed)
{
_speed = kUSBDeviceSpeedHigh;
packetSize = 64;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - found high speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
#ifdef SUPPORTS_SS_USB
else if (_hub->_ssHub && _portStatus.statusFlags & kHubPortSuperSpeed) {
_speed = kUSBDeviceSpeedSuper;
packetSize = 9;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - found super speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
#endif
else
{
_speed = kUSBDeviceSpeedFull;
packetSize = 8;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - found full speed device", this, _portNum, (uint32_t) _hub->_locationID);
}
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - configuring dev zero", this, (uint32_t)_portNum, (uint32_t) _hub->_locationID);
err = DoConfigureDeviceZero(_bus, packetSize, _speed, _hub->_device->GetAddress(), _portNum);
_getDeviceDescriptorFailed = true;
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - getting dev zero desc", this, (uint32_t)_portNum, (uint32_t) _hub->_locationID);
err = GetDevZeroDescriptorWithRetries();
if ( err != kIOReturnSuccess )
{
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub at 0x%x - failed to get dev zero desc, detach'ing device", this, (uint32_t)_portNum, (uint32_t) _hub->_locationID);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(1, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, unable (err = %x) to disable port", this, (uint32_t)_portNum, err);
USBTrace( kUSBTHubPort, kTPHubPortHandleResetPortHandler, (uintptr_t)this, _portNum, err, 1);
FatalError(err, "clearing port feature (4)");
_bus->ReleaseDeviceZero();
_devZero = false;
_portDevice = NULL;
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
return err;
}
USBLog(5,"**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, using %d for maxPacketSize", this, _portNum, _desc.bMaxPacketSize0);
}
if (_setAddressFailed > 0)
{
delay = ((_setAddressFailed) * 30) + (_setAddressFailed * 3);
USBLog(3, "**4** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, previous SetAddress failed, sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::HandleResetPortHandler - IOSleep in gate:%d", this, 3);}}
#endif
IOSleep(delay);
}
if (!err)
_getDeviceDescriptorFailed = false;
_state = hpsSetAddress;
if (_portDevice)
{
err = _bus->SetDeviceZeroAddress(_portDevice->GetAddress());
if (err)
{
USBLog(1,"**5** AppleUSBHubPort[%p]::HandleResetPortHandler - Port %d of Hub at 0x%x, unable to set device %p to address %d - disabling port", this, _portNum, (uint32_t)_hub->_locationID, _portDevice, _portDevice->GetAddress() );
USBTrace( kUSBTHubPort, kTPHubPortHandleResetPortHandler, (uintptr_t)this, _portNum, (uint32_t)_hub->_locationID, _portDevice->GetAddress());
if (
#ifdef SUPPORTS_SS_USB
!_hub->_ssHub &&
#endif
(err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(3, "**5** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, unable (err = %x) to disable port", this, _portNum, err);
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
if ( _portDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenReset, cachedDevice, &err);
cachedDevice->release();
}
}
FatalError(err, "clearing port feature (5)");
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
if ( _portDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
err = kIOReturnNoDevice;
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenReset, cachedDevice, &err);
cachedDevice->release();
}
}
return err;
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - now check device address", this);
#ifdef SUPPORTS_SS_USB
IOUSBControllerV3* bus3 = OSDynamicCast(IOUSBControllerV3, _bus);
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - now check device address2", this);
if (bus3)
{
USBDeviceAddress latestDeviceAddress = 0;
IOReturn kr = bus3->GetActualDeviceAddress(_portDevice->GetAddress(), &latestDeviceAddress);
if (kr == kIOReturnSuccess)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - setting device %d address to address: %d", this, _portDevice->GetAddress(), latestDeviceAddress);
_portDevice->SetAddress(latestDeviceAddress);
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - GetActualDeviceAddress returned: 0x%x", this, (uint32_t)kr);
}
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - Didn't get bus3", this);
}
#endif
IOSleep( 2 );
USBLog(5, "**5** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Releasing DeviceZero after successful SetAddress", this, _portNum);
_resetPending = false;
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsNormal;
}
}
if ( _state == hpsDeadDeviceZero )
{
_setAddressFailed++;
USBLog(3, "**6** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, setaddressfailed = %d, disabling port", this, _portNum, _setAddressFailed);
#ifdef SUPPORTS_SS_USB
if (!_hub->_ssHub)
#endif
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
if (_devZero)
{
USBLog(3, "**6** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, releasing devZero lock", this, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**7** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, setting state to hpsSetAddressFailed", this, _portNum);
_state = hpsSetAddressFailed;
}
else
{
delay = (_setAddressFailed * 30) + (_setAddressFailed * 3);
if ( delay )
{
USBLog(3, "**8** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::HandleResetPortHandler - IOSleep in gate:%d", this, 4);}}
#endif
IOSleep(delay);
}
}
_state = hpsNormal;
if (!_portDevice)
{
if (_devZero)
{
USBLog(3, "**9** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, releasing devZero lock", this, _portNum);
_resetPending = true;
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**9** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, _portDevice disappeared, returning", this, _portNum);
}
_attachRetry = 0;
_attachRetryFailed = false;
if ( _attachMessageDisplayed )
{
USBError(1,"[%p] The IOUSBFamily has successfully enumerated the device.", this);
_attachMessageDisplayed = false;
}
} while(false);
if (err)
{
if (_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, err = %x, releasing devZero lock", this, _portNum, err);
#ifdef SUPPORTS_SS_USB
if (!_hub->_ssHub)
#endif
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
_resetPending = true;
_bus->ReleaseDeviceZero();
_devZero = false;
}
}
if (_portDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenReset, cachedDevice, &err);
cachedDevice->release();
}
}
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, err = %x, ALL DONE", this, _portNum, err);
return err;
}
IOReturn
AppleUSBHubPort::HandleSuspendPortHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (changeFlags)
IOReturn status = kIOReturnSuccess;
Boolean fromResume = _resumePending;
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler for port(%d) _portPMState (%d) changeFlags:(%p) _resumePending: (%s)", this, (int)_portNum, (int)_portPMState, (void*)changeFlags, _resumePending ? "true" : "false");
SetPortVector(&AppleUSBHubPort::DefaultSuspendChangeHandler, kHubPortSuspend);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::HandleSuspendPortHandler - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(10);
if (_resumePending)
{
_resumePending = false;
if (_lowerPowerStateOnResume)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler - RESUME - clearing _lowerPowerStateOnResume - (hub %p port %d)", this, _hub, _portNum);
_lowerPowerStateOnResume = false;
USBLog(6, "AppleUSBHubPort[%p]::HandleSuspendPortHandler - calling LowerPowerState on hub[%p] port %d after clearing _lowerPowerStateOnResume", this, _hub, _portNum);
_hub->LowerPowerState();
}
}
if (_portPMState == usbHPPMS_drvr_suspended)
{
if (statusFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler _suspendChangeAlreadyLogged: %s", this, _suspendChangeAlreadyLogged ? "true" : "false");
if (!fromResume && !_suspendChangeAlreadyLogged)
{
UInt64 wakeTime;
absolutetime_to_nanoseconds(_hub->_wakeupTime, &wakeTime);
if (wakeTime != 0)
{
AbsoluteTime now;
UInt64 msElapsed;
UInt32 msAfterWake = 0;
clock_get_uptime(&now);
SUB_ABSOLUTETIME(&now, &(_hub->_wakeupTime));
absolutetime_to_nanoseconds(now, &msElapsed);
msElapsed /= 1000000;
#if DEBUG_LEVEL != 0
msAfterWake = 5000;
#else
msAfterWake = 1000;
#endif
if (msElapsed < msAfterWake) {
IOLog("The USB device %s (Port %d of Hub at 0x%x) may have caused a wake by issuing a remote wakeup (1)\n", _portDevice ? _portDevice->getName() : "Unknown", _portNum, (uint32_t)GetHub()->_locationID);
}
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler Port %d of Hub at 0x%x - device issued remote wakeup, may be wake reason (%d ms since wake)", this, _portNum, (uint32_t)GetHub()->_locationID, (uint32_t)msElapsed);
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler wakeTime hi:lo %lx:%lx", this, (long unsigned)(wakeTime >> 32), (long unsigned)(wakeTime &0xffffffff));
}
}
USBLog(5, "AppleUSBHubPort[%p]::HandleSuspendPortHandler finish", this);
MessageDeviceClients(kIOUSBMessagePortHasBeenResumed, &status, sizeof(IOReturn) );
}
}
else if (_portPMState == usbHPPMS_pm_suspended)
{
USBError(1, "AppleUSBHub[%p]::HandleSuspendPortHandler - port(%d) in portPMState(usbHPPMS_pm_suspended) - should not be here!", this, (int)_portNum);
}
_portPMState = usbHPPMS_active;
WakeSuspendCommand( &_portPMState );
return status;
}
#pragma mark Default Vectors
IOReturn
AppleUSBHubPort::DefaultOverCrntChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (changeFlags, statusFlags)
#ifdef SUPPORTS_SS_USB
IOUSB3HubDescriptor hubDescriptor;
#else
IOUSBHubDescriptor hubDescriptor;
#endif
bool individualPortPower = FALSE;
UInt16 characteristics;
IOUSBHubPortStatus portStatus;
IOReturn err;
AbsoluteTime currentTime;
UInt64 elapsedTime;
bool displayDialog = true;
err = _hub->GetPortStatus(&portStatus, _portNum);
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. Port %d of hub @ 0x%x (isRootHub: %d), status = 0x%x, change: 0x%x", this, _portNum, (uint32_t) _hub->_locationID, _hub->_isRootHub, portStatus.statusFlags, portStatus.changeFlags );
if ( (err == kIOReturnSuccess) && (portStatus.changeFlags != 0x1f) )
{
if ( (portStatus.statusFlags & kHubPortOverCurrent) || ( ~(portStatus.statusFlags & kHubPortPower) && !_hub->_isRootHub) )
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. OverCurrent condition in Port %d of hub @ 0x%x", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortDefaultOverCrntChangeHandler, (uintptr_t)this, _portNum, (uint32_t) _hub->_locationID, 1 );
hubDescriptor = _hub->GetCachedHubDescriptor();
characteristics = USBToHostWord(hubDescriptor.characteristics);
if ( (characteristics & 0x18) == 0x8 )
individualPortPower = TRUE;
#ifdef SUPPORTS_SS_USB
if ( _hub->_ssHub && _hub->_isRootHub && (portStatus.statusFlags & kHubPortDebouncing) )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. Port %d of hub @ 0x%x will not display dialog", this, _portNum, (uint32_t)_hub->_locationID);
displayDialog = false;
}
#endif
clock_get_uptime(¤tTime);
SUB_ABSOLUTETIME(¤tTime, &_overCurrentNoticeTimeStamp );
absolutetime_to_nanoseconds(currentTime, &elapsedTime);
elapsedTime /= 1000000000;
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. displayedNoticed: %d, time since last: %qd", this, _overCurrentNoticeDisplayed, elapsedTime );
if ( displayDialog && (!_overCurrentNoticeDisplayed || (elapsedTime > kDisplayOverCurrentTimeout)) )
{
DisplayOverCurrentNotice( individualPortPower );
_overCurrentNoticeDisplayed = true;
clock_get_uptime(&_overCurrentNoticeTimeStamp);
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. not displaying notice because elapsed time %qd is < kDisplayOverCurrentTimeout seconds", this, elapsedTime );
}
}
else
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. No OverCurrent condition. Ignoring. Port %d", this, _portNum );
USBTrace( kUSBTHubPort, kTPHubPortDefaultOverCrntChangeHandler, (uintptr_t)this, _portNum, 0, 2 );
}
retain();
_hub->retain();
_hub->RaisePowerState(); USBLog(6, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler - calling EnablePowerAfterOvercurrentThread for port %d on hub @ 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
_enablePowerAfterOvercurrentThreadActive = true;
if (thread_call_enter(_enablePowerAfterOvercurrentThread) == true)
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler - cannot call out to EnablePowerAfterOvercurrentThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortDefaultOverCrntChangeHandler, (uintptr_t)this, _portNum, (uint32_t) _hub->_locationID, 3 );
_hub->LowerPowerState();
_hub->release();
release();
_enablePowerAfterOvercurrentThreadActive = false;
}
}
return err;
}
IOReturn
AppleUSBHubPort::DefaultResetChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (changeFlags, statusFlags)
USBLog(5, "AppleUSBHubPort[%p]::DefaultResetChangeHandler for port %d returning kIOReturnSuccess", this, _portNum);
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultSuspendChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (changeFlags, statusFlags)
USBLog(5, "AppleUSBHubPort[%p]::DefaultSuspendChangeHandler for port %d returning kIOReturnSuccess", this, _portNum);
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultEnableChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
#pragma unused (statusFlags)
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
if (!(changeFlags & kHubPortConnection))
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultEnableChangeHandler for port %d, changeFlags: 0x%04x - this is a serious error (Section 11.24.2.7.2)", this, _portNum, changeFlags);
}
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
FatalError(err, "getting port status (1)");
return err;
}
if (!(status.statusFlags & kHubPortEnabled) && !(changeFlags & kHubPortConnection))
{
USBLog( 3, "AppleUSBHubPort[%p]::DefaultEnableChangeHandler: port %d disabled. Device driver should reset itself port", this, _portNum);
}
return err;
}
IOReturn
AppleUSBHubPort::DefaultConnectionChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
#ifdef SUPPORTS_SS_USB
UInt16 linkState;
#endif
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - handling port %d changes (0x%04x,0x%04x)", this, _portNum, statusFlags, changeFlags);
status.statusFlags = statusFlags;
status.changeFlags = changeFlags;
_connectionChangedState = 0;
do
{
if ( _getDeviceDescriptorFailed )
{
_connectionChangedState = 1;
USBLog(3, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - previous enumeration failed - sleeping 300 ms", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(300);
if (!(status.statusFlags & kHubPortConnection))
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - This is a disconnect", this, _portNum);
_connectionChangedState = 2;
_portPMState = usbHPPMS_active;
_attachRetry = 0;
_attachRetryFailed = false;
}
}
else
{
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - waiting 100 ms before asserting reset", this, _portNum);
_connectionChangedState = 2;
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - IOSleep in gate:%d", this, 2);}}
#endif
IOSleep(100);
}
else
{
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
linkState = GETLINKSTATE(statusFlags);
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - no connection, link state: 0x%x (%s)", this, _portNum, linkState, _hub->LinkStateName(linkState));
}
#endif
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - This is a disconnect", this, _portNum);
_connectionChangedState = 2;
_portPMState = usbHPPMS_active;
_attachRetry = 0;
_attachRetryFailed = false;
}
}
}
#ifdef SUPPORTS_SS_USB
if (_muxed && (_portDevice == NULL) && !(status.statusFlags & kHubPortConnection))
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - This is a disconnect, so calling _hub->DeviceDisconnected()", this, _portNum);
_hub->DeviceDisconnected(_portNum, _muxedMethod);
}
#endif
if ( _devZero )
{
if ( _resetPending )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - _resetPending was true but the device went away, so let it finish w/out error", this, _portNum);
_resetPending = false;
}
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - releasing devZero lock", this, _portNum);
_connectionChangedState = 3;
_bus->ReleaseDeviceZero();
_devZero = false;
}
if (_portDevice)
{
_hadResumePendingAndDisconnect = false;
if ( _ignoreDisconnectOnWakeup )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - we are ignoring this disconnect/reconnect", this, _portNum);
USBLog(1, "IOUSBFamily: Ignoring a false disconnect after wake for the device %s at 0x%x\n", _portDevice->getName(), (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortDefaultConnectionChangeHandler, (uintptr_t)this, _portNum, (uint32_t)_hub->_locationID, 0);
break;
}
_connectionChangedState = 4;
_portPMState = usbHPPMS_active;
#ifdef SUPPORTS_SS_USB
if(_muxed)
{
_hub->DeviceDisconnected(_portNum, _muxedMethod);
}
#endif
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - found device (%p) removing", this, _portNum, _portDevice);
RemoveDevice();
_connectionChangedState = 5;
}
else
{
_connectionChangedState = 6;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - no existing device found on port", this, _portNum);
}
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
_connectionChangedState = 7;
_retryPortStatus = true;
FatalError(err, "getting port status (7)");
break;
}
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
linkState = GETLINKSTATE(statusFlags);
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - after debounce, link state: 0x%x (%s)", this, _portNum, linkState, _hub->LinkStateName(linkState));
}
#endif
_connectionChangedState = 8;
USBLog(4, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port %d status(0x%04x)/change(0x%04x) - no error from GetPortStatus", this, _portNum, status.statusFlags, status.changeFlags);
if (status.changeFlags & kHubPortConnection)
{
if (_debounceCount++ < 5)
{
_retryPortStatus = true;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port %d connection bounce - debounceCount (%d)", this, _portNum, (uint32_t)_debounceCount);
break;
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port %d debounceCount (%d) exceeded. returning kIOReturnInternalError", this, _portNum, (uint32_t)_debounceCount);
err = kIOReturnInternalError;
break;
}
}
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - device detected, calling AddDevice", this, _portNum);
USBTrace(kUSBTEnumeration, kTPEnumerationCallAddDevice, (uintptr_t)this, _portNum, _hub->_locationID, 0);
_state = hpsDeviceZero;
_connectionChangedState = 9;
USBLog(6, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - calling LaunchAddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
LaunchAddDeviceThread();
_connectionChangedState = 10;
}
} while(false);
_ignoreDisconnectOnWakeup = false;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d done, ending.", this, _portNum);
return err;
}
#ifdef SUPPORTS_SS_USB
IOReturn
AppleUSBHubPort::DefaultBHResetChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultBHResetChangeHandler - Port %d of Hub at 0x%x changes (0x%04x,0x%04x)", this, _portNum, (uint32_t)_hub->_locationID, statusFlags, changeFlags);
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultPortLinkStateChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
UInt16 linkState = GETLINKSTATE(statusFlags);
IOReturn kr = kIOReturnSuccess;
USBLog(5, "AppleUSBHubPort[%p]::DefaultPortLinkStateChangeHandler - handling Port %d of Hub at 0x%x changes (0x%04x,0x%04x), LinkState: 0x%x (%s)", this, _portNum, (uint32_t)_hub->_locationID, statusFlags, changeFlags, linkState, _hub->LinkStateName(linkState));
_portLinkState = linkState;
kr = HandleLinkState(changeFlags, statusFlags);
return kr;
}
IOReturn
AppleUSBHubPort::DefaultPortConfigErrChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
UInt16 linkState = GETLINKSTATE(statusFlags);
IOReturn kr = kIOReturnSuccess;
IOUSBHubPortStatus status;
UInt16 portLinkErrorCount = 0;
kr = _hub->GetPortErrorCount(_portNum, &portLinkErrorCount);
if ( kr != kIOReturnSuccess)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - handling Port %d of Hub at 0x%x GetPortErrorCount: %d", this, _portNum, (uint32_t)_hub->_locationID, portLinkErrorCount);
}
USBLog(5, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - handling Port %d of Hub at 0x%x changes (0x%04x,0x%04x), LinkState: 0x%x (%s state), GetPortErrorCount: %d", this, _portNum, (uint32_t)_hub->_locationID, statusFlags, changeFlags, linkState, _hub->LinkStateName(linkState), portLinkErrorCount);
if ( (linkState != kSSHubPortLinkStateU0) || (linkState != kSSHubPortLinkStateSSInactive) )
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - IOSleep in gate:%d", this, 3);}}
#endif
IOSleep(100);
kr = _hub->GetPortStatus(&status, _portNum);
if (kr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - Port %d of Hub at 0x%x _hub->GetPortStatus() returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, kr);
return kr;
}
changeFlags = status.changeFlags;
statusFlags = status.statusFlags;
linkState = GETLINKSTATE(statusFlags);
USBLog(5, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - handling Port %d of Hub at 0x%x after waiting new status (0x%04x,0x%04x), LinkState: 0x%x (%s state)", this, _portNum, (uint32_t)_hub->_locationID, statusFlags, changeFlags, linkState, _hub->LinkStateName(linkState));
}
switch (linkState)
{
case kSSHubPortLinkStateRxDetect:
case kSSHubPortLinkStateSSDisabled:
SetPortVector(&AppleUSBHubPort::HandleResetPortHandler, kHubPortBeingReset);
kr = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - IOSleep in gate:%d", this, 4);}}
#endif
IOSleep(100);
if (kr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - Port %d of Hub at 0x%x SetPortFeature(kUSBHubPortResetFeature) returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, kr);
}
break;
case kSSHubPortLinkStateSSInactive:
USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - Port %d of Hub at 0x%x (0x%04x,0x%04x) In %s, issuing a SetPortFeature(kUSBHubPortBHPortResetFeature)", this, _portNum, (uint32_t)_hub->_locationID, statusFlags, changeFlags, _hub->LinkStateName(linkState));
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
kr = _hub->SetPortFeature(kUSBHubPortBHPortResetFeature, _portNum);
if (kr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - Port %d of Hub at 0x%x SetPortFeature(kUSBHubPortBHPortResetFeature) returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, kr);
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - IOSleep in gate:%d", this, 5);}}
#endif
IOSleep(100);
break;
default:
USBLog(3, "AppleUSBHubPort[%p]::DefaultPortConfigErrChangeHandler - Port %d of Hub at 0x%x not doing anything with this link state change", this, _portNum, (uint32_t)_hub->_locationID);
kr = kIOReturnSuccess;
break;
}
return kr;
}
#endif
# pragma mark Change Handlers
void
AppleUSBHubPort::PortStatusChangedHandlerEntry(OSObject *target)
{
AppleUSBHubPort *me;
if (!target)
{
USBLog(5, "AppleUSBHubPort::PortStatusChangedHandlerEntry - no target!");
return;
}
me = OSDynamicCast(AppleUSBHubPort, target);
if (!me)
{
USBLog(5, "AppleUSBHubPort::PortStatusChangedHandlerEntry - target is not really me!");
return;
}
me->PortStatusChangedHandler();
if ( me->_hub != NULL )
{
USBLog(6, "AppleUSBHubPort[%p]::PortStatusChangedHandlerEntry - calling LowerPowerState and DecrementOutstandingIO on hub[%p] port %d", me, me->_hub, me->_portNum);
me->_hub->LowerPowerState(); me->_hub->DecrementOutstandingIO(); }
me->release();
}
void
AppleUSBHubPort::PortStatusChangedHandler(void)
{
int which;
IOReturn err = kIOReturnSuccess;
bool skipOverGetPortStatus = false;
if (!IOLockTryLock(_runLock))
{
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler: port %d already in PSCH, setting _retryPortStatus to true", this, _portNum);
_retryPortStatus = true;
return;
}
if ( !IOLockTryLock(_initLock) )
{
USBLog(3, "AppleUSBHubPort[%p]::PortStatusChangedHandler: _initLock for port %d @ 0x%x held! Waiting...", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
IOLockLock(_initLock);
USBLog(3, "AppleUSBHubPort[%p]::PortStatusChangedHandler: _initLock for port %d released!", this, _portNum);
}
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler: port %d obtained runLock", this, _portNum);
_statusChangedState = 0;
_statusChangedThreadActive = true;
if (_delayOnStatusChange)
{
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler: delaying 100ms before first GetPortStatus after a reset of port %d", this, _portNum);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::PortStatusChangedHandler - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(100);
_delayOnStatusChange = false;
}
do
{
if ( !skipOverGetPortStatus )
{
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler: calling GetPortStatus for port %d", this, _portNum);
if ((err = _hub->GetPortStatus(&_portStatus, _portNum)))
{
_statusChangedState = 1;
FatalError(err, "get status (first in port status change)");
goto errorExit;
}
if ( (_portStatus.statusFlags == 0xffff) && (_portStatus.changeFlags == 0xffff) )
{
FatalError(err, "probably a PC card was ejected");
err = kIOReturnNoDevice;
goto errorExit;
}
_statusChangedState = 2;
#ifdef SUPPORTS_SS_USB
if (_hub->_ssHub)
{
UInt16 portLinkErrorCount = 0;
err = _hub->GetPortErrorCount(_portNum, &portLinkErrorCount);
if ((err ==kIOReturnSuccess) && (portLinkErrorCount > _portLinkErrorCount))
{
USBLog(1, "AppleUSBHubPort[%p]::PortStatusChangedHandler - Hub 0x%x port %d: link error count increased by %d, linkState: 0x%x (%s)",
this, (uint32_t)_hub->_locationID, _portNum, (uint32_t)(portLinkErrorCount - _portLinkErrorCount), GETLINKSTATE(_portStatus.statusFlags), _hub->LinkStateName(GETLINKSTATE(_portStatus.statusFlags)));
_portLinkErrorCount = portLinkErrorCount;
}
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - Hub 0x%x port %d - Initial status(0x%04x)/change(0x%04x), link state: 0x%x (%s)",
this, (uint32_t)_hub->_locationID, _portNum, _portStatus.statusFlags, _portStatus.changeFlags, GETLINKSTATE(_portStatus.statusFlags), _hub->LinkStateName(GETLINKSTATE(_portStatus.statusFlags)));
}
else
#endif
{
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - Hub 0x%x port %d - Initial status(0x%04x)/change(0x%04x)", this, (uint32_t)_hub->_locationID, _portNum, _portStatus.statusFlags, _portStatus.changeFlags);
}
USBTrace(kUSBTEnumeration, kTPEnumerationInitialGetPortStatus, (uintptr_t)this, _portNum, _hub->_locationID, *(uintptr_t *)&_portStatus);
_retryPortStatus = false;
}
if ( _hub->_ignoreDisconnectOnWakeup && (_portStatus.statusFlags & kHubPortConnection) && (_portStatus.changeFlags & kHubPortConnection) )
{
_ignoreDisconnectOnWakeup = ShouldApplyDisconnectWorkaround();
USBLog(_ignoreDisconnectOnWakeup ? 5 : 7,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - ShouldApplyDisconnectWorkaround returned %d", this, _portNum, _ignoreDisconnectOnWakeup);
}
if (_resumePending && (_portStatus.changeFlags & kHubPortConnection))
{
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - Hub 0x%x port %d - Had a connection change while a resume is pending", this, (uint32_t)_hub->_locationID, _portNum);
_hadResumePendingAndDisconnect = true;
}
_statusChangedState = 3;
for (which = 0; which < kNumChangeHandlers; which++)
{
if (!(_portStatus.changeFlags & _changeHandler[which].bit))
continue;
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - change %d clearing feature 0x%x (%s)", this, (uint32_t)_portNum, which, (uint32_t)_changeHandler[which].clearFeature, _hub->FeatureName(_changeHandler[which].clearFeature));
_statusChangedState = 4;
if ((err = _hub->ClearPortFeature(_changeHandler[which].clearFeature, _portNum)))
{
USBLog(3, "AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - error %x clearing feature 0x%x (%s)", this, (uint32_t)_portNum, err, (uint32_t)_changeHandler[which].clearFeature, _hub->FeatureName(_changeHandler[which].clearFeature));
FatalError(err, "clear port vector bit feature");
goto errorExit;
}
_statusChangedState = 5;
break;
}
if ( which >= kNumChangeHandlers )
{
break;
}
_statusChangedState = 6;
if ((err = _hub->GetPortStatus(&_portStatus, _portNum)))
{
USBLog(3, "AppleUSBHubPort[%p]::PortStatusChangedHandler: error 0x%x getting port status", this, err);
FatalError(err, "get status (second in port status change)");
goto errorExit;
}
if ( (_portStatus.statusFlags == 0xffff) && (_portStatus.changeFlags == 0xffff) )
{
FatalError(err, "status and change flags are 0xffff");
err = kIOReturnNoDevice;
goto errorExit;
}
_statusChangedState = 7;
USBLog(5, "AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - status(0x%04x) - change(0x%04x) - before call to (%d) handler function", this, _portNum, _portStatus.statusFlags, _portStatus.changeFlags, which);
_statusChangedState = ((which+1) * 20) + 1;
err = (this->*_changeHandler[which].handler)(_portStatus.changeFlags, _portStatus.statusFlags);
_statusChangedState = ((which+1) * 20) + 2;
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - err (%x) on return from call to (%d) handler function", this, _portNum, err, which);
_statusChangedState = 8;
if (kIOReturnSuccess == err)
{
if ( which == 4 || _retryPortStatus )
skipOverGetPortStatus = false;
else
skipOverGetPortStatus = true;
continue;
}
else
{
USBLog((kIOReturnNoDevice == err) ? 5 : 1,"AppleUSBHubPort[%p]::PortStatusChangedHandler - Port %d of Hub at 0x%x - error %x from (%d) handler", this, _portNum, (uint32_t)_hub->_locationID, err, which);
break;
}
}
while (true);
errorExit:
if ( err != kIOReturnSuccess )
{
if ( _attachMessageDisplayed )
{
{
USBError(1,"[%p] The IOUSBFamily was not able to enumerate a device.", this);
}
_attachMessageDisplayed = false;
}
if ( _devZero )
{
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - err = %x - done, releasing Dev Zero lock", this, _portNum, err);
_bus->ReleaseDeviceZero();
_devZero = false;
}
}
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - err = %x - done, releasing _runLock", this, _portNum, err);
IOLockUnlock(_runLock);
IOLockUnlock(_initLock);
_statusChangedThreadActive = false;
_debounceCount = 0;
if (_inCommandSleep)
{
IOCommandGate *gate = NULL;
if (_bus)
gate = _bus->GetCommandGate();
if (gate)
{
USBLog(3,"AppleUSBHubPort[%p]::PortStatusChangedHandler - calling commandWakeup", this);
gate->commandWakeup(&_statusChangedThreadActive, true);
}
}
}
bool
AppleUSBHubPort::StatusChanged(void)
{
if (!_portStatusChangedHandlerThread)
return false;
retain(); if ( thread_call_enter(_portStatusChangedHandlerThread) == TRUE )
{
USBLog(3,"AppleUSBHubPort[%p]::StatusChanged - _portStatusChangedHandlerThread already queued", this);
_hub->LowerPowerState();
_hub->DecrementOutstandingIO();
release();
}
return true;
}
void
AppleUSBHubPort::InitPortVectors(void)
{
int vector;
for (vector = 0; vector < kNumChangeHandlers; vector++)
{
_changeHandler[vector] = defaultPortVectors[vector];
switch (defaultPortVectors[vector].bit)
{
case kHubPortOverCurrent:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultOverCrntChangeHandler;
break;
case kHubPortBeingReset:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultResetChangeHandler;
break;
case kHubPortSuspend:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultSuspendChangeHandler;
break;
case kHubPortEnabled:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultEnableChangeHandler;
break;
case kHubPortConnection:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultConnectionChangeHandler;
break;
#ifdef SUPPORTS_SS_USB
case kSSHubPortChangeBHResetMask:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultBHResetChangeHandler;
break;
case kSSHubPortChangePortLinkStateMask:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultPortLinkStateChangeHandler;
break;
case kSSHubPortChangePortConfigErrMask:
_changeHandler[vector].handler = &AppleUSBHubPort::DefaultPortConfigErrChangeHandler;
break;
#endif
}
}
}
void
AppleUSBHubPort::SetPortVector(ChangeHandlerFuncPtr routine,
UInt32 condition)
{
int vector;
for(vector = 0; vector < kNumChangeHandlers; vector++)
{
if (condition == _changeHandler[vector].bit)
{
_changeHandler[vector].handler = routine;
}
}
}
IOReturn
AppleUSBHubPort::ReleaseDevZeroLock()
{
USBLog(5, "AppleUSBHubPort[%p]::ReleaseDevZeroLock Port %d of Hub at 0x%x, devZero = 0x%x, ", this, _portNum, (uint32_t)_hub->_locationID, _devZero);
if (_devZero)
{
IOUSBHubPortStatus status;
IOReturn kr = kIOReturnSuccess;
kr = _hub->GetPortStatus(&status, _portNum);
if ( kr != kIOReturnSuccess)
{
USBLog(3, "AppleUSBHubPort[%p]::ReleaseDevZeroLock() Port %d of Hub at 0x%x, GetPortStatus returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, kr);
}
else
{
#ifdef SUPPORTS_SS_USB
UInt16 linkState = GETLINKSTATE(status.statusFlags);
USBLog(5, "AppleUSBHubPort[%p]::ReleaseDevZeroLock - Port %d of Hub at 0x%x: status (0x%04x,0x%04x), LinkState: 0x%x (%s state)", this, _portNum, (uint32_t)_hub->_locationID, status.statusFlags, status.changeFlags, linkState, _hub->LinkStateName(linkState));
#else
USBLog(5, "AppleUSBHubPort[%p]::ReleaseDevZeroLock - Port %d of Hub at 0x%x: status (0x%04x,0x%04x)", this, _portNum, (uint32_t)_hub->_locationID, status.statusFlags, status.changeFlags);
#endif
}
#ifdef SUPPORTS_SS_USB
if (!_hub->_ssHub)
#endif
(void) _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
USBLog(1, "AppleUSBHubPort[%p]::ReleaseDevZeroLock()", this);
USBTrace( kUSBTHubPort, kTPHubPortReleaseDevZeroLock, (uintptr_t)this, _portNum, _devZero, _hub->_locationID);
_state = hpsNormal;
if ( _bus )
_bus->ReleaseDeviceZero();
_devZero = false;
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DetachDevice()
{
UInt32 delay = 0;
IOUSBHubPortStatus status;
IOReturn err = kIOReturnSuccess;
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice Port %d of Hub at 0x%x being detached (_attachRetry = %d)", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)_attachRetry);
USBTrace( kUSBTHubPort, kTPHubPortDetachDevice, (uintptr_t)this, _portNum, _hub->_locationID, 1);
if ( !_attachMessageDisplayed )
{
USBError(1,"[%p] The IOUSBFamily is having trouble enumerating a USB device that has been plugged in. It will keep retrying. (Port %d of Hub at 0x%x)", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_attachMessageDisplayed = true;
}
if ( _attachRetryFailed == true )
{
_state = hpsDeadDeviceZero;
err = kIOReturnNotResponding;
goto ErrorExit;
}
if( _attachRetry == 9 )
{
_attachRetryFailed = true;
USBError(1,"[%p] The IOUSBFamily gave up enumerating a USB device after 10 retries. (Port %d of Hub at 0x%x)", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_state = hpsDeadDeviceZero;
err = kIOReturnNotResponding;
goto ErrorExit;
}
_attachRetry++;
if ( _attachRetry % 4 == 0 )
{
const int kWaitForDevicePowerON = 100;
delay = _attachRetry * kWaitForDevicePowerON;
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice (Port %d of Hub at 0x%x), attachRetry limit reached. delaying for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
USBTrace( kUSBTHubPort, kTPHubPortDetachDevice, (uintptr_t)this, _portNum, _hub->_locationID, delay );
if ( (err = _hub->SetPortPower(_portNum, kHubPortPowerOff)) )
{
FatalError(err, "clearing port power feature");
goto ErrorExit;
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DetachDevice - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(delay);
if ( (err = _hub->SetPortPower(_portNum, kHubPortPowerOn)) )
{
FatalError(err, "setting port power feature");
goto ErrorExit;
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DetachDevice - IOSleep in gate:%d", this, 2);}}
#endif
IOSleep(kWaitForDevicePowerON);
_state = hpsDeadDeviceZero;
err = kIOReturnNotResponding;
}
else
{
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
FatalError(err, "getting port status (5)");
goto ErrorExit;
}
if ( !(status.statusFlags & kHubPortConnection) )
{
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice - Port %d of Hub at 0x%x - device has gone away", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortDetachDevice, (uintptr_t)this, _portNum, _hub->_locationID, kIOReturnNoDevice );
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
goto ErrorExit;
}
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::DetachDevice - IOSleep in gate:%d", this, 31);}}
#endif
IOSleep(300);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
FatalError(err, "getting port status (6)");
goto ErrorExit;
}
if (status.statusFlags & kHubPortConnection)
{
#ifdef SUPPORTS_SS_USB
if (!_hub->_ssHub)
#endif
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
if (status.changeFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::DetachDevice - port %d - Clearing connection change", this, _portNum);
_hub->ClearPortFeature(kUSBHubPortConnectionChangeFeature, _portNum);
}
_retryPortStatus = true;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
#ifdef SUPPORTS_SS_USB
if(_muxed)
{
_hub->DeviceDisconnected(_portNum, _muxedMethod);
}
#endif
RemoveDevice();
USBTrace(kUSBTEnumeration, kTPEnumerationCallAddDevice, (uintptr_t)this, _portNum, _hub->_locationID, 0);
err = kIOReturnSuccess;
USBLog(6, "AppleUSBHubPort[%p]::DetachDevice - calling LaunchAddDeviceThread for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
LaunchAddDeviceThread();
}
else
{
err = kIOReturnSuccess;
}
}
ErrorExit:
return err;
}
IOReturn
AppleUSBHubPort::GetDevZeroDescriptorWithRetries()
{
UInt32 delay = 30;
UInt32 retries = kMaxDevZeroRetries;
IOReturn err = kIOReturnSuccess;
IOReturn portStatusErr = kIOReturnSuccess;
IOUSBHubPortStatus status;
do
{
bzero(&_desc, sizeof(_desc));
#ifdef SUPPORTS_SS_USB
err = _bus->GetDeviceZeroDescriptor(&_desc, (kUSBDeviceSpeedHigh == _speed || kUSBDeviceSpeedSuper == _speed) ? 18 : 8); #else
err = _bus->GetDeviceZeroDescriptor(&_desc, (kUSBDeviceSpeedHigh == _speed) ? 18 : 8); #endif
if ( err == kIOReturnOverrun )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - GetDeviceZeroDescriptor returned kIOReturnOverrun. Checking for valid descriptor", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _hub->_locationID, 1 );
if ( (_desc.bDescriptorType == kUSBDeviceDesc) &&
(_desc.bLength == 18) &&
(_desc.bMaxPacketSize0 >= 8 ) &&
(_desc.bMaxPacketSize0 <= 64 )
)
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - GetDeviceZeroDescriptor returned kIOReturnOverrun. Descriptor looks valid", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _hub->_locationID, 2 );
err = kIOReturnSuccess;
break;
}
}
if ( err )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - GetDeviceZeroDescriptor returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, err);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, err, 3 );
portStatusErr = _hub->GetPortStatus(&status, _portNum);
if (portStatusErr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - GetPortStatus returned 0x%x", this, _portNum, (uint32_t)_hub->_locationID, err);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, portStatusErr, 4 );
FatalError(err, "getting port status (4)");
break;
}
if ( !(status.statusFlags & kHubPortConnection) )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - device has gone away", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _state, kIOReturnNoDevice );
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
break;
}
if ( status.statusFlags & kHubPortSuspend)
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x - port is suspended", this, _portNum, (uint32_t)_hub->_locationID);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _hub->_locationID, 5 );
portStatusErr = _hub->ClearPortFeature(kUSBHubPortSuspendFeature, _portNum);
if (kIOReturnSuccess != portStatusErr)
{
USBLog(3, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries Could not ClearPortFeature (%d) (kHubPortSuspend): (0x%x)", this, (uint32_t)_portNum, err);
break;
}
}
#ifdef SUPPORTS_SS_USB
if ((err == kIOUSBTransactionTimeout) && (_speed == kUSBDeviceSpeedSuper))
{
USBLog(3, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries setting tries to 1 because we got a timeout error on a super speed device", this);
retries = 1;
}
else
#endif
{
if ((err == kIOUSBTransactionTimeout) && ( retries == kMaxDevZeroRetries))
{
USBLog(3, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries setting retries to 2 because we got a timeout error", this);
retries = 2;
}
}
if ( retries == 2)
delay = 3;
else if ( retries == 1 )
delay = 30;
USBLog(3, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d of hub @ 0x%x , err: %x - sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, err, (uint32_t)delay);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep( delay );
retries--;
}
else
{
if ( (_desc.bMaxPacketSize0 < 8) || (_desc.bMaxPacketSize0 > 64 ) )
{
USBError(1, "The USB Family found a device at port %d of hub @ 0x%x with a bad USB device descriptor (0x%qx, 0x%qx )", (uint32_t)_portNum, (uint32_t)_hub->_locationID, * (uint64_t *)(&_desc), * (uint64_t *)(&_desc.idVendor));
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _hub->_locationID, 6 );
retries = 0;
err = kIOReturnDeviceError;
break;
}
}
if ((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable))
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - aborting due to power change", this);
USBTrace( kUSBTHubPort, kTPHubPortGetDevZeroDescriptorWithRetries, (uintptr_t)this, _portNum, _hub->_powerStateChangingTo, 7 );
}
}
while ( err && (retries > 0) && !((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable)));
return err;
}
bool
AppleUSBHubPort::AcquireDeviceZero()
{
IOReturn err = kIOReturnSuccess;
bool devZero = false;
err = _bus->AcquireDeviceZero();
USBLog(6, "AppleUSBHubPort[%p]::AcquireDeviceZero (Port %d of Hub at 0x%x) - _bus->AcquireDeviceZero returned 0x%x", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, err);
if ( err == kIOReturnSuccess )
devZero = true;
if ( devZero )
_devZeroCounter++;
return devZero;
}
void
AppleUSBHubPort::DisplayOverCurrentNotice(bool individual)
{
USBLog(1, "AppleUSBHubPort[%p]::DisplayOverCurrentNotice - port %d - individual: %d", this, _portNum, individual);
USBTrace( kUSBTHubPort, kTPHubPortDisplayOverCurrentNotice, (uintptr_t)this, _portNum, individual, 1 );
if ( _hub == NULL || _hub->_device == NULL )
{
USBLog(1, "AppleUSBHubPort[%p]::DisplayOverCurrentNotice - _hub (%p) or _hub->_device is NULL", this, _hub);
USBTrace( kUSBTHubPort, kTPHubPortDisplayOverCurrentNotice, (uintptr_t)this, (uintptr_t)_hub, 0, 2 );
return;
}
if ( individual )
_hub->_device->DisplayUserNotification(kUSBIndividualOverCurrentNotificationType);
else
_hub->_device->DisplayUserNotification(kUSBGangOverCurrentNotificationType);
return;
}
bool
AppleUSBHubPort::IsCaptiveOverride(UInt16 vendorID, UInt16 productID)
{
CaptiveErrataListEntry *entryPtr;
UInt32 i, errata = 0;
for(i = 0, entryPtr = gErrataList; i < ERRATALISTLENGTH; i++, entryPtr++)
{
if (vendorID == entryPtr->vendorID &&
productID >= entryPtr->productIDLo &&
productID <= entryPtr->productIDHi)
{
return true;
}
}
return false;
}
bool
AppleUSBHubPort::ShouldApplyDisconnectWorkaround()
{
AbsoluteTime now;
UInt64 msElapsed;
bool returnValue = false;
UInt64 wakeTime;
absolutetime_to_nanoseconds(_hub->_wakeupTime, &wakeTime);
if (wakeTime != 0)
{
clock_get_uptime(&now);
SUB_ABSOLUTETIME(&now, &(_hub->_wakeupTime));
absolutetime_to_nanoseconds(now, &msElapsed);
msElapsed /= 1000000;
USBLog(7, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d of hub @ 0x%x - time since wake: %qd ms", this, _portNum, (uint32_t)_hub->_locationID, msElapsed);
if (_hub->_ignoreDisconnectOnWakeup && _portDevice && (msElapsed < kWaitTimeToIgnoreDisconnect) )
{
OSBoolean * deviceHasMassStorageInterfaceRef = OSDynamicCast( OSBoolean, _portDevice->getProperty("kHasMSCInterface") );
if ( deviceHasMassStorageInterfaceRef && deviceHasMassStorageInterfaceRef->isTrue() )
{
USBLog(5, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d of hub @ 0x%x - we have a disconnect/reconnect on a mass storage device on a hub that tells us to ignore it, within %d ms of wake", this, _portNum, (uint32_t)_hub->_locationID, (uint32_t)msElapsed);
returnValue = true;
}
else if ( _hub->_isRootHub )
{
USBLog(7, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d - we have a disconnect/reconnect on a root hub that tells us to ignore it", this, _portNum);
returnValue = true;
}
else
{
OSNumber * bDeviceClassObj = OSDynamicCast( OSNumber, _portDevice->getProperty(kUSBDeviceClass) );
if ( bDeviceClassObj && (bDeviceClassObj->unsigned32BitValue() == kUSBHubClass))
{
USBLog(5, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d of hub @ 0x%x - we have a disconnect/reconnect off a hub on a hub that tells us to ignore it, within %d ms of wake", this, _portNum, (uint32_t)_hub->_locationID, (uint32_t)msElapsed);
returnValue = true;
}
}
}
}
return returnValue;
}
void
AppleUSBHubPort::WaitForSuspendCommand( void *event, uint64_t timeout )
{
IOWorkLoop *myWL = NULL;
IOCommandGate *gate = NULL;
if ( _bus )
{
myWL = _bus->getWorkLoop();
if ( myWL )
{
gate = _bus->GetCommandGate();
}
if ( not myWL or not gate )
{
USBLog(1, "AppleUSBHubPort[%p]::WaitForSuspendCommand - nil workloop or nil gate !", this);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, 0, 1 );
return;
}
}
if ( myWL->onThread() )
{
USBLog(6, "AppleUSBHubPort[%p]::WaitForSuspendCommand - called on workloop thread !", this);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, 0, 2 );
}
if ( myWL->inGate() )
{
if ( gate )
{
USBLog(6,"AppleUSBHubPort[%p]::WaitForSuspendCommand calling commandSleep", this);
uint64_t currentTime = mach_absolute_time();
AbsoluteTime deadline;
uint64_t elapsedTime = 0;
absolutetime_to_nanoseconds(*(AbsoluteTime *)¤tTime, &elapsedTime);
currentTime = elapsedTime + timeout*(1000*1000);
nanoseconds_to_absolutetime( currentTime, &deadline);
IOReturn kr = gate->commandSleep( event, deadline, THREAD_UNINT );
switch (kr)
{
case THREAD_AWAKENED:
USBLog(6,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep woke up normally (THREAD_AWAKENED) _hub->_myPowerState(%d)", this, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, (uintptr_t)_hub->_myPowerState, 3 );
break;
case THREAD_TIMED_OUT:
USBLog(3,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep timed out (THREAD_TIMED_OUT) _hub->_myPowerState(%d)", this, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, (uintptr_t)_hub->_myPowerState, 4 );
break;
case THREAD_INTERRUPTED:
USBLog(3,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep was interrupted (THREAD_INTERRUPTED) _hub->_myPowerState(%d)", this, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, (uintptr_t)_hub->_myPowerState, 5 );
break;
case THREAD_RESTART:
USBLog(3,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep was restarted (THREAD_RESTART) _hub->_myPowerState(%d)", this, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, (uintptr_t)_hub->_myPowerState, 6 );
break;
case kIOReturnNotPermitted:
USBLog(3,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep woke up (kIOReturnNotPermitted) _hub->_myPowerState(%d)", this, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, 0, (uintptr_t)_hub->_myPowerState, 7 );
break;
default:
USBLog(3,"AppleUSBHubPort[%p]::WaitForSuspendCommand commandSleep woke up with status (%p) _hub->_myPowerState(%d)", this, (void*)kr, (int)_hub->_myPowerState);
USBTrace( kUSBTHubPort, kTPHubPortWaitForSuspendCommand, (uintptr_t)this, kr, (uintptr_t)_hub->_myPowerState, 8 );
}
}
}
else
{
IOSleep(timeout);
}
}
void
AppleUSBHubPort::WakeSuspendCommand( void *event )
{
IOWorkLoop *myWL = NULL;
IOCommandGate *gate = NULL;
if ( _bus )
{
myWL = _bus->getWorkLoop();
if ( myWL )
{
gate = _bus->GetCommandGate();
}
if ( not myWL or not gate )
{
USBLog(1, "AppleUSBHub[%p]::WaitForSuspendCommand - nil workloop or nil gate !", this);
USBTrace( kUSBTHubPort, kTPHubPortWakeSuspendCommand, (uintptr_t)this, 0, 0, 1 );
return;
}
}
USBLog(3,"AppleUSBHubPort[%p]::WakeSuspendCommand calling commandWakeUp", this);
if ( gate )
{
gate->commandWakeup( event, true);
}
else
{
USBLog(1,"AppleUSBHubPort[%p]::WakeSuspendCommand cannot call commandGate->wakeup because there is no gate", this);
USBTrace( kUSBTHubPort, kTPHubPortWakeSuspendCommand, (uintptr_t)this, 0, 0, 2 );
}
}
void
AppleUSBHubPort::EnablePowerAfterOvercurrentEntry(OSObject *target)
{
AppleUSBHubPort *me;
if (!target)
{
USBLog(5, "AppleUSBHubPort::EnablePowerAfterOvercurrentEntry - no target!");
return;
}
me = OSDynamicCast(AppleUSBHubPort, target);
if (!me)
{
USBLog(5, "AppleUSBHubPort::EnablePowerAfterOvercurrentEntry - target is not really me!");
return;
}
if ( me->IsInactive() )
{
USBLog(6, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrentEntry - port object is inActive() for port %d on hub at 0x%x", me, me->_portNum, (uint32_t) me->_hub->_locationID);
return;
}
USBTrace( kUSBTHubPort, kTPHubPortEnablePowerAfterOvercurrent, (uintptr_t)me, me->_hub->_locationID, me->_portNum, 3);
me->EnablePowerAfterOvercurrent();
USBLog(6, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrentEntry - calling LowerPowerState and release on hub[%p] port %d", me, me->_hub, me->_portNum);
me->_hub->LowerPowerState();
me->_hub->release();
me->_enablePowerAfterOvercurrentThreadActive = false;
if (me->_inCommandSleep)
{
IOCommandGate *gate = NULL;
if (me->_bus)
gate = me->_bus->GetCommandGate();
if (gate)
{
USBLog(2,"AppleUSBHubPort[%p]::EnablePowerAfterOvercurrentEntry - calling commandWakeup", me);
USBTrace( kUSBTHubPort, kTPHubPortEnablePowerAfterOvercurrent, (uintptr_t)me, me->_hub->_locationID, me->_portNum, 4);
gate->commandWakeup(&me->_enablePowerAfterOvercurrentThreadActive, true);
}
}
me->release();
}
void
AppleUSBHubPort::EnablePowerAfterOvercurrent()
{
IOReturn kr;
IOUSBHubPortStatus portStatus;
if ( IsInactive() )
{
USBLog(6, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrent - port object is inActive() for port %d on hub at 0x%x", this, _portNum, (uint32_t) _hub->_locationID);
return;
}
if (_hub->isInactive() || !_hub->_device || _hub->_device->isInactive())
{
USBLog(5, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrent - port %d on hub at 0x%x - hub[%p] is inactive or hub device[%p] is missing or inactive - aborting EnablePowerAfterOvercurrent", this, _portNum, (uint32_t) _hub->_locationID, _hub, _hub->_device);
return;
}
if ((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable))
{
USBLog(5, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrent - port %d on hub at 0x%x - hub[%p] changing to power state[%d] - aborting EnablePowerAfterOvercurrent", this, _portNum, (uint32_t) _hub->_locationID, _hub, (int)_hub->_powerStateChangingTo);
return;
}
kr = _hub->GetPortStatus( &portStatus, _portNum);
USBTrace( kUSBTHubPort, kTPHubPortEnablePowerAfterOvercurrent, (uint32_t)_hub->_locationID, _portNum, (uintptr_t) (* (uintptr_t *)&portStatus), 0);
if ( kr == kIOReturnSuccess )
{
USBLog(4, "AppleUSBHub[%p]::EnablePowerAfterOvercurrentEntry - port %d of hub at 0x%x status(%p) change(%p)", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (void*)portStatus.statusFlags, (void*)portStatus.changeFlags);
if ((portStatus.statusFlags & kHubPortPower) == 0)
{
USBLog(1, "AppleUSBHub[%p]::EnablePowerAfterOvercurrentEntry - port %d of hub at 0x%x is not powered on! portPMState=%d. Waiting %d ms and then start()'ing port", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, _portPMState, kIOWaitTimeBeforeReEnablingPortPowerAfterOvercurrent);
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(_bus->getWorkLoop()->inGate()){USBLog(1, "AppleUSBHubPort[%p]::EnablePowerAfterOvercurrentEntry - IOSleep in gate:%d", this, 1);}}
#endif
IOSleep(kIOWaitTimeBeforeReEnablingPortPowerAfterOvercurrent);
USBTrace( kUSBTHubPort, kTPHubPortEnablePowerAfterOvercurrent, (uint32_t)_hub->_locationID, _portNum, _portPMState, 1);
start();
_portPMState = usbHPPMS_active;
}
else
{
USBLog(5, "AppleUSBHub[%p]::EnablePowerAfterOvercurrentEntry - port %d of hub at 0x%x is powered on, nothing to do here! portPMState=%d", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, _portPMState);
}
}
else
{
USBLog(1,"AppleUSBHub[%p]::EnablePowerAfterOvercurrentEntry GetPortStatus for port %d of hub @ 0x%x returned 0x%x, so port might be dead for good", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, kr);
USBTrace( kUSBTHubPort, kTPHubPortEnablePowerAfterOvercurrent, (uint32_t)_hub->_locationID, _portNum, kr, 2);
}
}
bool
AppleUSBHubPort::DetectExpressCardCantWake()
{
if ( _hub && !_detectedExpressCardCantWake )
{
USBLog(2, "AppleUSBHubPort[%p]::DetectExpressCardCantWake found an express card device which will disconnect across sleep port %d of hub @ 0x%x ", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID );
_detectedExpressCardCantWake = true;
if (_portDevice)
{
IOUSBDevice *cachedPortDevice = _portDevice;
cachedPortDevice->retain();
_cachedBadExpressCardVID = cachedPortDevice->GetVendorID();
_cachedBadExpressCardPID = cachedPortDevice->GetProductID();
cachedPortDevice->release();
}
return true;
}
return false;
}