/* * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ //================================================================================================ // // Headers // //================================================================================================ // #include //================================================================================================ // // Declare the AppleUSBComposite class so that bundles that instantiated it before the name // change will still work. We keep the same CFBundleIdentifier // //================================================================================================ // class AppleUSBComposite : public IOUSBCompositeDriver { OSDeclareDefaultStructors(AppleUSBComposite) }; OSDefineMetaClassAndStructors(AppleUSBComposite, IOUSBCompositeDriver) //================================================================================================ // // Local Definitions // //================================================================================================ // #define super IOService //================================================================================================ // // IOUSBCompositeDriver Methods // //================================================================================================ // OSDefineMetaClassAndStructors(IOUSBCompositeDriver, IOService) #pragma mark ееееееее IOService Methods еееееееее //============================================================================================= // // start // //============================================================================================= // bool IOUSBCompositeDriver::start(IOService * provider) { bool configured = false; if( !super::start(provider)) return (false); // Save a copy of our USB Device // fDevice = OSDynamicCast(IOUSBDevice, provider); if (!fDevice) return false; fExpectingClose = false; fNotifier = NULL; configured = ConfigureDevice(); if ( configured ) { // Create the general interest notifier so we get notifications of people attempting to open our device. We will only // close the device when we get a requestingClose message through our message method(). Note that we are registering // an interest on the fDevice, not on ourselves. We do this because that's who the open/close semantics are about, the IOUSBDevice // and not us, the driver. // 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; } //============================================================================================= // // message // //============================================================================================= // IOReturn IOUSBCompositeDriver::message( UInt32 type, IOService * provider, void * argument ) { IOReturn err = kIOReturnSuccess; err = super::message (type, provider, argument); switch ( type ) { case kIOUSBMessagePortHasBeenReset: // Should we do something here if we get an error? // USBLog(3, "%s[%p]::message - received kIOUSBMessagePortHasBeenReset",getName(), this); err = ReConfigureDevice(); break; case kIOMessageServiceIsRequestingClose: // Someone really wants us to close, so let's close our device: 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; } //============================================================================================= // // willTerminate // //============================================================================================= // bool IOUSBCompositeDriver::willTerminate( IOService * provider, IOOptionBits options ) { USBLog(6, "%s[%p]::willTerminate isInactive = %d", getName(), this, isInactive()); // Clean up our notifier. That will release it // if ( fNotifier ) fNotifier->remove(); return super::willTerminate(provider, options); } //============================================================================================= // // didTerminate // //============================================================================================= // bool IOUSBCompositeDriver::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) { USBLog(6, "%s[%p]::didTerminate isInactive = %d", getName(), this, isInactive()); // if we are still hanging on to the device, go ahead and close it if (fDevice->isOpen(this)) fDevice->close(this); return super::didTerminate(provider, options, defer); } #pragma mark ееееееее IOUSBCompositeDriver Methods еееееееее //============================================================================================= // // ConfigureDevice // //============================================================================================= // 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; // Find if we have a Preferred Configuration // prefConfig = (OSNumber *) getProperty("Preferred Configuration"); if ( prefConfig ) { prefConfigValue = prefConfig->unsigned32BitValue(); USBLog(3, "%s[%p](%s) found a preferred configuration (%d)", getName(), this, fDevice->getName(), prefConfigValue ); } // No preferred configuration so, find the first config/interface // 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) { // We have more than 1 configuration. Select the one with the highest power that is available in the port. This presumes // that such a configuration is more desirable. // for (i = 0; i < numberOfConfigs; i++) { cdTemp = fDevice->GetFullConfigurationDescriptor(i); if (!cdTemp) { USBLog(3,"%s[%p](%s) ConfigureDevice Config %d does not exist", getName(), this, fDevice->getName(), i); continue; } // Get the MaxPower for this configuration. If we have enough power for it AND it's greater than our previous power // then use this config 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, fDevice->GetBusPowerAvailable(), maxPower ); } } 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; fDevice->DisplayUserNotification(kUSBNotEnoughPowerNotificationType); goto ErrorExit; } } else { // set the configuration to the first config // cd = fDevice->GetFullConfigurationDescriptor(0); if (!cd) { USBLog(1, "%s[%p](%s) GetFullConfigDescriptor(0) returned NULL, retrying", getName(), this, fDevice->getName() ); 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; } } } // Open our device so that we can configure it // if ( !fDevice->open(this) ) { USBError(1, "%s[%p] Could not open device (%s)", getName(), this, fDevice->getName() ); err = kIOReturnExclusiveAccess; goto ErrorExit; } // Save our configuration value // fConfigValue = prefConfig ? prefConfigValue : cd->bConfigurationValue; // Now, configure it // 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 we tried a "Preferred Configuration" then attempt to set the configuration to the default one: // 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; } } // Set the remote wakeup feature if it's supported // 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 ) { // Wait and retry IOSleep(300); err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup); } } // If we have a property that tells us that we should suspend the port, do it now // suspendPropertyRef = OSDynamicCast( OSBoolean, fDevice->getProperty("kSuspendPort") ); 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 ); } } // Let's close the device since we're done configuring it // fExpectingClose = true; fDevice->close(this); return true; ErrorExit: USBLog(3, "%s[%p]::start aborting startup (0x%x)", getName(), this, err ); return false; } //============================================================================================= // // ReConfigureDevice // //============================================================================================= // IOReturn IOUSBCompositeDriver::ReConfigureDevice() { const IOUSBConfigurationDescriptor * cd = NULL; const IOUSBConfigurationDescriptor * cdTemp = NULL; IOReturn err = kIOReturnSuccess; IOUSBDevRequest request; UInt8 numberOfConfigs = 0; UInt32 i; OSBoolean * suspendPropertyRef; // Clear out the structure for the request // bzero( &request, sizeof(IOUSBDevRequest)); // if we're not opened, then we need to open the device before we // can reconfigure it. If that fails, then we need to seize the device and hope that // whoever has it will close it // if ( fDevice && !fDevice->isOpen(this) ) { // Let's attempt to open the device // if ( !fDevice->open(this) ) { // OK, since we can't open it, we give up. Note that we will not attempt to // seize it -- that's too much. If somebody has it open, then we shouldn't continue // with the reset. Such is the case with Classic: they open the device and do a DeviceReset // but they don't expect us to actually configure the device. // USBLog(3, "%s[%p]::ReConfigureDevice. Can't open it, giving up",getName(), this); err = kIOReturnExclusiveAccess; goto ErrorExit; } } // We have the device open, so now reconfigure it // Send the SET_CONFIG request on the bus, using the fConfigValue we used in ConfigureDevice // 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); } // Set the remote wakeup feature if it's supported // if (fConfigbmAttributes & kUSBAtrRemoteWakeup) { USBLog(3,"%s[%p]::ReConfigureDevice Setting kUSBFeatureDeviceRemoteWakeup for device: %s", getName(), this, fDevice->getName()); err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup); if ( err != kIOReturnSuccess ) { // Wait and retry IOSleep(300); err = fDevice->SetFeature(kUSBFeatureDeviceRemoteWakeup); } } // If we have a property that tells us that we should suspend the port, do it now // suspendPropertyRef = OSDynamicCast( OSBoolean, fDevice->getProperty("kSuspendPort") ); 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 ); } } ErrorExit: USBLog(3, "%s[%p]::ReConfigureDevice returned 0x%x",getName(),this, err); return err; } //============================================================================================= // // SetConfiguration // //============================================================================================= // IOReturn IOUSBCompositeDriver::SetConfiguration(UInt8 configValue, bool startInterfaceMatching) { // Call the device object to do the configuration // return fDevice->SetConfiguration(this, configValue, startInterfaceMatching); } #pragma mark ееееееее Static Methods еееееееее //============================================================================================= // // CompositeDriverInterestHandler // //============================================================================================= // IOReturn IOUSBCompositeDriver::CompositeDriverInterestHandler( void * target, void * refCon, UInt32 messageType, IOService * provider, void * messageArgument, vm_size_t argSize ) { IOUSBCompositeDriver * me = (IOUSBCompositeDriver *) target; if (!me) { return kIOReturnError; } switch ( messageType ) { case kIOMessageServiceIsAttemptingOpen: // The messagArgument for this message has the IOOptions passed in to the open() call that caused this message. If the options are // kIOServiceSeize, we now that someone really tried to open it. In the kernel, we will also get a message() call with a kIIOServiceRequestingClose // message, so we deal with closing the driver in that message. // USBLog(5, "CompositeDriverInterestHandler received kIOMessageServiceIsAttemptingOpen with argument: %d", (int) messageArgument ); break; case kIOMessageServiceWasClosed: USBLog(3, "CompositeDriverInterestHandler received kIOMessageServiceWasClosed (expecting close = %d)", me->fExpectingClose); me->fExpectingClose = false; break; case kIOMessageServiceIsTerminated: case kIOUSBMessagePortHasBeenReset: break; default: USBLog(5, "CompositeDriverInterestHandler message unknown: 0x%lx", messageType); } return kIOReturnSuccess; } #pragma mark ееееееее Padding Methods еееееееее OSMetaClassDefineReservedUnused(IOUSBCompositeDriver, 0); 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);