AppleUSBComposite.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOMessage.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBLog.h>
#include "AppleUSBComposite.h"
#include <IOKit/assert.h>
#define super IOService
OSDefineMetaClassAndStructors(AppleUSBComposite, IOService)
bool
AppleUSBComposite::start(IOService * provider)
{
bool configured = false;
if( !super::start(provider))
return (false);
_device = OSDynamicCast(IOUSBDevice, provider);
if(!_device)
return false;
_expectingClose = false;
_notifier = NULL;
configured = ConfigureDevice();
if ( configured )
{
_notifier = _device->registerInterest( gIOGeneralInterest, &AppleUSBComposite::CompositeDriverInterestHandler, this, NULL );
}
USBLog(5, "%s::start returning %d",getName(), configured);
return configured;
}
IOReturn
AppleUSBComposite::CompositeDriverInterestHandler( void * target, void * refCon, UInt32 messageType, IOService * provider,
void * messageArgument, vm_size_t argSize )
{
AppleUSBComposite * me = (AppleUSBComposite *) target;
if (!me)
{
return kIOReturnError;
}
switch ( messageType )
{
case kIOMessageServiceIsAttemptingOpen:
USBLog(5, "CompositeDriverInterestHandler received kIOMessageServiceIsAttemptingOpen with argument: %d", (int) messageArgument );
break;
case kIOMessageServiceWasClosed:
USBLog(3, "CompositeDriverInterestHandler received kIOMessageServiceWasClosed (expecting close = %d)", me->_expectingClose);
me->_expectingClose = false;
break;
case kIOMessageServiceIsTerminated:
case kIOUSBMessagePortHasBeenReset:
break;
default:
USBLog(5, "CompositeDriverInterestHandler message unknown: 0x%lx", messageType);
}
return kIOReturnSuccess;
}
bool
AppleUSBComposite::ConfigureDevice()
{
const IOUSBConfigurationDescriptor * cd = NULL;
const IOUSBConfigurationDescriptor * cdTemp = NULL;
IOReturn err = kIOReturnSuccess;
UInt8 prefConfigValue = 0;
OSNumber * prefConfig = NULL;
UInt8 i;
UInt8 maxPower = 0;
UInt8 numberOfConfigs = 0;
do {
USBLog(3,"%s[%p]: USB Generic Composite @ %d", getName(), this, _device->GetAddress());
prefConfig = (OSNumber *) getProperty("Preferred Configuration");
if ( prefConfig )
{
prefConfigValue = prefConfig->unsigned32BitValue();
USBLog(3, "%s[%p](%s) found a preferred configuration (%d)", getName(), this, _device->getName(), prefConfigValue );
}
numberOfConfigs = _device->GetNumConfigurations();
if ( numberOfConfigs < 1)
{
USBError(1, "%s[%p](%s) Could not get any configurations", getName(), this, _device->getName() );
err = kIOUSBConfigNotFound;
continue;
}
if (numberOfConfigs > 1)
{
for (i = 0; i < numberOfConfigs; i++)
{
cdTemp = _device->GetFullConfigurationDescriptor(i);
if (!cdTemp)
{
USBLog(3,"%s[%p](%s) ConfigureDevice Config %d does not exist", getName(), this, _device->getName(), i);
continue;
}
if( (_device->GetBusPowerAvailable() >= cdTemp->MaxPower) && (cdTemp->MaxPower > maxPower) )
{
USBLog(5,"%s[%p](%s) ConfigureDevice Config %d with MaxPower %d", getName(), this, _device->getName(), i, cdTemp->MaxPower );
cd = cdTemp;
maxPower = cdTemp->MaxPower;
}
else
{
USBLog(5,"%s[%p](%s) ConfigureDevice Config %d with MaxPower %d cannot be used (available: %d, previous %d)", getName(), this, _device->getName(), i, cdTemp->MaxPower, _device->GetBusPowerAvailable(), maxPower );
}
}
if ( !cd )
{
USBLog(3, "%s[%p](%s) ConfigureDevice failed to find configuration by power", getName(), this, _device->getName() );
err = kIOUSBNotEnoughPowerErr;
continue;
}
}
else
{
cd = _device->GetFullConfigurationDescriptor(0);
if (!cd)
{
USBLog(1, "%s[%p](%s) GetFullConfigDescriptor(0) returned NULL, retrying", getName(), this, _device->getName() );
IOSleep( 300 );
cd = _device->GetFullConfigurationDescriptor(0);
if ( !cd )
{
USBError(1, "%s[%p](%s) GetFullConfigDescriptor(0) returned NULL", getName(), this, _device->getName() );
err = kIOUSBConfigNotFound;
continue;
}
}
}
if (!_device->open(this))
{
USBError(1, "%s[%p](%s) Could not open device", getName(), this, _device->getName() );
err = kIOReturnExclusiveAccess;
break;
}
err = _device->SetConfiguration(this, (prefConfig ? prefConfigValue : cd->bConfigurationValue), true);
if (err)
{
USBError(1, "%s[%p](%s) SetConfiguration (%d) returned 0x%x", getName(), this, _device->getName(), (prefConfig ? prefConfigValue : cd->bConfigurationValue), err );
if ( prefConfig )
{
err = _device->SetConfiguration(this, cd->bConfigurationValue, true);
USBError(1, "%s[%p](%s) SetConfiguration (%d) returned 0x%x", getName(), this, _device->getName(), cd->bConfigurationValue, err );
}
if ( err )
{
_device->close(this);
break;
}
}
if (cd->bmAttributes & kUSBAtrRemoteWakeup)
{
USBLog(3,"%s[%p] Setting kUSBFeatureDeviceRemoteWakeup for device: %s", getName(), this, _device->getName());
_device->SetFeature(kUSBFeatureDeviceRemoteWakeup);
}
_expectingClose = true;
_device->close(this);
return true;
} while (false);
USBLog(3, "%s[%p] aborting startup (0x%x)", getName(), this, err );
return false;
}
IOReturn
AppleUSBComposite::ReConfigureDevice()
{
const IOUSBConfigurationDescriptor * cd = NULL;
const IOUSBConfigurationDescriptor * cdTemp = NULL;
IOReturn err = kIOReturnSuccess;
IOUSBDevRequest request;
UInt8 numberOfConfigs = 0;
UInt32 i;
UInt8 maxPower = 0;
bzero( &request, sizeof(IOUSBDevRequest));
if ( _device && !_device->isOpen(this) )
{
if ( !_device->open(this) )
{
USBLog(3, "%s[%p]::ReConfigureDevice. Can't open it, giving up",getName(), this);
err = kIOReturnExclusiveAccess;
goto ErrorExit;
}
}
numberOfConfigs = _device->GetNumConfigurations();
if (numberOfConfigs > 1)
{
for (i = 0; i < numberOfConfigs; i++)
{
cdTemp = _device->GetFullConfigurationDescriptor(i);
if (!cdTemp)
{
USBLog(3,"%s[%p](%s)::ReConfigureDevice Config %d does not exist", getName(), this, _device->getName(), i);
continue;
}
if( (_device->GetBusPowerAvailable() >= cdTemp->MaxPower) && (cdTemp->MaxPower > maxPower) )
{
USBLog(5,"%s[%p](%s)::ReConfigureDevice Config %d with MaxPower %d", getName(), this, _device->getName(), i, cdTemp->MaxPower );
cd = cdTemp;
maxPower = cdTemp->MaxPower;
}
else
{
USBLog(5,"%s[%p](%s)::ReConfigureDevice Config %d with MaxPower %d cannot be used (available: %d, previous %d)", getName(), this, _device->getName(), i, cdTemp->MaxPower, _device->GetBusPowerAvailable(), maxPower );
}
}
}
else
{
cd = _device->GetFullConfigurationDescriptor(0);
if (!cd)
{
USBLog(1, "%s[%p](%s)::ReConfigureDevice GetFullConfigDescriptor(0) returned NULL, retrying", getName(), this, _device->getName() );
IOSleep( 300 );
cd = _device->GetFullConfigurationDescriptor(0);
}
}
if ( !cd )
{
USBError(1, "%s[%p](%s)::ReConfigureDevice GetFullConfigDescriptor(0) returned NULL", getName(), this, _device->getName() );
err = kIOUSBConfigNotFound;
goto ErrorExit;
}
request.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBStandard, kUSBDevice);
request.bRequest = kUSBRqSetConfig;
request.wValue = cd->bConfigurationValue;
request.wIndex = 0;
request.wLength = 0;
request.pData = 0;
err = _device->DeviceRequest(&request, 5000, 0);
if (cd->bmAttributes & kUSBAtrRemoteWakeup)
{
USBLog(3,"%s[%p]::ReConfigureDevice Setting kUSBFeatureDeviceRemoteWakeup for device: %s", getName(), this, _device->getName());
_device->SetFeature(kUSBFeatureDeviceRemoteWakeup);
}
if (err)
{
USBLog(3, "%s[%p]::ReConfigureDevice. SET_CONFIG returned 0x%x",getName(), this, err);
}
ErrorExit:
USBLog(3, "%s[%p]::ReConfigureDevice returned 0x%x",getName(),this, err);
return err;
}
IOReturn
AppleUSBComposite::message( UInt32 type, IOService * provider, void * argument )
{
IOReturn err = kIOReturnSuccess;
err = super::message (type, provider, argument);
switch ( type )
{
case kIOUSBMessagePortHasBeenReset:
USBLog(3, "%s[%p]::message - received kIOUSBMessagePortHasBeenReset",getName(), this);
err = ReConfigureDevice();
break;
case kIOMessageServiceIsTerminated:
USBLog(5, "%s[%p]::message - received kIOMessageServiceIsTerminated",getName(), this);
break;
case kIOMessageServiceIsRequestingClose:
if ( _device && _device->isOpen(this) )
{
USBLog(3, "%s[%p]::message - Received kIOMessageServiceIsRequestingClose - closing device",getName(), this);
_expectingClose = true;
_device->close(this);
}
else
{
err = kIOReturnNotOpen;
}
break;
default:
break;
}
return err;
}
bool
AppleUSBComposite::willTerminate( IOService * provider, IOOptionBits options )
{
USBLog(6, "%s[%p]::willTerminate isInactive = %d", getName(), this, isInactive());
if ( _notifier )
_notifier->remove();
return super::willTerminate(provider, options);
}
bool
AppleUSBComposite::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
USBLog(6, "%s[%p]::didTerminate isInactive = %d", getName(), this, isInactive());
if (_device->isOpen(this))
_device->close(this);
return super::didTerminate(provider, options, defer);
}
#if 0
void
AppleUSBComposite::stop(IOService * provider)
{
USBLog(3, "%s[%p]::stop isInactive = %d", getName(), this, isInactive());
return(super::stop(provider));
}
bool
AppleUSBComposite::finalize(IOOptionBits options)
{
USBLog(3, "%s[%p]::finalize isInactive = %d", getName(), this, isInactive());
return(super::finalize(options));
}
bool
AppleUSBComposite::requestTerminate( IOService * provider, IOOptionBits options )
{
USBLog(3, "%s[%p]::requestTerminate isInactive = %d", getName(), this, isInactive());
return super::requestTerminate(provider, options);
}
bool
AppleUSBComposite::terminate( IOOptionBits options = 0 )
{
USBLog(3, "%s[%p]::terminate isInactive = %d", getName(), this, isInactive());
return super::terminate(options);
}
void
AppleUSBComposite::free( void )
{
super::free();
}
bool
AppleUSBComposite::terminateClient( IOService * client, IOOptionBits options )
{
USBLog(3, "%s[%p]::terminateClient isInactive = %d", getName(), this, isInactive());
return super::terminateClient(client, options);
}
#endif