IOUSBCompositeDriver.cpp [plain text]
#include <IOKit/usb/IOUSBCompositeDriver.h>
#include <IOKit/usb/IOUSBControllerV3.h>
#include "USBTracepoints.h"
class AppleUSBComposite : public IOUSBCompositeDriver
{
OSDeclareDefaultStructors(AppleUSBComposite)
};
OSDefineMetaClassAndStructors(AppleUSBComposite, IOUSBCompositeDriver)
#define super IOService
#ifndef IOUSBCOMPOSITEDRIVER_USE_KPRINTF
#define IOUSBCOMPOSITEDRIVER_USE_KPRINTF 0
#endif
#if IOUSBCOMPOSITEDRIVER_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= IOUSBCOMPOSITEDRIVER_USE_KPRINTF) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
OSDefineMetaClassAndStructors(IOUSBCompositeDriver, IOService)
#pragma mark ееееееее IOService Methods еееееееее
bool
IOUSBCompositeDriver::start(IOService * provider)
{
bool configured = false;
if ( !super::start(provider))
return (false);
fDevice = OSDynamicCast(IOUSBDevice, provider);
if (!fDevice)
return false;
fExpectingClose = false;
fNotifier = NULL;
if (ConfigureDevicePowerManagement(provider) != kIOReturnSuccess)
{
USBLog(1, "IOUSBCompositeDriver[%p]::start - ConfigureDevicePowerManagement failed", this);
return false;
}
configured = ConfigureDevice();
if ( configured )
{
fNotifier = fDevice->registerInterest( gIOGeneralInterest, &IOUSBCompositeDriver::CompositeDriverInterestHandler, this, NULL );
USBLog(3,"%s[%p]::start USB Generic Composite @ %d", getName(), this, fDevice->GetAddress());
}
USBLog(5, "%s[%p]::start returning %d", getName(), this, configured);
return configured;
}
bool
IOUSBCompositeDriver::init(OSDictionary * propTable)
{
if (!super::init(propTable)) return false;
if (!fIOUSBCompositeExpansionData)
{
fIOUSBCompositeExpansionData = (IOUSBCompositeDriverExpansionData *)IOMalloc(sizeof(fIOUSBCompositeExpansionData));
if (!fIOUSBCompositeExpansionData)
return false;
bzero(fIOUSBCompositeExpansionData, sizeof(fIOUSBCompositeExpansionData));
}
return true;
}
void
IOUSBCompositeDriver::free()
{
USBLog(6,"+IOUSBCompositeDriver[%p]::free", this);
if (fIOUSBCompositeExpansionData)
{
IOFree(fIOUSBCompositeExpansionData, sizeof(fIOUSBCompositeExpansionData));
fIOUSBCompositeExpansionData = NULL;
}
USBLog(6, "-IOUSBCompositeDriver[%p]::free", this);
super::free();
}
IOReturn
IOUSBCompositeDriver::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn err = kIOReturnSuccess;
err = super::message (type, provider, argument);
switch ( type )
{
case kIOUSBMessagePortHasBeenReset:
USBLog(5, "%s[%p]::message - received kIOUSBMessagePortHasBeenReset",getName(), this);
err = ReConfigureDevice();
break;
case kIOUSBMessageCompositeDriverReconfigured:
USBLog(5, "%s[%p]::message - received kIOUSBMessageCompositeDriverReconfigured",getName(), this);
break;
case kIOMessageServiceIsRequestingClose:
if ( fDevice && fDevice->isOpen(this) )
{
USBLog(3, "%s[%p]::message - Received kIOMessageServiceIsRequestingClose - closing device",getName(), this);
fExpectingClose = true;
fDevice->close(this);
}
else
{
err = kIOReturnNotOpen;
}
break;
default:
break;
}
return err;
}
bool
IOUSBCompositeDriver::willTerminate( IOService * provider, IOOptionBits options )
{
USBLog(6, "%s[%p]::willTerminate isInactive = %d", getName(), this, isInactive());
if ( fNotifier )
fNotifier->remove();
return super::willTerminate(provider, options);
}
bool
IOUSBCompositeDriver::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
USBLog(6, "%s[%p]::didTerminate isInactive = %d", getName(), this, isInactive());
if (fDevice->isOpen(this))
fDevice->close(this);
return super::didTerminate(provider, options, defer);
}
#pragma mark ееееееее IOUSBCompositeDriver Methods еееееееее
bool
IOUSBCompositeDriver::ConfigureDevice()
{
IOReturn err = kIOReturnSuccess;
UInt8 prefConfigValue = 0;
OSNumber * prefConfig = NULL;
const IOUSBConfigurationDescriptor * cd = NULL;
const IOUSBConfigurationDescriptor * cdTemp = NULL;
UInt8 i;
SInt16 maxPower = -1;
UInt8 numberOfConfigs = 0;
OSBoolean * suspendPropertyRef;
OSBoolean * expressCardCantWakeRef;
OSBoolean * lowPowerNotificationDisplayed;
bool issueRemoteWakeup = false;
prefConfig = (OSNumber *) getProperty(kUSBPreferredConfiguration);
if ( prefConfig )
{
prefConfigValue = prefConfig->unsigned32BitValue();
USBLog(3, "%s[%p](%s) found a preferred configuration (%d)", getName(), this, fDevice->getName(), prefConfigValue );
}
else
{
prefConfig = (OSNumber *) fDevice->getProperty(kUSBPreferredConfiguration);
if ( prefConfig )
{
prefConfigValue = prefConfig->unsigned32BitValue();
USBLog(3, "%s[%p](%s) found a preferred configuration (%d)", getName(), this, fDevice->getName(), prefConfigValue );
}
}
numberOfConfigs = fDevice->GetNumConfigurations();
if ( numberOfConfigs < 1)
{
USBError(1, "%s[%p](%s) Could not get any configurations", getName(), this, fDevice->getName() );
err = kIOUSBConfigNotFound;
goto ErrorExit;
}
if (numberOfConfigs > 1)
{
for (i = 0; i < numberOfConfigs; i++)
{
cdTemp = fDevice->GetFullConfigurationDescriptor(i);
if (!cdTemp)
{
USBLog(1, "%s[%p](%s)::ConfigureDevice GetFullConfigDescriptor(%d) returned NULL, retrying", getName(), this, fDevice->getName(), i );
USBTrace( kUSBTCompositeDriver, kTPCompositeDriverConfigureDevice , (uintptr_t)this, i, 0, 1 );
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(fDevice->GetBus()->getWorkLoop()->inGate()){USBLog(1, "%s[%p](%s)::ConfigureDevice GetFullConfigDescriptor - IOSleep in gate:%d", getName(), this, fDevice->getName(), 1);}}
#endif
IOSleep( 300 );
cdTemp = fDevice->GetFullConfigurationDescriptor(i);
if ( !cdTemp )
{
USBError(1, "%s[%p](%s)::ConfigureDevice GetFullConfigDescriptor(%d) returned NULL", getName(), this, fDevice->getName(), i );
err = kIOUSBConfigNotFound;
goto ErrorExit;
}
}
if ( (fDevice->GetBusPowerAvailable() >= cdTemp->MaxPower) && ( ((SInt16)cdTemp->MaxPower) > maxPower) )
{
USBLog(5,"%s[%p](%s) ConfigureDevice Config %d with MaxPower %d", getName(), this, fDevice->getName(), i, cdTemp->MaxPower );
cd = cdTemp;
maxPower = (SInt16) cdTemp->MaxPower;
}
else
{
USBLog(5,"%s[%p](%s) ConfigureDevice Config %d with MaxPower %d cannot be used (available: %d, previous %d)", getName(), this, fDevice->getName(), i, cdTemp->MaxPower, (uint32_t)fDevice->GetBusPowerAvailable(), maxPower );
fDevice->setProperty("Failed Requested Power", cdTemp->MaxPower, 32);
}
}
if ( !cd )
{
USBError(1,"USB Low Power Notice: The device \"%s\" cannot be used because there is not enough power to configure it",fDevice->getName());
USBLog(3, "%s[%p](%s) ConfigureDevice failed to find configuration by power", getName(), this, fDevice->getName() );
err = kIOUSBNotEnoughPowerErr;
lowPowerNotificationDisplayed = OSDynamicCast( OSBoolean, fDevice->getProperty("Low Power Displayed") );
if ( !lowPowerNotificationDisplayed or (lowPowerNotificationDisplayed && lowPowerNotificationDisplayed->isFalse()) )
{
bool display = true;
fDevice->DisplayUserNotification(kUSBNotEnoughPowerNotificationType);
fDevice->setProperty("Low Power Displayed", display);
}
goto ErrorExit;
}
}
else
{
cd = fDevice->GetFullConfigurationDescriptor(0);
if (!cd)
{
USBLog(1, "%s[%p](%s) GetFullConfigDescriptor(0) returned NULL, retrying", getName(), this, fDevice->getName() );
USBTrace( kUSBTCompositeDriver, kTPCompositeDriverConfigureDevice , (uintptr_t)this, 0, 0, 2 );
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(fDevice->GetBus()->getWorkLoop()->inGate()){USBLog(1, "%s[%p](%s)::ConfigureDevice GetFullConfigDescriptor - IOSleep in gate:%d", getName(), this, fDevice->getName(), 1);}}
#endif
IOSleep( 300 );
cd = fDevice->GetFullConfigurationDescriptor(0);
if ( !cd )
{
USBError(1, "%s[%p](%s) GetFullConfigDescriptor(0) returned NULL", getName(), this, fDevice->getName() );
err = kIOUSBConfigNotFound;
goto ErrorExit;
}
}
}
if ( !fDevice->open(this) )
{
USBError(1, "%s[%p] Could not open device (%s)", getName(), this, fDevice->getName() );
err = kIOReturnExclusiveAccess;
goto ErrorExit;
}
fConfigValue = prefConfig ? prefConfigValue : cd->bConfigurationValue;
fConfigbmAttributes = cd->bmAttributes;
if (fConfigbmAttributes & kUSBAtrRemoteWakeup)
{
fIOUSBCompositeExpansionData->fIssueRemoteWakeup = true;
}
#if 0
{
IOUSBControllerV3 *bus = OSDynamicCast(IOUSBControllerV3, fDevice->GetBus());
if (bus)
{
UInt32 bandwidth;
bus->GetBandwidthAvailableForDevice(fDevice, &bandwidth);
USBLog(2, "Composite Driver(%s): Bandwidth for device is %d", fDevice->getName(), (int)bandwidth);
}
}
#endif
err = SetConfiguration(fConfigValue, true);
if (err)
{
USBError(1, "%s[%p](%s) SetConfiguration (%d) returned 0x%x", getName(), this, fDevice->getName(), (prefConfig ? prefConfigValue : cd->bConfigurationValue), err );
if ( prefConfig )
{
fConfigValue = cd->bConfigurationValue;
err = SetConfiguration(fConfigValue, true);
USBError(1, "%s[%p](%s) SetConfiguration (%d) returned 0x%x", getName(), this, fDevice->getName(), cd->bConfigurationValue, err );
}
if ( err )
{
fDevice->close(this);
goto ErrorExit;
}
}
if (!fIOUSBCompositeExpansionData->fRemoteWakeupIssued)
{
fConfigbmAttributes = cd->bmAttributes;
if (fConfigbmAttributes & kUSBAtrRemoteWakeup)
{
USBLog(3,"%s[%p] Setting kUSBFeatureDeviceRemoteWakeup for device: %s", getName(), this, fDevice->getName());
err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup);
if ( err != kIOReturnSuccess )
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(fDevice->GetBus()->getWorkLoop()->inGate()){USBLog(1, "%s[%p](%s)::SetConfiguration - IOSleep in gate:%d", getName(), this, fDevice->getName(), 1);}}
#endif
IOSleep(300);
err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup);
}
}
}
expressCardCantWakeRef = OSDynamicCast( OSBoolean, fDevice->getProperty(kUSBExpressCardCantWake) );
if ( expressCardCantWakeRef && expressCardCantWakeRef->isTrue() )
{
USBLog(3, "%s[%p](%s) found an express card device which will disconnect across sleep", getName(), this, fDevice->getName() );
fDevice->GetBus()->retain();
fDevice->GetBus()->message(kIOUSBMessageExpressCardCantWake, this, fDevice);
fDevice->GetBus()->release();
}
suspendPropertyRef = OSDynamicCast( OSBoolean, fDevice->getProperty(kUSBSuspendPort) );
if ( suspendPropertyRef && suspendPropertyRef->isTrue() )
{
USBLog(3, "%s[%p](%s) Need to suspend the port", getName(), this, fDevice->getName() );
err = fDevice->SuspendDevice(true);
if ( err != kIOReturnSuccess )
{
USBLog(3, "%s[%p](%s) SuspendDevice returned 0x%x", getName(), this, fDevice->getName(), err );
}
}
fExpectingClose = true;
fDevice->close(this);
return true;
ErrorExit:
USBLog(3, "%s[%p]::start aborting startup (0x%x)", getName(), this, err );
return false;
}
IOReturn
IOUSBCompositeDriver::ReConfigureDevice()
{
const IOUSBConfigurationDescriptor * cd = NULL;
const IOUSBConfigurationDescriptor * cdTemp = NULL;
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
UInt8 numberOfConfigs = 0;
UInt32 i;
OSBoolean * suspendPropertyRef;
OSBoolean * expressCardCantWakeRef;
bzero( &request, sizeof(IOUSBDevRequest));
if ( fDevice && !fDevice->isOpen(this) )
{
if ( !fDevice->open(this) )
{
USBLog(3, "%s[%p]::ReConfigureDevice. Can't open it, giving up",getName(), this);
err = kIOReturnExclusiveAccess;
goto ErrorExit;
}
}
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqSetConfig;
request.wValue = fConfigValue;
request.wIndex = 0;
request.wLength = 0;
request.pData = 0;
err = fDevice->DeviceRequest(&request, 5000, 0);
if (err)
{
USBLog(3, "%s[%p]::ReConfigureDevice. SET_CONFIG returned 0x%x",getName(), this, err);
fDevice->close(this);
goto ErrorExit;
}
if (fConfigbmAttributes & kUSBAtrRemoteWakeup)
{
USBLog(3,"%s[%p]::ReConfigureDevice Setting kUSBFeatureDeviceRemoteWakeup for device: %s", getName(), this, fDevice->getName());
err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup);
if ( err != kIOReturnSuccess )
{
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
{if(fDevice->GetBus()->getWorkLoop()->inGate()){USBLog(1, "%s[%p](%s)::ReConfigureDevice - IOSleep in gate:%d", getName(), this, fDevice->getName(), 1);}}
#endif
IOSleep(300);
err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup);
}
}
expressCardCantWakeRef = OSDynamicCast( OSBoolean, fDevice->getProperty(kUSBExpressCardCantWake) );
if ( expressCardCantWakeRef && expressCardCantWakeRef->isTrue() )
{
USBLog(3, "%s[%p](%s) found an express card device which will disconnect across sleep", getName(), this, fDevice->getName() );
fDevice->GetBus()->retain();
fDevice->GetBus()->message(kIOUSBMessageExpressCardCantWake, this, fDevice);
fDevice->GetBus()->release();
}
suspendPropertyRef = OSDynamicCast( OSBoolean, fDevice->getProperty(kUSBSuspendPort) );
if ( suspendPropertyRef && suspendPropertyRef->isTrue() )
{
USBLog(3, "%s[%p](%s) Need to suspend the port", getName(), this, fDevice->getName() );
err = fDevice->SuspendDevice(true);
if ( err != kIOReturnSuccess )
{
USBLog(3, "%s[%p](%s) SuspendDevice returned 0x%x", getName(), this, fDevice->getName(), err );
}
}
fDevice->close(this);
fDevice->retain();
(void) fDevice->messageClients(kIOUSBMessageCompositeDriverReconfigured, NULL, 0);
fDevice->release();
ErrorExit:
USBLog(6, "%s[%p]::ReConfigureDevice returned 0x%x",getName(),this, err);
return err;
}
IOReturn
IOUSBCompositeDriver::SetConfiguration(UInt8 configValue, bool startInterfaceMatching)
{
IOReturn kr = kIOReturnSuccess;
if ( fIOUSBCompositeExpansionData && fIOUSBCompositeExpansionData->fIssueRemoteWakeup )
{
fIOUSBCompositeExpansionData->fRemoteWakeupIssued = true;
kr = fDevice->SetConfiguration(this, configValue, startInterfaceMatching, true);
if ( kr != kIOReturnSuccess)
{
USBLog(6, "%s[%p]::SetConfiguration returned 0x%x, resetting the device",getName(),this, kr);
kr = fDevice->ResetDevice();
USBLog(6, "%s[%p]::ResetDevice returned 0x%x",getName(),this, kr);
if ( kr == kIOReturnSuccess)
{
kr = fDevice->SetConfiguration(this, configValue, startInterfaceMatching, true);
USBLog(6, "%s[%p]::SetConfiguration returned 0x%x",getName(),this, kr);
}
}
}
else
{
fIOUSBCompositeExpansionData->fRemoteWakeupIssued = false;
kr = fDevice->SetConfiguration(this, configValue, startInterfaceMatching);
if ( kr != kIOReturnSuccess)
{
USBLog(6, "%s[%p]::SetConfiguration returned 0x%x, resetting the device",getName(),this, kr);
kr = fDevice->ResetDevice();
USBLog(6, "%s[%p]::ResetDevice returned 0x%x",getName(),this, kr);
if ( kr == kIOReturnSuccess)
{
kr = fDevice->SetConfiguration(this, configValue, startInterfaceMatching, true);
USBLog(6, "%s[%p]::SetConfiguration returned 0x%x",getName(),this, kr);
}
}
}
USBLog(6, "%s[%p]::SetConfiguration returning 0x%x",getName(),this, kr);
return kr;
}
#pragma mark ееееееее Static Methods еееееееее
IOReturn
IOUSBCompositeDriver::CompositeDriverInterestHandler( void * target, void * refCon, UInt32 messageType, IOService * provider,
void * messageArgument, vm_size_t argSize )
{
#pragma unused (provider, refCon, argSize)
IOUSBCompositeDriver * me = (IOUSBCompositeDriver *) target;
if (!me)
{
return kIOReturnError;
}
switch ( messageType )
{
case kIOMessageServiceIsAttemptingOpen:
USBLog(5, "CompositeDriverInterestHandler received kIOMessageServiceIsAttemptingOpen with argument: %p", messageArgument );
break;
case kIOMessageServiceWasClosed:
USBLog(5, "CompositeDriverInterestHandler received kIOMessageServiceWasClosed (expecting close = %d)", me->fExpectingClose);
me->fExpectingClose = false;
break;
case kIOMessageServiceIsTerminated:
case kIOUSBMessagePortHasBeenReset:
break;
default:
USBLog(5, "CompositeDriverInterestHandler message unknown: 0x%x", (uint32_t)messageType);
}
return kIOReturnSuccess;
}
OSMetaClassDefineReservedUsed(IOUSBCompositeDriver, 0);
IOReturn
IOUSBCompositeDriver::ConfigureDevicePowerManagement( IOService * provider )
{
#pragma unused(provider)
return kIOReturnSuccess;
}
#pragma mark ееееееее Padding Methods еееееееее
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 1);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 2);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 3);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 4);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 5);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 6);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 7);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 8);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 9);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 10);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 11);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 12);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 13);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 14);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 15);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 16);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 17);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 18);
OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 19);