AppleUSBHubPort.cpp [plain text]
#include <UserNotification/KUNCUserNotifications.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/usb/USBSpec.h> // USBHub.h should include this file
#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 "AppleUSBHubPort.h"
#define super OSObject
#define self this
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, 0x0307, 0x0307 },
{ 0x05ac, 0x0201, 0x0206 },
{ 0x05ac, 0x9212, 0x9217 },
};
#define ERRATALISTLENGTH (sizeof(gErrataList)/sizeof(CaptiveErrataListEntry))
OSDefineMetaClassAndStructors(AppleUSBHubPort, OSObject)
static portStatusChangeVector defaultPortVectors[kNumChangeHandlers] =
{
{ 0, kHubPortOverCurrent, kUSBHubPortOverCurrentChangeFeature },
{ 0, kHubPortBeingReset, kUSBHubPortResetChangeFeature },
{ 0, kHubPortSuspend, kUSBHubPortSuspendChangeFeature },
{ 0, kHubPortEnabled, kUSBHubPortEnableChangeFeature },
{ 0, kHubPortConnection, kUSBHubPortConnectionChangeFeature },
};
IOReturn
AppleUSBHubPort::init( AppleUSBHub *parent, int portNum, UInt32 powerAvailable, bool captive )
{
_hub = parent;
_bus = parent->_bus;
_hubDesc = &parent->_hubDescriptor;
_portNum = portNum;
_portDevice = NULL;
_portPowerAvailable = powerAvailable;
_captive = captive;
_state = hpsNormal;
_retryPortStatus = false;
_statusChangedThreadActive = false;
_initThreadActive = false;
_inCommandSleep = false;
_attachRetry = 0;
_devZeroCounter = 0;
_attachMessageDisplayed = false;
_overCurrentNoticeDisplayed = false;
_portPMState = usbHPPMS_uninitialized;
_resumePending = false;
_portResumeRecoveryTime = kPortResumeRecoveryTime;
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;
}
InitPortVectors();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::start(void)
{
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);
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);
USBLog(3, "AppleUSBHubPort[%p]::stop called, _devZero = (%d).", this, _devZero);
if ( _statusChangedThreadActive || _initThreadActive)
{
UInt32 retries = 0;
IOWorkLoop *myWL = NULL;
IOCommandGate *gate = NULL;
if (_bus)
myWL = _bus->getWorkLoop();
if (!myWL)
{
USBLog(2, "AppleUSBHubPort[%p]::stop called, no workloop.", this);
}
else
{
gate = _bus->GetCommandGate();
if (!gate)
{
USBLog(2, "AppleUSBHubPort[%p]::stop - i got the WL but there is no gate.", this);
}
if (myWL->onThread())
{
USBLog(2, "AppleUSBHubPort[%p]::stop - i am on the main thread. DANGER AHEAD.", this);
}
}
while ( retries < 600 && ( _statusChangedThreadActive || _initThreadActive) )
{
if (!myWL || !gate || myWL->onThread() || !myWL->inGate())
{
IOSleep( 100 );
}
else
{
IOReturn kr;
USBLog(2, "AppleUSBHubPort[%p]::stop - trying command sleep (%d/%d).", this, _statusChangedThreadActive, _initThreadActive);
_inCommandSleep = true;
if (_statusChangedThreadActive)
{
kr = gate->commandSleep(&_statusChangedThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _statusChangedThreadActive commandSleep returned %d", this, kr);
}
}
else if (_initThreadActive)
{
kr = gate->commandSleep(&_initThreadActive);
if (kr != THREAD_AWAKENED)
{
USBLog(5,"AppleUSBHubPort[%p]::stop _initThreadActive commandSleep returned %d", this, kr);
}
}
_inCommandSleep = false;
USBLog(2, "AppleUSBHubPort[%p]::stop - returned from command sleep (%d,%d)!!", this, _statusChangedThreadActive, _initThreadActive);
}
retries++;
}
}
if ( _statusChangedThreadActive || _initThreadActive)
{
USBLog(2, "AppleUSBHubPort[%p]::stop - not quiesced - just returning", this);
return;
}
if (_devZero)
{
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "AppleUSBHubPort[%p]::stop - calling RemoveDevice", this);
RemoveDevice();
if (v3Bus && (v3Bus->IsControllerAvailable()) && !_hub->isInactive() && !_hub->_portSuspended)
{
USBLog(5, "AppleUSBHubPort[%p]::stop - removing port power", this);
if ( (err = _hub->ClearPortFeature(kUSBHubPortPowerFeature, _portNum)) )
{
USBLog(1, "AppleUSBHubPort[%p]::stop - err (%p) from ClearPortFeature", this, (void*)err);
}
}
if (_initThread)
{
thread_call_cancel(_initThread);
thread_call_free(_initThread);
_initThread = 0;
}
if (_portStatusChangedHandlerThread)
{
thread_call_cancel(_portStatusChangedHandlerThread);
thread_call_free(_portStatusChangedHandlerThread);
_portStatusChangedHandlerThread = 0;
}
}
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 %p beginning INIT (getting _initLock)", this, _portNum, _hub);
_initThreadActive = true;
IOLockLock(_initLock);
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p enabling port power", this, _portNum, _hub);
if ((err = _hub->SetPortFeature(kUSBHubPortPowerFeature, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p could not (err = %x) enable port power", this, _portNum, _hub, err);
FatalError(err, "setting port power");
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p waiting %d ms for power on", this, _portNum, _hub, _hubDesc->powerOnToGood * 2);
IOSleep(_hubDesc->powerOnToGood * 2);
if (!_captive)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p non-captive device - leaving PortInit", this, _portNum, _hub);
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p about to get port status #1", this, _portNum, _hub);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p could not get (err = %x) port status #1", this, _portNum, _hub, err);
FatalError(err, "getting port status (2)");
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p - status(%04x), change(%04x) bits detected", this, _portNum, _hub, status.statusFlags, status.changeFlags);
if (status.changeFlags & kHubPortConnection)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p - clearing connection change feature", this, _portNum, _hub);
if ((err = _hub->ClearPortFeature(kUSBHubPortConnectionChangeFeature, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p could not (err = %x) clear connection change", this, _portNum, _hub, err);
FatalError(err, "clearing port connection change");
goto errorExit;
}
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p about to get port status #2", this, _portNum, _hub);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
USBLog(3, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p could not (err = %x) get port status #2", this, _portNum, _hub, err);
FatalError(err, "getting port status (3)");
goto errorExit;
}
}
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p device detected calling AddDevice", this, _portNum, _hub);
if ((err = AddDevice()))
FatalError(err, "adding device");
}
errorExit:
USBLog(5, "***** AppleUSBHubPort[%p]::PortInit - port %d on hub %p - done - releasing _initLock", this, _portNum, _hub);
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);
}
}
}
IOReturn
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 %p - start", this, _portNum, _hub);
if ((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable))
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - hub[%p] changing to power state[%d] - aborting AddDevice", this, _hub, (int)_hub->_powerStateChangingTo);
}
else do
{
if ( !_devZero )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - bus %p - acquiring dev zero lock", this, _portNum, _hub, _bus);
_devZero = AcquireDeviceZero();
if (!_devZero)
{
USBLog(2, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - bus %p - unable to get devZero lock", this, _portNum, _hub, _bus);
FatalError(kIOReturnCannotLock, "acquiring device zero");
break;
}
}
else
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - bus %p - already owned devZero lock", this, _portNum, _hub, _bus);
}
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d @ 0x%x - resetting port", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
SetPortVector(&AppleUSBHubPort::AddDeviceResetChangeHandler, kHubPortBeingReset);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
if (err)
{
if ( err != kIOUSBDeviceNotHighSpeed)
{
USBLog(1, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - unable (err = %x) to reset port (set feature (resetting port)", this, _portNum, _hub, err);
}
if (_portDevice)
{
USBLog(1,"AppleUSBHubPort: Removing %s from port %d of Hub at 0x%x", _portDevice->getName(), _portNum, (uint32_t)_hub->_locationID);
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;
while (j++ < 5 && !resetActive && !err)
{
i = 0;
while ((i++ < 10) && !err)
{
err = _hub->GetPortStatus(&status, _portNum);
if ((status.statusFlags & kHubPortBeingReset) || (status.changeFlags & kHubPortBeingReset) || (_state == hpsSetAddress))
{
resetActive = true;
break; }
USBLog(2, "AppleUSBHubPort[%p]::AddDevice - port[%d] not in reset after %d ms", this, _portNum, i);
if (i == 10)
{
USBLog(2, "AppleUSBHubPort[%p]::AddDevice - retrying SetPortReset", this);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
}
IOSleep(1);
}
}
if ( !resetActive)
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - port[%d] not in reset after 5 retries", this, _portNum);
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - sleeping 100 ms - err[%p]", this, _portNum, _hub, (void*)err);
IOSleep(100);
} while(false);
if (err && _devZero)
{
USBLog(3, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p- bus %p - got error (%x) - releasing devZero lock", this, _portNum, _hub, _bus, err);
if (!checkingForDeadHub)
{
if ( (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");
if (err == kIOUSBTransactionTimeout)
{
_hub->CallCheckForDeadHub(); checkingForDeadHub = true;
}
}
}
_bus->ReleaseDeviceZero();
_devZero = false;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
}
USBLog(5, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - (err = %x) done - returning .", this, _portNum, _hub, err);
return(err);
}
void
AppleUSBHubPort::RemoveDevice(void)
{
bool ok;
const IORegistryPlane *usbPlane;
IOUSBDevice *cachedPortDevice;
IOLockLock(_removeDeviceLock);
cachedPortDevice = _portDevice;
_portDevice = NULL;
IOLockUnlock(_removeDeviceLock);
if (cachedPortDevice)
{
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice start (%s)", this, cachedPortDevice->getName());
usbPlane = cachedPortDevice->getPlane(kIOUSBPlane);
if ( _usingExtraPortPower )
{
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice returning _portPowerAvailable to kUSB100mAAvailable", this);
_portPowerAvailable = kUSB100mAAvailable;
_usingExtraPortPower = false;
}
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);
IOSleep(100);
}
if (cachedPortDevice->getBusyState())
{
USBError(1, "AppleUSBHubPort: Port %d of Hub at %p about to terminate a busy device (%s) after waiting 10 seconds", _portNum, (void*)_hub->_locationID, cachedPortDevice->getName());
}
cachedPortDevice->terminate(kIOServiceRequired | kIOServiceSynchronous);
}
else
{
USBLog(4, "AppleUSBHubPort[%p]::RemoveDevice - hub no longer active - terminating device[%p] asynchronously", 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::SuspendPort(bool suspend, bool fromDevice)
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
UInt32 resumeRetries = 10;
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 )
{
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);
}
do {
if (_hub->isInactive())
{
if (!suspend && (_portPMState == usbHPPMS_drvr_suspended))
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort(resume) on port(%d)- Inactive hub, doing for free!", this, _portNum);
if ( _portDevice && fromDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenResumed, cachedDevice, NULL);
cachedDevice->release();
_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);
}
err = kIOReturnSuccess;
break;
}
err = _hub->GetPortStatus(&status, _portNum);
if (kIOReturnSuccess != err)
{
USBLog(3,"AppleUSBHubPort[%p]::SuspendPort Could not get Port Status: 0x%x", this, err);
break;
}
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort - GetPortStatus returned status[%p] change[%p]", this, (void*)status.statusFlags, (void*)status.changeFlags );
if (!suspend && !(status.statusFlags & kHubPortSuspend) )
{
USBLog(5,"AppleUSBHubPort[%p]::SuspendPort Port was NOT suspended", this);
if ( _portDevice && fromDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortWasNotSuspended, cachedDevice, NULL);
cachedDevice->release();
}
}
break;
}
USBLog(7, "AppleUSBHubPort[%p]::SuspendPort - setting vector to HandleSuspendPortHandler", this);
SetPortVector(&AppleUSBHubPort::HandleSuspendPortHandler, kHubPortSuspend);
if (suspend)
{
if (fromDevice)
{
if (_portPMState == usbHPPMS_pm_suspended)
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort - converting suspend state from pm_suspended to drvr_suspended statusFlags(%p)", this, (void*)status.statusFlags);
if (status.statusFlags & kHubPortSuspend)
{
IOUSBControllerV3 *v3Bus = NULL;
IOReturn err;
if (_hub)
{
if (_hub->_device)
v3Bus = OSDynamicCast(IOUSBControllerV3, _hub->_device->GetBus());
if (v3Bus && _portDevice)
{
USBLog(5, "AppleUSBHub[%p]::SuspendPort - Enabling endpoints for device at address (%d)", this, (int)_portDevice->GetAddress());
err = v3Bus->EnableAddressEndpoints(_portDevice->GetAddress(), true);
if (err)
{
USBLog(2, "AppleUSBHub[%p]::SuspendPort - EnableAddressEndpoints returned (%p)", this, (void*)err);
}
}
}
}
else
{
USBError(1, "AppleUSBHub[%p]::SuspendPort - expected port to be suspended for conversion, but it is not!!", this);
}
}
_portPMState = usbHPPMS_drvr_suspended;
}
else
{
_portPMState = usbHPPMS_pm_suspended;
}
err = _hub->SetPortFeature(kUSBHubPortSuspendFeature, _portNum);
if ( err != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort Could not SetPortFeature (%d) (kUSBHubPortSuspendFeature): (0x%x)", this, _portNum, err);
if ( _portDevice && fromDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenResumed, cachedDevice, NULL);
cachedDevice->release();
}
}
err = kIOReturnSuccess;
}
else
{
if ( _portDevice && fromDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenSuspended, cachedDevice, &err);
cachedDevice->release();
}
}
}
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort - calling ClearPortFeature", this);
err = _hub->ClearPortFeature(kUSBHubPortSuspendFeature, _portNum);
if ( err != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort Could not ClearPortFeature (%d) (kUSBHubPortSuspendFeature): (0x%x)", this, _portNum, err);
}
_resumePending = true;
USBLog(2, "AppleUSBHubPort[%p]::SuspendPort - RESUME - calling RaisePowerState on hub[%p] port %d and setting _lowerPowerStateOnResume", this, _hub, _portNum);
_hub->RaisePowerState(); if (_lowerPowerStateOnResume)
{
USBLog(1, "AppleUSBHubPort[%p]::SuspendPort - RESUME - _lowerPowerStateOnResume already set (hub %p port %d)- UNEXPECTED!", this, _hub, _portNum);
}
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort - RESUME - setting _lowerPowerStateOnResume - (hub %p port %d)", this, _hub, _portNum);
_lowerPowerStateOnResume = true;
}
} while (false);
if ( err != kIOReturnSuccess )
{
if ( _portDevice && fromDevice)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenSuspended, cachedDevice, &err);
cachedDevice->release();
}
}
USBLog(7, "AppleUSBHubPort[%p]::SuspendPort - setting vector to DefaultSuspendChangeHandler", this);
SetPortVector(&AppleUSBHubPort::DefaultSuspendChangeHandler, kHubPortSuspend);
}
return err;
}
IOReturn
AppleUSBHubPort::ReEnumeratePort(UInt32 options)
{
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();
return AddDevice();
}
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->DoDeviceRequest(&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->DoDeviceRequest(&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;
bool wait100ms = false;
USBLog(5, "+AppleUSBHubPort[%p]::ResetPort for port %d", this, _portNum);
if ( ShouldApplyDisconnectWorkaround() )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, will wait 500 ms", this, _portNum);
IOSleep(500);
wait100ms = true;
}
do {
_devZero = AcquireDeviceZero();
if (!_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort for port %d could not get devZero lock", this, _portNum);
err = kIOReturnCannotLock;
break;
}
#if 0
err = _hub->GetPortStatus(&status, _portNum);
if (kIOReturnSuccess != err)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort for port %d could not get port status (0x%x)", this, _portNum, err);
break;
}
if ( status.statusFlags & kHubPortSuspend)
{
err = _hub->ClearPortFeature(kUSBHubPortSuspendFeature, _portNum);
if (kIOReturnSuccess != err)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort Could not ClearPortFeature (%d) (kHubPortSuspend): (0x%x)", this, _portNum, err);
break;
}
err = _hub->GetPortStatus(&status, _portNum);
if (kIOReturnSuccess != err)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort for port %d could not get port status (0x%x)", this, _portNum, err);
break;
}
if ( status.statusFlags & kHubPortSuspend)
{
USBError(1, "AppleUSBHubPort[%p]::ResetPort for port %d Port is still suspended after clearing it", this, _portNum);
}
}
#endif
SetPortVector(&AppleUSBHubPort::HandleResetPortHandler, kHubPortBeingReset);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
if (err != kIOReturnSuccess)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort Could not ClearPortFeature (%d) (kUSBHubPortResetFeature): (0x%x)", this, _portNum, err);
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
break;
}
if ( wait100ms )
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d, waiting for 100ms after reset", this, _portNum);
IOSleep(100);
}
} while (false);
if (err == kIOReturnSuccess)
{
_bus->WaitForReleaseDeviceZero();
}
else if(_devZero)
{
_bus->ReleaseDeviceZero();
_devZero = false;
}
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();
}
}
USBLog(5, "-AppleUSBHubPort[%p]::ResetPort for port %d", this, _portNum);
return err;
}
void
AppleUSBHubPort::FatalError(IOReturn err, const char *str)
{
if (_hub->IsHSRootHub())
{
if (err != kIOUSBDeviceNotHighSpeed)
{
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);
}
}
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);
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;
v2Bus = OSDynamicCast(IOUSBControllerV2, bus);
if(v2Bus != 0)
{
return(v2Bus->ConfigureDeviceZero(maxPacketSize, speed, hub, port));
}
else
{
return(bus->ConfigureDeviceZero(maxPacketSize, speed));
}
}
IOReturn
AppleUSBHubPort::AddDeviceResetChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOReturn err = kIOReturnSuccess;
IOReturn err2 = kIOReturnSuccess;
IOUSBDevice * usbDevice;
USBDeviceAddress address;
UInt32 delay = 10;
const IORegistryPlane * usbPlane;
USBLog(5, "***** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - start - status(0x%04x) change (0x%04x)", this, _portNum, _hub, (int)statusFlags, (int)changeFlags);
if ( _extraResetDelay )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - delaying 100ms workaround", this);
IOSleep(100);
_extraResetDelay = false;
}
do
{
if (_state != hpsDeadDeviceZero)
{
if (changeFlags & kHubPortEnabled)
{
USBLog(1, "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 %p - leaving (kHubPortBeingReset)", this, _portNum, _hub);
break;
}
if (_getDeviceDescriptorFailed)
{
delay = 300;
USBLog(3, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - new delay %d", this, (uint32_t)_portNum, _hub, (uint32_t)delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - delaying %d ms", this, (uint32_t)_portNum, _hub, (uint32_t)delay);
IOSleep(delay);
if (_portStatus.statusFlags & kHubPortLowSpeed)
{
_speed = kUSBDeviceSpeedLow;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - found low speed device", this, _portNum, _hub);
}
else
{
if (_portStatus.statusFlags & kHubPortHighSpeed)
{
_speed = kUSBDeviceSpeedHigh;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - found high speed device", this, _portNum, _hub);
}
else
{
_speed = kUSBDeviceSpeedFull;
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - found full speed device", this, _portNum, _hub);
}
}
USBLog(5, "**2** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - configuring dev zero", this, _portNum, _hub);
err = DoConfigureDeviceZero(_bus, (kUSBDeviceSpeedHigh == _speed) ? 64 : 8, _speed, _hub->_device->GetAddress(), _portNum);
_getDeviceDescriptorFailed = true;
bzero(&_desc, sizeof(_desc));
USBLog(5, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - getting dev zero desc", this, _portNum, _hub);
err = GetDevZeroDescriptorWithRetries();
if ( err != kIOReturnSuccess )
{
USBLog(5, "**3** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - failed to get dev zero desc, detach'ing device", this, _portNum, _hub);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
if ( (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");
_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(3, "**4** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, previous SetAddress failed, sleeping for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)delay);
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 @ 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);
_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 @ 0x%x, unable to set device %p to address %d - disabling port", this, _portNum, (uint32_t)_hub->_locationID, usbDevice, address );
if ( (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");
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
_portDevice = NULL;
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
return DetachDevice();
}
else
{
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);
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
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);
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);
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
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);
IOSleep(10); err = AddDevice();
return err;
}
_state = hpsNormal;
err = DoCreateDevice(_bus, usbDevice, address, _desc.bMaxPacketSize0, _speed, _portPowerAvailable, _hub->_device->GetAddress(), _portNum);
if ( !err )
{
_portDevice = usbDevice;
}
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, _portDevice disappeared, cleaning up", this, _portNum);
_retryPortStatus = true;
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
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);
IOSleep(10); err = AddDevice();
return err;
}
USBLog(5, "**10** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, at addr: %d, Succesful", this, _portNum, address);
_attachRetry = 0;
if ( _attachMessageDisplayed )
{
USBError(1,"[%p] The IOUSBFamily has successfully enumerated the device.", this);
_attachMessageDisplayed = false;
}
usbPlane = _portDevice->getPlane(kIOUSBPlane);
if ( usbPlane )
{
_portDevice->attachToParent( _hub->_device, usbPlane);
}
else
{
USBLog(1, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - we could not get the kIOUSBPlane!! Problems ahead", this);
}
_portDevice->setProperty("PortNum",_portNum,32);
_portDevice->SetProperties();
_portDevice->SetHubParent(_hub);
if ( IsCaptive() || IsCaptiveOverride(_portDevice->GetVendorID(), _portDevice->GetProductID()) )
_portDevice->setProperty("non-removable","yes");
if (_portPowerAvailable == kUSB100mAAvailable)
{
UInt32 extraPowerAllocated = 0;
bool keepExtraPower = false;
USBLog(6, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - Checking to see if our device has 400mA extra", this);
extraPowerAllocated = _portDevice->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);
_portDevice->ReturnExtraPower(kUSBPowerDuringWake, extraPowerAllocated);
}
}
else
{
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);
_portDevice->setProperty("HubWakePowerReserved", extraPowerAllocated, 32);
keepExtraPower = true;
}
else
{
int numConfigs = _portDevice->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 = _portDevice->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;
_portDevice->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);
_portDevice->ReturnExtraPower(kUSBPowerDuringWake, extraPowerAllocated);
}
}
}
USBLog(5, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, calling registerService for device %s", this, _portNum, _portDevice->getName() );
_portDevice->registerService();
} while(false);
if (err)
{
if (_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, err = %x, releasing devZero lock", this, _portNum, err);
_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);
return err;
}
IOReturn
AppleUSBHubPort::HandleResetPortHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOReturn err = kIOReturnSuccess;
UInt32 delay = 10;
USBLog(5, "***** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - start", this, _portNum, _hub);
SetPortVector(&AppleUSBHubPort::DefaultResetChangeHandler, kHubPortBeingReset);
if ( _extraResetDelay )
{
USBLog(5, "***** AppleUSBHubPort[%p]::HandleResetPortHandler - delaying 100ms workaround", this);
IOSleep(100);
_extraResetDelay = false;
}
do
{
if (_state != hpsDeadDeviceZero)
{
if (_portStatus.statusFlags & kHubPortBeingReset)
{
USBLog(5, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - leaving (kHubPortBeingReset)", this, _portNum, _hub);
SetPortVector(&AppleUSBHubPort::HandleResetPortHandler, kHubPortBeingReset);
return kIOReturnSuccess;
}
if (_getDeviceDescriptorFailed)
{
delay = 300;
USBLog(3, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - new delay %d", this, (uint32_t)_portNum, _hub, (uint32_t)delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - delaying %d ms", this, (uint32_t)_portNum, _hub, (uint32_t)delay);
IOSleep(delay);
if (_portStatus.statusFlags & kHubPortLowSpeed)
{
_speed = kUSBDeviceSpeedLow;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - found low speed device", this, (uint32_t)_portNum, _hub);
}
else
{
if (_portStatus.statusFlags & kHubPortHighSpeed)
{
_speed = kUSBDeviceSpeedHigh;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - found high speed device", this, (uint32_t)_portNum, _hub);
}
else
{
_speed = kUSBDeviceSpeedFull;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - found full speed device", this, (uint32_t)_portNum, _hub);
}
}
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - configuring dev zero", this, (uint32_t)_portNum, _hub);
err = DoConfigureDeviceZero(_bus, (kUSBDeviceSpeedHigh == _speed) ? 64 : 8, _speed, _hub->_device->GetAddress(), _portNum);
_getDeviceDescriptorFailed = true;
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - getting dev zero desc", this, (uint32_t)_portNum, _hub);
err = GetDevZeroDescriptorWithRetries();
if ( err != kIOReturnSuccess )
{
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - failed to get dev zero desc, detach'ing device", this, (uint32_t)_portNum, _hub);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
if ( (err = _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum)) )
{
USBLog(1, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, unable (err = %x) to disable port", this, (uint32_t)_portNum, err);
FatalError(err, "clearing port feature");
_bus->ReleaseDeviceZero();
_devZero = false;
_portDevice = NULL;
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
return DetachDevice();
}
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);
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 @ 0x%x, unable to set device %p to address %d - disabling port", this, _portNum, (uint32_t)_hub->_locationID, _portDevice, _portDevice->GetAddress() );
if ( (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");
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 DetachDevice();
}
else
{
IOSleep( 2 );
USBLog(5, "**5** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Releasing DeviceZero after successful SetAddress", this, _portNum);
_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);
_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);
IOSleep(delay);
}
}
_state = hpsNormal;
if (!_portDevice)
{
if (_devZero)
{
USBLog(3, "**9** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, releasing devZero lock", this, _portNum);
_bus->ReleaseDeviceZero();
_devZero = false;
}
USBLog(3, "**9** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, _portDevice disappeared, returning", this, _portNum);
}
_attachRetry = 0;
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);
_hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
_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)
{
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);
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)
{
IOUSBDevice *cachedDevice = _portDevice;
if (cachedDevice)
{
cachedDevice->retain();
cachedDevice->message(kIOUSBMessagePortHasBeenResumed, cachedDevice, 0);
cachedDevice->release();
}
}
}
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;
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultOverCrntChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOUSBHubDescriptor hubDescriptor;
bool individualPortPower = FALSE;
UInt16 characteristics;
IOUSBHubPortStatus portStatus;
IOReturn err;
AbsoluteTime currentTime;
UInt64 elapsedTime;
err = _hub->GetPortStatus(&portStatus, _portNum);
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. Port %d (isRootHub: %d), status = 0x%x, change: 0x%x", this, _portNum, _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", this, _portNum );
hubDescriptor = _hub->GetCachedHubDescriptor();
characteristics = USBToHostWord(hubDescriptor.characteristics);
if ( (characteristics & 0x18) == 0x8 )
individualPortPower = TRUE;
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 ( !_overCurrentNoticeDisplayed || (elapsedTime > 30) )
{
DisplayOverCurrentNotice( individualPortPower );
_overCurrentNoticeDisplayed = true;
clock_get_uptime(&_overCurrentNoticeTimeStamp);
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. not displaying notice because elapsed time %qd is < 5 seconds", this, elapsedTime );
}
}
else
{
USBLog(1, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. No OverCurrent condition. Ignoring. Port %d", this, _portNum );
}
}
return err;
}
IOReturn
AppleUSBHubPort::DefaultResetChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultResetChangeHandler for port %d returning kIOReturnSuccess", this, _portNum);
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultSuspendChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultSuspendChangeHandler for port %d returning kIOReturnSuccess", this, _portNum);
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultEnableChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
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;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - handling port %d changes (%x,%x).", 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);
IOSleep(300);
}
else
{
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - waiting 100 ms before asserting reset", this, _portNum);
_connectionChangedState = 2;
IOSleep(100);
}
else
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - This is a disconnect", this, _portNum);
_connectionChangedState = 2;
_portPMState = usbHPPMS_active; }
}
if ( _devZero )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - releasing devZero lock", this, _portNum);
_connectionChangedState = 3;
_bus->ReleaseDeviceZero();
_devZero = false;
}
if (_portDevice)
{
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);
break;
}
_connectionChangedState = 4;
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 (5)");
break;
}
_connectionChangedState = 8;
USBLog(4, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port %d status(%04x)/change(%04x) - no error from GetPortStatus", this, _portNum, status.statusFlags, status.changeFlags);
if (status.changeFlags & kHubPortConnection)
{
_retryPortStatus = true;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port %d connection bounce", this, _portNum);
break;
}
if (status.statusFlags & kHubPortConnection)
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - device detected, calling AddDevice", this, _portNum);
_state = hpsDeviceZero;
_connectionChangedState = 9;
err = AddDevice();
_connectionChangedState = 10;
}
} while(false);
_ignoreDisconnectOnWakeup = false;
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d done, ending.", this, _portNum);
return err;
}
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();
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;
do
{
if ( !skipOverGetPortStatus )
{
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) )
{
err = kIOReturnNoDevice;
goto errorExit;
}
_statusChangedState = 2;
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - status(0x%04x)/change(0x%04x) - clearing retryPortStatus", this, _portNum, _portStatus.statusFlags, _portStatus.changeFlags);
_retryPortStatus = false;
}
if ( _hub->_ignoreDisconnectOnWakeup && (_portStatus.statusFlags & kHubPortConnection) && (_portStatus.changeFlags & kHubPortConnection) )
{
_ignoreDisconnectOnWakeup = ShouldApplyDisconnectWorkaround();
USBLog(5,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - ShouldApplyDisconnectWorkaround returned %d", this, _portNum, _ignoreDisconnectOnWakeup);
}
_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.", this, (uint32_t)_portNum, which, (uint32_t)_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.", this, (uint32_t)_portNum, err, (uint32_t)_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) )
{
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 @ 0x%x - error %x from (%d) handler", this, _portNum, (uint32_t)_hub->_locationID, err, which);
break;
}
}
while (true);
errorExit:
if ( _attachMessageDisplayed )
{
if ( err != kIOReturnSuccess )
{
USBError(1,"[%p] The IOUSBFamily was not able to enumerate a device.", this);
}
_attachMessageDisplayed = false;
}
if ( _devZero )
{
_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;
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;
}
}
}
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 devZero = 0x%x", this, _devZero);
if (_devZero)
{
(void) _hub->ClearPortFeature(kUSBHubPortEnableFeature, _portNum);
USBLog(1, "AppleUSBHubPort[%p]::ReleaseDevZeroLock()", this);
_state = hpsNormal;
if ( _bus )
_bus->ReleaseDeviceZero();
_devZero = false;
IOSleep(300);
}
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DetachDevice()
{
UInt32 delay = 0;
IOUSBHubPortStatus status;
IOReturn err = kIOReturnSuccess;
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice Port %d of hub @ 0x%x being detached", this, _portNum, (uint32_t)_hub->_locationID);
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 @ location: 0x%x)", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID);
_attachMessageDisplayed = true;
}
_attachRetry++;
if ( _attachRetry % 4 == 0 )
{
delay = _attachRetry * 100;
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice (Port %d of hub @ 0x%x), attachRetry limit reached. delaying for %d milliseconds", this, (uint32_t)_portNum, (uint32_t)_hub->_locationID, (uint32_t)delay);
IOSleep(delay);
if ( (err = _hub->ClearPortFeature(kUSBHubPortPowerFeature, _portNum)) )
{
FatalError(err, "clearing port power feature");
goto ErrorExit;
}
IOSleep(delay);
if ( (err = _hub->SetPortFeature(kUSBHubPortPowerFeature, _portNum)) )
{
FatalError(err, "setting port power feature");
goto ErrorExit;
}
IOSleep(delay);
_state = hpsDeadDeviceZero;
err = kIOReturnNotResponding;
}
else
{
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
FatalError(err, "getting port status (4)");
goto ErrorExit;
}
if ( !(status.statusFlags & kHubPortConnection) )
{
USBLog(1, "AppleUSBHubPort[%p]::DetachDevice - port %d of hub @ 0x%x - device has gone away", this, _portNum, (uint32_t)_hub->_locationID);
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
goto ErrorExit;
}
IOSleep(300);
if ((err = _hub->GetPortStatus(&status, _portNum)))
{
FatalError(err, "getting port status (4)");
goto ErrorExit;
}
if (status.statusFlags & kHubPortConnection)
{
_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);
RemoveDevice();
err = AddDevice();
}
else
{
err = kIOReturnSuccess;
}
}
ErrorExit:
return err;
}
IOReturn
AppleUSBHubPort::GetDevZeroDescriptorWithRetries()
{
UInt32 delay = 30;
UInt32 retries = 4;
IOReturn err = kIOReturnSuccess;
IOReturn portStatusErr = kIOReturnSuccess;
IOUSBHubPortStatus status;
do
{
bzero(&_desc, sizeof(_desc));
err = _bus->GetDeviceZeroDescriptor(&_desc, (kUSBDeviceSpeedHigh == _speed) ? 18 : 8);
if ( err == kIOReturnOverrun )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - GetDeviceZeroDescriptor returned kIOReturnOverrun. Checking to for valid descripor", this, _portNum);
if ( (_desc.bDescriptorType == kUSBDeviceDesc) && (_desc.bLength == 18) )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - GetDeviceZeroDescriptor returned kIOReturnOverrun. Descriptor looks valid", this, _portNum);
err = kIOReturnSuccess;
break;
}
}
if ( err )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - GetDeviceZeroDescriptor returned 0x%x", this, _portNum, err);
portStatusErr = _hub->GetPortStatus(&status, _portNum);
if (portStatusErr != kIOReturnSuccess)
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - GetPortStatus returned 0x%x", this, _portNum, err);
FatalError(err, "getting port status (4)");
break;
}
if ( !(status.statusFlags & kHubPortConnection) )
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - device has gone away", this, _portNum);
_state = hpsDeadDeviceZero;
err = kIOReturnNoDevice;
break;
}
if ( status.statusFlags & kHubPortSuspend)
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d - port is suspended", this, _portNum);
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;
}
}
if ( retries == 2)
delay = 3;
else if ( retries == 1 )
delay = 30;
USBLog(3, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - port %d, err: %x - sleeping for %d milliseconds", this, (uint32_t)_portNum, err, (uint32_t)delay);
IOSleep( delay );
retries--;
}
if ((_hub->_powerStateChangingTo < kIOUSBHubPowerStateLowPower) && (_hub->_powerStateChangingTo != kIOUSBHubPowerStateStable))
{
USBLog(1, "AppleUSBHubPort[%p]::GetDevZeroDescriptorWithRetries - aborting due to power change", this);
}
}
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(7, "AppleUSBHubPort[%p]::AcquireDeviceZero (Port %d of hub @ 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);
if ( _hub == NULL || _hub->_device == NULL )
{
USBLog(1, "AppleUSBHubPort[%p]::DisplayOverCurrentNotice - _hub (%p) or _hub->_device is NULL", this, _hub);
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;
clock_get_uptime(&now);
SUB_ABSOLUTETIME(&now, &(_hub->_wakeupTime));
absolutetime_to_nanoseconds(now, &msElapsed);
msElapsed /= 1000000;
USBLog(6, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d - time since wake: %qd ms", this, _portNum, msElapsed);
if (_portDevice && (msElapsed < (20 * 1000)) )
{
OSBoolean * deviceHasMassStorageInterfaceRef = OSDynamicCast( OSBoolean, _portDevice->getProperty("kHasMSCInterface") );
if ( deviceHasMassStorageInterfaceRef && deviceHasMassStorageInterfaceRef->isTrue() )
{
USBLog(5, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d - we have a disconnect/reconnect on a mass storage device on a hub that tells us to ignore it", this, _portNum);
returnValue = true;
}
else if ( _hub->_isRootHub )
{
USBLog(6, "AppleUSBHubPort[%p]::ShouldApplyDisconnectWorkaround - port %d - we have a disconnect/reconnect on a root hub that tells us to ignore it", this, _portNum);
returnValue = true;
}
}
return returnValue;
}