IOUSBRootHubDevice.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/usb/IOUSBHubPolicyMaker.h>
#include <IOKit/usb/IOUSBControllerV3.h>
static class IOUSBController_ExtraCurrentIOLockClass gExtraCurrentIOLockClass;
#define super IOUSBHubDevice
#define self this
#ifndef IOUSBROOTHUBDEVICE_USE_KPRINTF
#define IOUSBROOTHUBDEVICE_USE_KPRINTF 0
#endif
#if IOUSBROOTHUBDEVICE_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= IOUSBROOTHUBDEVICE_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
#define _MYCONTROLLERSPEED _expansionData->_myControllerSpeed
#define _PROVIDESEXTRACURRENT _expansionData->_builtInController
#define _HASBUILTINPROPERTY _expansionData->_hasBuiltInProperty
#define _HASTUNNELLEDPROPERTY _expansionData->_hasTunnelledProperty
#define _STANDARD_PORT_POWER_IN_SLEEP super::_expansionData->_standardPortSleepCurrent
#define _UNCONNECTEDEXTERNALPORTS super::_expansionData->_unconnectedExternalPorts
OSDefineMetaClassAndStructors( IOUSBRootHubDevice, IOUSBHubDevice )
IOUSBRootHubDevice*
IOUSBRootHubDevice::NewRootHubDevice()
{
IOUSBRootHubDevice *me = new IOUSBRootHubDevice;
if (!me)
return NULL;
if (!me->init())
{
me->release();
me = NULL;
}
return me;
}
bool
IOUSBRootHubDevice::init()
{
if (!super::init())
return false;
if (!_expansionData)
{
_expansionData = (ExpansionData *)IOMalloc(sizeof(ExpansionData));
if (!_expansionData)
return false;
bzero(_expansionData, sizeof(ExpansionData));
}
return true;
}
bool
IOUSBRootHubDevice::InitializeCharacteristics()
{
UInt32 characteristics = kIOUSBHubDeviceIsRootHub;
USBLog(5, "%s[%p]::InitializeCharacteristics", getName(), this);
if (GetSpeed() == kUSBDeviceSpeedHigh)
characteristics |= kIOUSBHubDeviceIsOnHighSpeedBus;
if (GetSpeed() == kUSBDeviceSpeedSuper)
characteristics |= kIOUSBHubDeviceIsOnSuperSpeedBus;
SetHubCharacteristics(characteristics);
return true;
}
bool
IOUSBRootHubDevice::start(IOService *provider)
{
bool returnValue = false;
OSString * cardTypeRef = NULL;
USBLog(5, "%s[%p]::start", getName(), this);
_controller = OSDynamicCast(IOUSBController, provider);
if(_controller)
{
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _controller);
if(v3Bus && _expansionData)
{
_MYCONTROLLERSPEED = v3Bus->_controllerSpeed;
USBLog(5, "%s[%p]::start - _MYCONTROLLERSPEED: %d", getName(), this, _MYCONTROLLERSPEED);
}
else
{
USBLog(5, "%s[%p]::start - _MYCONTROLLERSPEED is zero!!", getName(), this);
}
}
else
{
USBLog(5, "%s[%p]::start - _controller is NULL", getName(), this);
}
cardTypeRef = OSDynamicCast(OSString, provider->getProperty("Card Type"));
if ( cardTypeRef && cardTypeRef->isEqualTo("Built-in") )
{
_PROVIDESEXTRACURRENT = true;
_HASBUILTINPROPERTY = true;
}
else
{
USBLog(6, "IOUSBRootHubDevice[%p]::start - no 'Card Type' property or is NOT 'Built'-in' ", this);
_PROVIDESEXTRACURRENT = false;
_HASBUILTINPROPERTY = false;
}
if ( _controller && _controller->getProvider() && ((_controller->getProvider())->getProperty(kIOPCITunnelledKey) == kOSBooleanTrue) )
{
_PROVIDESEXTRACURRENT = false;
_HASTUNNELLEDPROPERTY = true;
}
else
{
_HASTUNNELLEDPROPERTY = false;
}
returnValue = super::start(provider);
if ( !returnValue)
{
USBLog(5, "IOUSBRootHubDevice[%p]::start - super returned false", this);
return false;
}
_commandGate = IOUSBDevice::_expansionData->_commandGate;
_commandGate->retain();
USBLog(5, "%s[%p]::start (_commandGate %p)", getName(), this, IOUSBDevice::_expansionData->_commandGate);
return returnValue;
}
void
IOUSBRootHubDevice::stop( IOService *provider )
{
if ( _commandGate )
{
_commandGate->release();
_commandGate = NULL;
}
super::stop(provider);
}
void
IOUSBRootHubDevice::free()
{
USBLog(2, "IOUSBRootHubDevice[%p]::+free", this);
if (_expansionData)
{
IOFree(_expansionData, sizeof(ExpansionData));
_expansionData = NULL;
}
super::free();
USBLog(2, "IOUSBRootHubDevice[%p]::-free", this);
}
IOReturn
IOUSBRootHubDevice::GatedDeviceRequest (OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3 )
{
IOUSBRootHubDevice *me = (IOUSBRootHubDevice*)owner;
if (!me)
return kIOReturnNotResponding;
return me->DeviceRequestWorker((IOUSBDevRequest*)arg0, (uintptr_t)arg1, (uintptr_t)arg2, (IOUSBCompletion*)arg3);
}
IOReturn
IOUSBRootHubDevice::DeviceRequest(IOUSBDevRequest *request, IOUSBCompletion *completion)
{
return DeviceRequest(request, 0, 0, completion);
}
IOReturn
IOUSBRootHubDevice::DeviceRequest(IOUSBDevRequest *request, UInt32 noDataTimeout, UInt32 completionTimeout, IOUSBCompletion *completion)
{
IOReturn kr = kIOReturnSuccess;
if (!isInactive() && IOUSBDevice::_expansionData && IOUSBDevice::_expansionData->_commandGate && IOUSBDevice::_expansionData->_workLoop)
{
IOCommandGate * gate = IOUSBDevice::_expansionData->_commandGate;
IOWorkLoop * workLoop = IOUSBDevice::_expansionData->_workLoop;
retain();
workLoop->retain();
gate->retain();
if (_myPolicyMaker && (_myPolicyMaker->getPowerState() == kIOUSBHubPowerStateLowPower))
{
USBLog(5, "IOUSBRootHubDevice[%p]::DeviceRequest - doing a device request while in low power mode - should be OK", this);
}
kr = gate->runAction(GatedDeviceRequest, request, (void*)noDataTimeout, (void*)completionTimeout, completion);
if ( kr != kIOReturnSuccess )
{
USBLog(2,"IOUSBRootHubDevice[%p]::DeviceRequest GatedDeviceRequest runAction() failed (0x%x)",this, kr);
}
gate->release();
workLoop->release();
release();
}
else
{
kr = kIOReturnNotResponding;
}
return kr;
}
IOReturn
IOUSBRootHubDevice::DeviceRequestWorker(IOUSBDevRequest *request, UInt32 noDataTimeout, UInt32 completionTimeout, IOUSBCompletion *completion)
{
#pragma unused (noDataTimeout, completionTimeout, completion)
IOReturn err = kIOReturnSuccess;
UInt16 theRequest;
UInt8 dType, dIndex;
if (!request)
return(kIOReturnBadArgument);
theRequest = (request->bRequest << 8) | request->bmRequestType;
USBLog(7, "+IOUSBRootHubDevice[%p]::DeviceRequestWorker speed: %d _MYCONTROLLERSPEED: %d theRequest: %d", this, _speed, _MYCONTROLLERSPEED, theRequest);
switch (theRequest)
{
case kClearDeviceFeature:
if (request->wIndex == 0)
err = _controller->ClearRootHubFeature(request->wValue);
else
err = kIOReturnBadArgument;
break;
case kGetDescriptor:
dType = request->wValue >> 8;
dIndex = request->wValue & 0x00FF;
switch (dType) {
case kUSBDeviceDesc:
{
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
RHCommandHeaderPtr command = (RHCommandHeaderPtr)request->pData;
command->request = 0;
command->request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
err = _controller->GetRootHubDeviceDescriptor((IOUSBDeviceDescriptor*)request->pData);
request->wLenDone = sizeof(IOUSBDeviceDescriptor);
break;
}
case kUSBConfDesc:
{
OSData *fullDesc = OSData::withCapacity(1024);
UInt16 newLength;
err = _controller->GetRootHubConfDescriptor(fullDesc);
if ( (err == kIOReturnSuccess) && (fullDesc->getLength() > 0) )
{
newLength = fullDesc->getLength();
if (newLength < request->wLength)
request->wLength = newLength;
bcopy(fullDesc->getBytesNoCopy(), (char *)request->pData, request->wLength);
request->wLenDone = request->wLength;
}
fullDesc->release();
break;
}
case kUSBBOSDescriptor:
{
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _controller);
err = kIOReturnUnsupported;
if ( v3Bus )
{
OSData *fullDesc = OSData::withCapacity(1024);
UInt16 newLength;
err = v3Bus->GetRootHubBOSDescriptor(fullDesc);
if ( (err == kIOReturnSuccess) && (fullDesc->getLength() > 0) )
{
newLength = fullDesc->getLength();
if (newLength < request->wLength)
request->wLength = newLength;
bcopy(fullDesc->getBytesNoCopy(), (char *)request->pData, request->wLength);
request->wLenDone = request->wLength;
}
else
{
request->wLenDone = 0;
}
fullDesc->release();
}
break;
}
case kUSBStringDesc:
{
OSData *fullDesc = OSData::withCapacity(1024);
UInt16 newLength;
unsigned int offset = 0;
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
RHCommandHeader command;
command.request = 0;
command.request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
offset = sizeof(UInt32);
fullDesc->appendBytes(&command, offset);
}
err = _controller->GetRootHubStringDescriptor((request->wValue & 0x00ff), fullDesc);
if ( (err == kIOReturnSuccess) && (fullDesc->getLength() > 0) )
{
newLength = fullDesc->getLength() - offset;
if (newLength < request->wLength)
request->wLength = newLength;
bcopy(fullDesc->getBytesNoCopy(offset,request->wLength), (char *)request->pData, request->wLength);
request->wLenDone = request->wLength;
}
fullDesc->release();
break;
}
default:
err = kIOReturnBadArgument;
}
break;
case kGetDeviceStatus:
if ((request->wValue == 0) && (request->wIndex == 0) && (request->pData != 0))
{
*(UInt16*)(request->pData) = HostToUSBWord(1); request->wLenDone = 2;
}
else
err = kIOReturnBadArgument;
break;
case kSetAddress:
if (request->wIndex == 0)
err = _controller->SetHubAddress(request->wValue);
else
err = kIOReturnBadArgument;
break;
case kSetConfiguration:
if (request->wIndex == 0)
configuration = request->wValue;
else
err = kIOReturnBadArgument;
break;
case kSetDeviceFeature:
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
USBLog(5, "IOUSBRootHubDevice[%p]::DeviceRequestWorker kSetDeviceFeature unimplemented for SS RH for speed: %d ", this, _speed);
RHCommandHeader command;
command.request = 0;
command.request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
if (request->wIndex == 0)
err = _controller->SetRootHubFeature(request->wValue);
else
err = kIOReturnBadArgument;
break;
case kGetConfiguration:
if ((request->wIndex == 0) && (request->pData != 0))
{
*(UInt8*)(request->pData) = configuration;
request->wLenDone = 1;
}
else
err = kIOReturnBadArgument;
break;
case kClearInterfaceFeature:
case kClearEndpointFeature:
case kGetInterface:
case kGetInterfaceStatus:
case kGetEndpointStatus:
case kSetInterfaceFeature:
case kSetEndpointFeature:
case kSetDescriptor:
case kSetInterface:
case kSyncFrame:
err = kIOReturnUnsupported;
break;
case kClearHubFeature:
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
USBLog(5, "IOUSBRootHubDevice[%p]::DeviceRequestWorker kClearHubFeature unimplemented for SS RH for speed: %d ", this, _speed);
RHCommandHeader command;
command.request = 0;
command.request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
if (request->wIndex == 0)
err = _controller->ClearRootHubFeature(request->wValue);
else
err = kIOReturnBadArgument;
break;
case kClearPortFeature:
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
request->wValue <<= 8;
request->wValue |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
err = _controller->ClearRootHubPortFeature(request->wValue, request->wIndex);
break;
case kGetPortState:
if ((request->wValue == 0) && (request->pData != 0))
err = _controller->GetRootHubPortState((UInt8 *)request->pData, request->wIndex);
else
err = kIOReturnBadArgument;
break;
case kGetHubDescriptor:
{
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _controller);
if ( (request->wValue == ((kUSBHubDescriptorType << 8) + 0)) && (request->pData != 0))
{
err = _controller->GetRootHubDescriptor((IOUSBHubDescriptor *)request->pData);
request->wLenDone = sizeof(IOUSBHubDescriptor);
}
else if ( v3Bus && (request->wValue == ((kUSB3HubDescriptorType << 8) + 0)) && (request->pData != 0))
{
err = v3Bus->GetRootHub3Descriptor((IOUSB3HubDescriptor *)request->pData);
request->wLenDone = sizeof(IOUSB3HubDescriptor);
}
else
err = kIOReturnBadArgument;
}
break;
case kGetHubStatus:
if ((request->wValue == 0) && (request->wIndex == 0) && (request->pData != 0))
{
err = _controller->GetRootHubStatus((IOUSBHubStatus *)request->pData);
request->wLenDone = sizeof(IOUSBHubStatus);
}
else
err = kIOReturnBadArgument;
break;
case kGetPortStatus:
if ((request->wValue == 0) && (request->pData != 0))
{
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
RHCommandHeaderPtr command = (RHCommandHeaderPtr)request->pData;
command->request = 0;
command->request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
err = _controller->GetRootHubPortStatus((IOUSBHubPortStatus *)request->pData, request->wIndex);
request->wLenDone = sizeof(IOUSBHubPortStatus);
}
else
err = kIOReturnBadArgument;
break;
case kSetHubDescriptor:
if (request->pData != 0)
err = _controller->SetRootHubDescriptor((OSData *)request->pData);
else
err = kIOReturnBadArgument;
break;
case kSetHubFeature:
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
USBLog(5, "IOUSBRootHubDevice[%p]::DeviceRequestWorker kSetHubFeature unimplemented for SS RH for speed: %d ", this, _speed);
RHCommandHeader command;
command.request = 0;
command.request |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
if (request->wIndex == 0)
err = _controller->SetRootHubFeature(request->wValue);
else
err = kIOReturnBadArgument;
break;
case kSetPortFeature:
if(_MYCONTROLLERSPEED == kUSBDeviceSpeedSuper)
{
request->wValue <<= 8;
request->wValue |= (_speed << kUSBSpeed_Shift) & kUSBSpeed_Mask;
}
err = _controller->SetRootHubPortFeature(request->wValue, request->wIndex);
break;
case kSetHubDepth:
USBLog(1, "%s[%p]::DeviceRequestWorker unimplemented kSetHubDepth", getName(), this);
break;
case kGetPortErrorCount:
{
IOUSBControllerV3 *v3Bus = OSDynamicCast(IOUSBControllerV3, _controller);
if ( v3Bus)
{
if (request->wValue == 0 && request->wLength == 2)
err = v3Bus->GetRootHubPortErrorCount(request->wIndex, (UInt16 *)request->pData);
else
err = kIOReturnBadArgument;
}
else
err = kIOReturnBadArgument;
break;
}
default:
USBLog(3, "%s[%p]::DeviceRequestWorker unimplemented request 0x%x", getName(), this, theRequest);
err = kIOReturnBadArgument;
}
return(err);
}
bool
IOUSBRootHubDevice::IsRootHub(void)
{
return true;
}
#pragma mark Extra Power APIs
UInt32
IOUSBRootHubDevice::RequestExtraPower(UInt32 type, UInt32 requestedPower)
{
UInt32 returnValue = 0;
bool retry = false;
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::RequestExtraPower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return 0;
}
USBLog(5, "%s[%p]::RequestExtraPower type: %d, requested %d, inGate: %d", getName(), this, (uint32_t)type, (uint32_t) requestedPower, IOUSBDevice::_expansionData->_workLoop->inGate());
if ( type == kUSBPowerDuringWake || type == kUSBPowerDuringWakeRevocable || type == kUSBPowerDuringWakeUSB3)
{
returnValue = RequestExtraWakePower( type, requestedPower, &retry );
if ( retry && (returnValue == 0) )
{
AbsoluteTime deadline;
IOReturn err;
UInt32 flag = 0;
SendExtraPowerMessage( kUSBPowerRequestWakeRelease, requestedPower );
if ( IOUSBDevice::_expansionData->_workLoop->inGate())
{
clock_interval_to_deadline(100, kMillisecondScale, &deadline);
USBLog(5, "%s[%p]::RequestExtraPower we didn't get our %d, but were told to retry. calling commandSleep for 100ms, and then retrying", getName(), this, (uint32_t) requestedPower);
err = _commandGate->commandSleep(&flag, deadline, THREAD_ABORTSAFE);
if (err != THREAD_TIMED_OUT)
{
USBLog(3, "%s[%p]::RequestExtraPower commandSleep woke up with a 0x%x", getName(), this, (uint32_t) err);
}
}
else
{
USBLog(5, "%s[%p]::RequestExtraPower we didn't get our %d, but were told to retry. Sleeping 100ms and trying again", getName(), this, (uint32_t) requestedPower);
IOSleep(100);
}
retry = false;
returnValue = RequestExtraWakePower( type, requestedPower, &retry );
SendExtraPowerMessage( kUSBPowerRequestWakeReallocate, requestedPower );
}
}
else if ( type == kUSBPowerDuringSleep )
{
returnValue = RequestSleepPower( requestedPower );
}
else if ( type == kUSBPowerRequestWakeReallocate || type == kUSBPowerRequestSleepReallocate)
{
SendExtraPowerMessage( type, requestedPower );
}
return returnValue;
}
UInt32
IOUSBRootHubDevice::RequestExtraWakePower(UInt32 wakeType, UInt32 requestedPower, bool *retry)
{
OSNumber * numberObject = NULL;
UInt32 currentRequiredForUSB3Devices = 0;
UInt32 totalExtraCurrent = 0;
UInt32 totalRevocableExtraCurrent = 0;
UInt32 maxPowerPerPort = 0;
UInt32 extraAllocated = 0;
UInt32 unconnectedSSPorts = 0;
SInt32 adjustedUnconnectedPorts = 0;
OSObject * propertyObject = NULL;
IOService * resourceService = getResourceService();
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::RequestExtraWakePower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return 0;
}
IOLockLock(gExtraCurrentIOLockClass.lock);
if ( _expansionData == NULL)
{
USBLog(5, "%s[%p]::RequestExtraWakePower - _expansionData is NULL after locking", getName(), this);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return 0;
}
propertyObject = resourceService->copyProperty(kAppleCurrentExtra);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
totalExtraCurrent = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::RequestExtraWakePower - we have a kAppleCurrentExtra with %d", getName(), this, (uint32_t) totalExtraCurrent);
}
OSSafeReleaseNULL(propertyObject);
propertyObject = resourceService->copyProperty(kAppleMaxPortCurrent);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
maxPowerPerPort = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::RequestExtraWakePower - we have a kAppleMaxPortCurrent with %d", getName(), this, (uint32_t) maxPowerPerPort);
}
OSSafeReleaseNULL(propertyObject);
propertyObject = resourceService->copyProperty(kAppleRevocableExtraCurrent);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
totalRevocableExtraCurrent = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::RequestExtraWakePower - we have a totalRevocableExtraCurrent with %d", getName(), this, (uint32_t) totalRevocableExtraCurrent);
}
OSSafeReleaseNULL(propertyObject);
unconnectedSSPorts = UpdateUnconnectedExternalPorts(0);
adjustedUnconnectedPorts = unconnectedSSPorts - IOUSBController::gExternalNonSSPortsUsingExtraCurrent;
if (adjustedUnconnectedPorts < 0)
adjustedUnconnectedPorts = 0;
currentRequiredForUSB3Devices = (kUSB3MaxPowerPerPort - kUSB2MaxPowerPerPort) * adjustedUnconnectedPorts;
USBLog(5, "%s[%p]::RequestExtraWakePower type: %s - requestedPower = %d, available: %d, unconnected external SS ports: %d, external NonSS ports using extra: %d, thus we need to have %d for possible SS ports", getName(), this, wakeType == kUSBPowerDuringWake ? "kUSBPowerDuringWake" : (wakeType == kUSBPowerDuringWakeRevocable ? "kUSBPowerDuringWakeRevocable" : "kUSBPowerDuringWakeUSB3"), (uint32_t)requestedPower, (uint32_t) totalExtraCurrent, (uint32_t)unconnectedSSPorts, (uint32_t)IOUSBController::gExternalNonSSPortsUsingExtraCurrent, (uint32_t)currentRequiredForUSB3Devices);
if (requestedPower > (maxPowerPerPort-kUSB2MaxPowerPerPort)) {
USBLog(5, "%s[%p]::RequestExtraWakePower - requestedPower = %d was greater than the maximum per port of %d. Using that value instead", getName(), this, (uint32_t)requestedPower, (uint32_t) (maxPowerPerPort-kUSB2MaxPowerPerPort));
requestedPower = maxPowerPerPort-kUSB2MaxPowerPerPort;
}
if (requestedPower <= totalExtraCurrent)
{
bool allocate = true;
if (wakeType == kUSBPowerDuringWake)
{
if ( (totalExtraCurrent + totalRevocableExtraCurrent - requestedPower) < currentRequiredForUSB3Devices)
{
USBLog(5, "%s[%p]::RequestExtraWakePower - requestedPower = %d, we have %d extra, %d revocable, but need to have %d for USB3 devices, so we can't allocate it ", getName(), this, (uint32_t)requestedPower, (uint32_t)totalExtraCurrent, (uint32_t)totalRevocableExtraCurrent, (uint32_t)currentRequiredForUSB3Devices);
allocate = false;
*retry = false;
}
}
if ( allocate )
{
extraAllocated = requestedPower;
totalExtraCurrent -= extraAllocated;
USBLog(5, "%s[%p]::RequestExtraWakePower - setting kAppleCurrentExtra to %d", getName(), this, (uint32_t) totalExtraCurrent);
resourceService->setProperty(kAppleCurrentExtra, totalExtraCurrent, 32);
if (wakeType == kUSBPowerDuringWakeRevocable)
{
totalRevocableExtraCurrent += requestedPower;
USBLog(5, "%s[%p]::RequestExtraWakePower - setting kAppleRevocableExtraCurrent to %d", getName(), this, (uint32_t) totalRevocableExtraCurrent);
resourceService->setProperty(kAppleRevocableExtraCurrent, totalRevocableExtraCurrent, 32);
}
}
}
else
{
if ( (wakeType != kUSBPowerDuringWakeRevocable) && (requestedPower <= (totalExtraCurrent + totalRevocableExtraCurrent)) )
{
*retry = true;
}
}
USBLog(5, "%s[%p]::RequestExtraWakePower - extraAllocated = %d, retry = %d", getName(), this, (uint32_t)extraAllocated, *retry);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return extraAllocated;
}
IOReturn
IOUSBRootHubDevice::ReturnExtraPower(UInt32 type, UInt32 returnedPower)
{
IOReturn kr = kIOReturnSuccess;
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::ReturnExtraPower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return 0;
}
USBLog(5, "%s[%p]::ReturnExtraPower type: %d, returnedPower %d", getName(), this, (uint32_t)type, (uint32_t) returnedPower);
if ( type == kUSBPowerDuringWake || type == kUSBPowerDuringWakeRevocable || type == kUSBPowerDuringWakeUSB3)
{
ReturnExtraWakePower(type, returnedPower);
}
else if ( type == kUSBPowerDuringSleep )
{
ReturnSleepPower( returnedPower );
}
else if ( type == kUSBPowerRequestWakeRelease || type == kUSBPowerRequestSleepRelease )
{
SendExtraPowerMessage( type, returnedPower );
}
else
kr = kIOReturnBadArgument;
return kr;
}
void
IOUSBRootHubDevice::ReturnExtraWakePower(UInt32 wakeType, UInt32 returnedPower)
{
OSNumber * numberObject = NULL;
OSObject * propertyObject = NULL;
UInt32 totalExtraCurrent = 0;
UInt32 totalRevocableExtraCurrent = 0;
UInt32 unconnectedSSPorts = 0;
IOService * resourceService = getResourceService();
USBLog(5, "%s[%p]::ReturnExtraPower - returning = %d", getName(), this, (uint32_t)returnedPower);
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::ReturnExtraPower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return;
}
IOLockLock(gExtraCurrentIOLockClass.lock);
if (_expansionData == NULL)
{
USBLog(5, "%s[%p]::ReturnExtraPower - _expansionData is NULL after locking", getName(), this);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return;
}
unconnectedSSPorts = UpdateUnconnectedExternalPorts(0);
propertyObject = resourceService->copyProperty(kAppleCurrentExtra);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
totalExtraCurrent = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::ReturnExtraPower - we have a kAppleCurrentExtra with %d", getName(), this, (uint32_t) totalExtraCurrent);
}
OSSafeReleaseNULL(propertyObject);
propertyObject = resourceService->copyProperty(kAppleRevocableExtraCurrent);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
totalRevocableExtraCurrent = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::ReturnExtraPower - we have a totalRevocableExtraCurrent with %d", getName(), this, (uint32_t) totalRevocableExtraCurrent);
}
OSSafeReleaseNULL(propertyObject);
if (returnedPower > 0)
{
totalExtraCurrent += returnedPower;
USBLog(5, "%s[%p]::ReturnExtraPower - setting kAppleCurrentExtra to %d", getName(), this, (uint32_t) totalExtraCurrent);
resourceService->setProperty(kAppleCurrentExtra, totalExtraCurrent, 32);
if (wakeType == kUSBPowerDuringWakeRevocable)
{
totalRevocableExtraCurrent -= returnedPower;
USBLog(5, "%s[%p]::ReturnExtraPower - setting kAppleRevocableExtraCurrent to %d", getName(), this, (uint32_t) totalRevocableExtraCurrent);
resourceService->setProperty(kAppleRevocableExtraCurrent, totalRevocableExtraCurrent, 32);
}
}
USBLog(5, "%s[%p]::ReturnExtraWakePower type: %s - returnedPower = %d, new available: %d, unconnected external SS ports: %d, thus we need to have %d for them", getName(), this, wakeType == kUSBPowerDuringWake ? "kUSBPowerDuringWake" : (wakeType == kUSBPowerDuringWakeRevocable ? "kUSBPowerDuringWakeRevocable" : "kUSBPowerDuringWakeUSB3"), (uint32_t)returnedPower, (uint32_t) totalExtraCurrent, (uint32_t)unconnectedSSPorts, (uint32_t)(400*unconnectedSSPorts));
IOLockUnlock(gExtraCurrentIOLockClass.lock);
}
void
IOUSBRootHubDevice::InitializeExtraPower(UInt32 maxPortCurrent, UInt32 totalExtraCurrent)
{
#pragma unused (maxPortCurrent, totalExtraCurrent)
USBLog(1, "%s[%p]::InitializeExtraPower - Obsolete method called", getName(), this);
}
void
IOUSBRootHubDevice::SetSleepCurrent(UInt32 sleepCurrent)
{
USBLog(5, "%s[%p]::SetSleepCurrent - %d", getName(), this, (uint32_t)sleepCurrent);
super::SetSleepCurrent(sleepCurrent);
}
UInt32
IOUSBRootHubDevice::GetSleepCurrent()
{
return super::GetSleepCurrent();
}
UInt32
IOUSBRootHubDevice::RequestSleepPower(UInt32 requestedPower)
{
OSNumber * numberObject = NULL;
UInt32 totalExtraSleepCurrent = 0;
UInt32 maxSleepCurrentPerPort = 0;
UInt32 extraAllocated = 0; OSObject * propertyObject = NULL;
IOService * resourceService = getResourceService();
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::RequestSleepPower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return 0;
}
if (requestedPower == 0)
{
USBLog(5, "%s[%p]::RequestSleepPower - asked for 0, returning 0", getName(), this);
return 0;
}
if ( _STANDARD_PORT_POWER_IN_SLEEP == 0)
{
USBLog(5, "%s[%p]::RequestSleepPower - port does not have any _STANDARD_PORT_POWER_IN_SLEEP, returning 0", getName(), this );
return 0;
}
if ( requestedPower <= _STANDARD_PORT_POWER_IN_SLEEP)
{
USBLog(5, "%s[%p]::RequestSleepPower - requested <= _STANDARD_PORT_POWER_IN_SLEEP, returning %d", getName(), this, (uint32_t)requestedPower );
return requestedPower;
}
IOLockLock(gExtraCurrentIOLockClass.lock);
if (_expansionData == NULL)
{
USBLog(5, "%s[%p]::RequestSleepPower - _expansionData is NULL after locking", getName(), this);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return 0;
}
propertyObject = resourceService->copyProperty(kAppleCurrentExtraInSleep);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
totalExtraSleepCurrent = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::RequestSleepPower - we have a kAppleCurrentExtraInSleep with %d", getName(), this, (uint32_t) totalExtraSleepCurrent);
}
OSSafeReleaseNULL(propertyObject);
propertyObject = resourceService->copyProperty(kAppleMaxPortCurrentInSleep);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
maxSleepCurrentPerPort = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::RequestSleepPower - we have a kAppleMaxPortCurrentInSleep with %d", getName(), this, (uint32_t) maxSleepCurrentPerPort);
}
OSSafeReleaseNULL(propertyObject);
USBLog(5, "%s[%p]::RequestSleepPower - extra requestedPower = %d, available: %d", getName(), this, (uint32_t) (requestedPower-_STANDARD_PORT_POWER_IN_SLEEP), (uint32_t) totalExtraSleepCurrent);
if (requestedPower > maxSleepCurrentPerPort) {
USBLog(5, "%s[%p]::RequestSleepPower - requestedPower = %d was greater than the maximum per port of %d. Using that value instead", getName(), this, (uint32_t)requestedPower, (uint32_t) maxSleepCurrentPerPort);
requestedPower = maxSleepCurrentPerPort;
}
if ((requestedPower-_STANDARD_PORT_POWER_IN_SLEEP) <= totalExtraSleepCurrent)
{
extraAllocated = (requestedPower-_STANDARD_PORT_POWER_IN_SLEEP);
totalExtraSleepCurrent -= extraAllocated;
USBLog(5, "%s[%p]::RequestSleepPower - updating kAppleCurrentExtraInSleep to %d", getName(), this, (uint32_t) totalExtraSleepCurrent);
resourceService->setProperty(kAppleCurrentExtraInSleep, totalExtraSleepCurrent, 32);
}
USBLog(5, "%s[%p]::RequestSleepPower - extraAllocated = %d", getName(), this, (uint32_t)extraAllocated);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return extraAllocated+_STANDARD_PORT_POWER_IN_SLEEP;
}
void
IOUSBRootHubDevice::ReturnSleepPower(UInt32 returnedPower)
{
OSNumber * numberObject = NULL;
OSObject * propertyObject = NULL;
UInt32 powerAvailable = 0;
IOService * resourceService = getResourceService();
if ( (_expansionData == NULL) || (_PROVIDESEXTRACURRENT == false) )
{
USBLog(5, "%s[%p]::ReturnSleepPower - _expansionData is NULL or _PROVIDESEXTRACURRENT is false", getName(), this);
return;
}
USBLog(5, "%s[%p]::ReturnSleepPower - returning = %d", getName(), this, (uint32_t)returnedPower);
IOLockLock(gExtraCurrentIOLockClass.lock);
if (_expansionData == NULL)
{
USBLog(5, "%s[%p]::ReturnSleepPower - _expansionData is NULL after locking", getName(), this);
IOLockUnlock(gExtraCurrentIOLockClass.lock);
return;
}
propertyObject = resourceService->copyProperty(kAppleCurrentExtraInSleep);
numberObject = OSDynamicCast(OSNumber, propertyObject);
if (numberObject)
{
powerAvailable = numberObject->unsigned32BitValue();
USBLog(5, "%s[%p]::ReturnSleepPower - we have a kAppleCurrentExtraInSleep with %d", getName(), this, (uint32_t) powerAvailable);
}
OSSafeReleaseNULL(propertyObject);
if (returnedPower > _STANDARD_PORT_POWER_IN_SLEEP)
{
powerAvailable += (returnedPower-_STANDARD_PORT_POWER_IN_SLEEP);
USBLog(5, "%s[%p]::ReturnSleepPower - setting kAppleCurrentExtraInSleep to %d", getName(), this, (uint32_t) powerAvailable);
resourceService->setProperty(kAppleCurrentExtraInSleep, powerAvailable, 32);
}
IOLockUnlock(gExtraCurrentIOLockClass.lock);
}
IOReturn
IOUSBRootHubDevice::GetDeviceInformation(UInt32 *info)
{
*info = 0;
if ( _expansionData == NULL )
{
USBLog(5, "%s[%p]::GetDeviceInformation - _expansionData is NULL", getName(), this);
return kIOReturnNoDevice;
}
*info =(( 1 << kUSBInformationDeviceIsCaptiveBit ) |
( 1 << kUSBInformationDeviceIsInternalBit ) |
( 1 << kUSBInformationDeviceIsConnectedBit ) |
( 1 << kUSBInformationDeviceIsEnabledBit ) |
( 1 << kUSBInformationDeviceIsRootHub )
);
if (_HASBUILTINPROPERTY)
{
*info |= (1 << kUSBInformationRootHubisBuiltIn);
}
if (_HASTUNNELLEDPROPERTY)
{
*info |= (1 << kUSBInformationDeviceIsOnThunderboltBit);
}
USBLog(6, "IOUSBRootHubDevice[%p]::GetDeviceInformation returning 0x%x", this, (uint32_t)*info);
return kIOReturnSuccess;
}
void
IOUSBRootHubDevice::SendExtraPowerMessage(UInt32 type, UInt32 returnedPower)
{
OSIterator * rootHubDeviceiterator = NULL;
OSIterator * iterator = NULL;
OSObject * obj = NULL;
USBLog(6, "IOUSBRootHubDevice[%p]::SendExtraPowerMessage - type: 0x%x, argument: %d", this, (uint32_t)type, (uint32_t) returnedPower);
rootHubDeviceiterator = IOService::getMatchingServices(serviceMatching("IOUSBRootHubDevice"));
if ( rootHubDeviceiterator != NULL )
{
while ( (obj = rootHubDeviceiterator->getNextObject()) )
{
IOService * service = ( IOService * ) obj;
USBLog(7, "%s[%p]::SendExtraPowerMessage - found %s (%p)", getName(), this, service->getName(), service);
iterator = service->getParentEntry(gIOServicePlane)->getChildIterator(gIOServicePlane);
if ( !iterator )
{
USBLog(5, "%s[%p]::SendExtraPowerMessage - could not getChildIterator", getName(), this);
continue;
}
if (iterator)
{
OSObject *next;
while( (next = iterator->getNextObject()) )
{
IOUSBDevice *aDevice = OSDynamicCast(IOUSBDevice, next);
if ( aDevice )
{
if ( type == kUSBPowerRequestWakeRelease )
{
USBLog(7, "%s[%p]::SendExtraPowerMessage - sending kIOUSBMessageReleaseExtraCurrent to %s", getName(), this, aDevice->getName());
aDevice->messageClients(kIOUSBMessageReleaseExtraCurrent, &returnedPower, sizeof(UInt32));
}
else if ( type == kUSBPowerRequestWakeReallocate )
{
USBLog(7, "%s[%p]::SendExtraPowerMessage - sending kIOUSBMessageReallocateExtraCurrent to %s", getName(), this, aDevice->getName());
aDevice->messageClients(kIOUSBMessageReallocateExtraCurrent, NULL, 0);
}
}
}
iterator->release();
}
}
rootHubDeviceiterator->release();
}
else
{
USBLog(5, "%s[%p]::RequestExtraWakePower - Could not find any IOUSBRootHubDevice's", getName(), this);
}
}
OSMetaClassDefineReservedUsed(IOUSBRootHubDevice, 0);
OSMetaClassDefineReservedUsed(IOUSBRootHubDevice, 1);
OSMetaClassDefineReservedUsed(IOUSBRootHubDevice, 2);
OSMetaClassDefineReservedUsed(IOUSBRootHubDevice, 3);
OSMetaClassDefineReservedUsed(IOUSBRootHubDevice, 4);