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/IOUSBDevice.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBLog.h>
#include "AppleUSBHubPort.h"
#define super OSObject
#define self this
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 = 0;
_portPowerAvailable = powerAvailable;
_captive = captive;
_state = hpsNormal;
_retryPortStatus = false;
_statusChangedThreadActive = false;
_initThreadActive = false;
_inCommandSleep = false;
_attachRetry = 0;
_devZeroCounter = 0;
_attachMessageDisplayed = false;
_overCurrentNoticeDisplayed = false;
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;
}
_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);
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);
return kIOReturnNoMemory;
}
InitPortVectors();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::start(void)
{
USBLog(5, "AppleUSBHubPort[%p]::start: forking init thread", this);
retain(); thread_call_enter(_initThread);
USBLog(5, "AppleUSBHubPort[%p]::start: fork complete", this);
return kIOReturnSuccess;
}
void
AppleUSBHubPort::free(void)
{
if (_runLock) {
IOLockFree(_runLock);
_runLock = 0;
}
if (_initLock) {
IOLockFree(_initLock);
_initLock = 0;
}
super::free();
}
void
AppleUSBHubPort::stop(void)
{
USBLog(5, "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
{
USBLog(2, "AppleUSBHubPort[%p]::stop - trying command sleep (%d/%d).", this,_statusChangedThreadActive, _initThreadActive);
_inCommandSleep = true;
if (_statusChangedThreadActive)
gate->commandSleep(&_statusChangedThreadActive, THREAD_UNINT);
else if (_initThreadActive)
gate->commandSleep(&_initThreadActive, THREAD_UNINT);
_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;
}
RemoveDevice();
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->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;
}
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 waiting %d ms for power on", this, _portNum, _hub, _hubDesc->powerOnToGood * 2);
IOSleep(_hubDesc->powerOnToGood * 2);
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(%8x), change(%8x) 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;
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);
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(0, "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%lx - resetting port", this, _portNum, _hub->_locationID);
SetPortVector(&AppleUSBHubPort::AddDeviceResetChangeHandler, kHubPortBeingReset);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
if (err)
{
USBLog(3, "***** AppleUSBHubPort[%p]::AddDevice - port %d on hub %p - unable (err = %x) to reset port", this, _portNum, _hub, err);
FatalError(err, "set feature (resetting port)");
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(1, "AppleUSBHubPort[%p]::AddDevice - port[%d] not in reset after %d ms", this, _portNum, i);
if (i == 10)
{
USBLog(1, "AppleUSBHubPort[%p]::AddDevice - retrying SetPortReset", this);
err = _hub->SetPortFeature(kUSBHubPortResetFeature, _portNum);
}
IOSleep(1);
}
}
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;
if (_portDevice)
{
cachedPortDevice = _portDevice;
_portDevice = NULL;
USBLog(3, "AppleUSBHubPort[%p]::RemoveDevice start (%s)", this, cachedPortDevice->getName());
usbPlane = cachedPortDevice->getPlane(kIOUSBPlane);
if ( usbPlane )
cachedPortDevice->detachAll(usbPlane);
cachedPortDevice->terminate(kIOServiceRequired);
cachedPortDevice->release();
}
InitPortVectors();
}
IOReturn
AppleUSBHubPort::SuspendPort( bool suspend)
{
IOReturn err = kIOReturnSuccess;
IOUSBHubPortStatus status;
USBLog(5, "AppleUSBHubPort[%p]::SuspendPort(%d) for port %d", this, suspend, _portNum);
do {
err = _hub->GetPortStatus(&status, _portNum);
if (kIOReturnSuccess != err)
{
USBLog(3,"AppleUSBHubPort[%p]::SuspendPort Could not get Port Status: 0x%x", this, err);
break;
}
if (!suspend && !(status.statusFlags & kHubPortSuspend) )
{
USBLog(5,"AppleUSBHubPort[%p]::SuspendPort Port was NOT suspended", this);
if ( _portDevice )
{
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortWasNotSuspended, _portDevice, NULL);
_portDevice->release();
}
break;
}
SetPortVector(&AppleUSBHubPort::HandleSuspendPortHandler, kHubPortSuspend);
if (suspend)
{
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 )
{
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenResumed, _portDevice, NULL);
_portDevice->release();
}
err = kIOReturnSuccess;
}
else
{
if ( _portDevice )
{
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenSuspended, _portDevice, &err);
_portDevice->release();
}
}
}
else
{
err = _hub->ClearPortFeature(kUSBHubPortSuspendFeature, _portNum);
if ( err != kIOReturnSuccess )
{
USBLog(3, "AppleUSBHubPort[%p]::SuspendPort Could not ClearPortFeature (%d) (kUSBHubPortSuspendFeature): (0x%x)", this, _portNum, err);
}
}
} while (false);
if ( err != kIOReturnSuccess )
{
if ( _portDevice )
{
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenSuspended, _portDevice, &err);
_portDevice->release();
}
SetPortVector(&AppleUSBHubPort::DefaultSuspendChangeHandler, kHubPortSuspend);
}
return err;
}
IOReturn
AppleUSBHubPort::ReEnumeratePort(UInt32 options)
{
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- reenumerating port %d, options 0x%lx",this, _portNum, options);
if ( (options & kUSBAddExtraResetTimeMask) )
{
USBLog(5,"AppleUSBHubPort[%p]::ReEnumeratePort -- reenumerating port %d, options 0x%lx",this, _portNum, 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:%lX, wValue:%X, wIndex:%X, IOReturn: 0x%x",this, _portNum, 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;
USBLog(5, "AppleUSBHubPort[%p]::ResetPort for port %d", this, _portNum);
do {
_devZero = AcquireDeviceZero();
if (!_devZero)
{
USBLog(3, "AppleUSBHubPort[%p]::ResetPort for port %d could not get devZero lock", this, _portNum);
err = kIOReturnCannotLock;
break;
}
#if 1
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;
}
} while (false);
if (err == kIOReturnSuccess)
{
_bus->WaitForReleaseDeviceZero();
}
else if(_devZero)
{
_bus->ReleaseDeviceZero();
_devZero = false;
}
if (err && _portDevice)
{
USBLog(5, "AppleUSBHubPort[%p]::ResetPort - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenReset, _portDevice, &err);
_portDevice->release();
}
return err;
}
void
AppleUSBHubPort::FatalError(IOReturn err, char *str)
{
if (_hub->IsHSRootHub())
{
if (err != kIOUSBDeviceNotHighSpeed)
{
USBLog(1, "AppleUSBHubPort[%p]: Port %d of Hub at 0x%lx: error 0x%x: %s",this, _portNum, _hub->_locationID, err, str);
}
}
else
{
USBError(1, "AppleUSBHubPort: Port %d of Hub at 0x%lx reported error 0x%x while doing %s", _portNum, _hub->_locationID, err, str);
}
if (_portDevice != 0)
{
USBLog(2,"AppleUSBHubPort: Removing %s from port %d", _portDevice->getName(), _portNum);
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", this, _portNum, _hub);
if ( _extraResetDelay )
{
USBLog(5, "***** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - delaying 100ms workaround", this);
IOSleep(100);
_extraResetDelay = false;
}
do
{
if (_state != hpsDeadDeviceZero)
{
if ( !(statusFlags & kHubPortConnection) )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - device has gone away", 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 %ld", this, _portNum, _hub, delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d on hub %p - delaying %ld ms", this, _portNum, _hub, 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, 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", this, _portNum, _hub);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
}
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 %ld milliseconds", this, _portNum, delay);
IOSleep(delay);
}
if ( err == kIOReturnSuccess )
_getDeviceDescriptorFailed = false;
_state = hpsSetAddress;
usbDevice = _bus->MakeDevice( &address );
if (usbDevice == NULL || address == 0)
{
USBLog(3,"**5** AppleUSBHubPort[%p]::AddDeviceResetChangeHandler - port %d, unable to set device %p to address %d - disabling port", this, _portNum, 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 = 0;
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 %ld milliseconds", this, _portNum, 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);
_portDevice->setProperty("PortNum",_portNum,32);
_portDevice->SetProperties();
if ( IsCaptive() )
_portDevice->setProperty("non-removable","yes");
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 %ld", this, _portNum, _hub, delay);
}
USBLog(5, "**1** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - delaying %ld ms", this, _portNum, _hub, 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, _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, _portNum, _hub);
}
else
{
_speed = kUSBDeviceSpeedFull;
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - found full speed device", this, _portNum, _hub);
}
}
USBLog(5, "**2** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - configuring dev zero", this, _portNum, _hub);
err = DoConfigureDeviceZero(_bus, 8, _speed, _hub->_device->GetAddress(), _portNum);
_getDeviceDescriptorFailed = true;
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - getting dev zero desc", this, _portNum, _hub);
err = GetDevZeroDescriptorWithRetries();
if ( err != kIOReturnSuccess )
{
USBLog(5, "**3** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d on hub %p - failed to get dev zero desc", this, _portNum, _hub);
_getDeviceDescriptorFailed = true;
_state = hpsDeadDeviceZero;
}
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 %ld milliseconds", this, _portNum, delay);
IOSleep(delay);
}
if (!err)
_getDeviceDescriptorFailed = false;
_state = hpsSetAddress;
if (_portDevice)
{
err = _bus->SetDeviceZeroAddress(_portDevice->GetAddress());
if (err)
{
USBLog(3,"**5** AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, unable to set device %p to address %d - disabling port", this, _portNum, _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)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenReset, _portDevice, &err);
_portDevice->release();
}
FatalError(err, "clearing port feature");
return err;
}
_bus->ReleaseDeviceZero();
_devZero = false;
_state = hpsSetAddressFailed;
if ( _portDevice)
{
err = kIOReturnNoDevice;
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenReset, _portDevice, &err);
_portDevice->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 %ld milliseconds", this, _portNum, 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)
{
USBLog(5, "AppleUSBHubPort[%p]::HandleResetPortHandler - port %d, Sending kIOUSBMessagePortHasBeenReset message (0x%x)", this, _portNum, err);
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenReset, _portDevice, &err);
_portDevice->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, changeFlags: 0x%x", this, _portNum, changeFlags);
SetPortVector(&AppleUSBHubPort::DefaultSuspendChangeHandler, kHubPortSuspend);
_portDevice->retain();
_portDevice->message(kIOUSBMessagePortHasBeenResumed, _portDevice, 0);
_portDevice->release();
return kIOReturnSuccess;
}
IOReturn
AppleUSBHubPort::DefaultOverCrntChangeHandler(UInt16 changeFlags, UInt16 statusFlags)
{
IOUSBHubDescriptor hubDescriptor;
bool individualPortPower = FALSE;
UInt16 characteristics;
IOUSBHubPortStatus portStatus;
IOReturn err;
USBLog(5, "AppleUSBHubPort[%p]::DefaultOverCrntChangeHandler. Port %d", this, _portNum );
err = _hub->GetPortStatus(&portStatus, _portNum);
if ( (err == kIOReturnSuccess) && (portStatus.changeFlags != 0x1f) )
{
if ( (portStatus.statusFlags & kHubPortOverCurrent))
{
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;
if ( !_overCurrentNoticeDisplayed)
{
DisplayOverCurrentNotice( individualPortPower );
_overCurrentNoticeDisplayed = true;
}
}
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%x", 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).", this, _portNum, 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
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler port (%d) - waiting 100 ms before asserting reset", this, _portNum);
_connectionChangedState = 2;
IOSleep(100);
}
if ( _devZero )
{
USBLog(5, "AppleUSBHubPort[%p]::DefaultConnectionChangeHandler - port %d - releasing devZero lock", this, _portNum);
_connectionChangedState = 3;
_bus->ReleaseDeviceZero();
_devZero = false;
}
if (_portDevice != 0 )
{
_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(%8x)/change(%8x) - 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);
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();
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%lx held! Waiting...", this, _portNum, _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(%8x)/change(%8x) - clearing retryPortStatus", this, _portNum, _portStatus.statusFlags, _portStatus.changeFlags);
_retryPortStatus = false;
}
_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 %lx feature.", this, _portNum, which, _changeHandler[which].clearFeature);
_statusChangedState = 4;
if ((err = _hub->ClearPortFeature(_changeHandler[which].clearFeature, _portNum)))
{
USBLog(3, "AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - error %x clearing %lx feature.", this, _portNum, err, _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 %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(%8x) - change(%8x) - 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(3,"AppleUSBHubPort[%p]::PortStatusChangedHandler - port %d - error %x from (%d) handler", this, _portNum, 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(); thread_call_enter(_portStatusChangedHandlerThread);
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(3, "AppleUSBHubPort[%p]::DetachDevice Port %d being detached", this, _portNum);
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%lx)", this, _portNum, _hub->_locationID);
_attachMessageDisplayed = true;
}
_attachRetry++;
if ( _attachRetry % 4 == 0 )
{
delay = _attachRetry * 100;
USBLog(2, "AppleUSBHubPort[%p]::DetachDevice (Port %d), attachRetry limit reached. delaying for %ld milliseconds", this, _portNum, 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(5, "AppleUSBHubPort[%p]::DetachDevice - port %d - device has gone away", this, _portNum);
_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, 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, _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 %ld milliseconds", this, _portNum, err, delay);
IOSleep( delay );
retries--;
}
}
while ( err && retries > 0 );
return err;
}
bool
AppleUSBHubPort::AcquireDeviceZero()
{
IOReturn err;
bool devZero = false;
err = _bus->AcquireDeviceZero();
if ( err == kIOReturnSuccess )
devZero = true;
if ( devZero )
_devZeroCounter++;
return devZero;
}
void
AppleUSBHubPort::DisplayOverCurrentNotice(bool individual)
{
if ( individual )
_hub->_device->DisplayUserNotification(kUSBIndividualOverCurrentNotificationType);
else
_hub->_device->DisplayUserNotification(kUSBGangOverCurrentNotificationType);
return;
}
bool
AppleUSBHubPort::willTerminate( IOService * provider, IOOptionBits options )
{
USBLog(3, "AppleUSBHubPort[%p]::willTerminate", this);
ReleaseDevZeroLock();
return false;
}