AppleUSBAudioDevice.cpp [plain text]
//--------------------------------------------------------------------------------
//
//	File:		AppleUSBAudioDevice.cpp
//
//	Contains:	Support for the USB Audio Class Control Interface.
//			This includes support for exporting device controls
//			to the Audio HAL such as Volume, Bass, Treble and
//			Mute.
//
//			Future support will include parsing of the device
//			topology and exporting of all appropriate device
//			control functions through the Audio HAL.
//
//	Technology:	OS X
//
//--------------------------------------------------------------------------------

#include "AppleUSBAudioCommon.h"
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioMuteControl.h"
#include "USBAudioObject.h"
#include "AppleUSBAudioEngine.h"

#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IORegistryEntry.h>
#include <IOKit/audio/IOAudioStream.h>
#include <IOKit/audio/IOAudioDefines.h>

#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include <IOKit/IOMessage.h>

#include <libkern/c++/OSCollectionIterator.h>

#define super IOAudioDevice

OSDefineMetaClassAndStructors (AppleUSBAudioDevice, super)

bool AppleUSBAudioDevice::init (OSDictionary * properties)  {
	bool		resultCode;

	debug2IOLog ("+AppleUSBAudioDevice[%p]::init ()\n", this);
	resultCode = FALSE;		// Assume failure

	// get the IOAudioDevice generic initialization
	FailIf (FALSE == super::init (properties), Exit);

	resultCode = TRUE;

Exit:
	debug2IOLog ("-AppleUSBAudioDevice[%p]::init ()\n", this);
	return resultCode;
}

void AppleUSBAudioDevice::free () {
    debug2IOLog ("+AppleUSBAudioDevice[%p]::free ()\n", this);

#if DEBUG
	if (interfaceVendor && interfaceVendor->getRetainCount () == 0) Debugger ("interfaceVendor = 0");
	if (interfaceProduct && interfaceProduct->getRetainCount () == 0) Debugger ("interfaceProduct = 0");
	if (deviceReleaseNumber && deviceReleaseNumber->getRetainCount () == 0) Debugger ("deviceReleaseNumber = 0");
	if (configurationValue && configurationValue->getRetainCount () == 0) Debugger ("configurationValue = 0");
	if (interfaceNumber && interfaceNumber->getRetainCount () == 0) Debugger ("interfaceNumber = 0");
	if (usbAudio && usbAudio->getRetainCount () == 0) Debugger ("usbAudio = 0");
#endif

    if (interfaceLock) {
        IORecursiveLockFree (interfaceLock);
        interfaceLock = NULL;
    }

    if (interfaceVendor) {
        interfaceVendor->release ();
        interfaceVendor = 0;
    }

    if (interfaceProduct) {
        interfaceProduct->release ();
        interfaceProduct = 0;
    }

    if (deviceReleaseNumber) {
        deviceReleaseNumber->release ();
        deviceReleaseNumber = 0;
    }

    if (configurationValue) {
        configurationValue->release ();
        configurationValue = 0;
    }

    if (interfaceNumber) {
        interfaceNumber->release ();
        interfaceNumber = 0;
    }

    if (usbAudio) {
        usbAudio->release ();
        usbAudio = 0;
    }

    super::free ();
    debug2IOLog ("-AppleUSBAudioDevice[%p]::free ()\n", this);
}

bool AppleUSBAudioDevice::requestTerminate (IOService * provider, IOOptionBits options) {
	debug4IOLog ("+AppleUSBAudioDevice[%p]::requestTerminate (%p, %x)\n", this, provider, options);
	debug4IOLog ("-AppleUSBAudioDevice[%p]::requestTerminate (%p, %x)\n", this, provider, options);
	return TRUE;		// it is OK to terminate us
}

bool AppleUSBAudioDevice::start (IOService * provider) {
    OSObject *						obj;
	UInt8							stringIndex;
	char							string[kStringBufferSize];
	IOReturn						err;
    Boolean							resultCode;

	debug3IOLog ("+AppleUSBAudioDevice[%p]::start (%p)\n", this, provider);

	resultCode = FALSE;

	controlInterface = OSDynamicCast (IOUSBInterface, provider);
	FailIf (NULL == controlInterface, Exit);
	previousInterface = controlInterface;

	debug2IOLog ("There are %d configurations on this device\n", controlInterface->GetDevice()->GetNumConfigurations ());
	usbAudio = USBAudioConfigObject::create (controlInterface->GetDevice()->GetFullConfigurationDescriptor (0));
	FailIf (NULL == usbAudio, Exit);

	// If this is an iSub, we need to not go any further because we don't support it in this driver
	// This will cause the driver to not load on any device that has _only_ a low frequency effect output terminal
	FailIf (usbAudio->GetNumOutputTerminals (0, 0) == 1 && usbAudio->GetIndexedOutputTerminalType (0, 0, 0) == OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER, Exit);

	err = kIOReturnError;
	string[0] = 0;
	stringIndex = controlInterface->GetDevice()->GetProductStringIndex ();
	if (0 != stringIndex) {
		err = controlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
	}

	if (0 == string[0] || kIOReturnSuccess != err) {
		strcpy (string, "Unknown USB Audio Device");
	}

	setDeviceName (string);

	err = kIOReturnError;
	string[0] = 0;
	stringIndex = controlInterface->GetDevice()->GetManufacturerStringIndex ();
	if (0 != stringIndex) {
		err = controlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
	}

	if (0 == string[0] || kIOReturnSuccess != err) {
		strcpy (string, "Unknown Manufacturer");
	}

	setManufacturerName (string);
	setDeviceTransportType (kIOAudioDeviceTransportTypeUSB);

	FailIf (FALSE == controlInterface->open (this), Exit);
	// get the IOAudioDevice generic start routine
	FailIf (FALSE == super::start (provider), Exit);

	interfaceLock = IORecursiveLockAlloc ();
	FailIf (NULL == interfaceLock, Exit);

	if (obj = controlInterface->getProperty (kUSBVendorName)) {
		obj->retain ();
		interfaceVendor = obj;
	}

	if (obj = controlInterface->getProperty (kUSBProductName)) {
		obj->retain ();
		interfaceProduct = obj;
	}

	if (obj = controlInterface->getProperty (kUSBDeviceReleaseNumber)) {
		obj->retain ();
		deviceReleaseNumber = obj;
	}

	if (obj = controlInterface->getProperty (kUSBConfigurationValue)) {
		obj->retain();
		configurationValue = obj;
	}

	if (obj = controlInterface->getProperty (kUSBInterfaceNumber)) {
		obj->retain ();
		interfaceNumber = obj;
	}

	resultCode = TRUE;

Exit:
	debug3IOLog ("-AppleUSBAudioDevice[%p]::start (%p)\n", this, provider);
	return resultCode;
}

void AppleUSBAudioDevice::streamStopped (IOAudioEngine *audioEngine) {
    // This must be called from within the workLoop
    // The AppleUSBAudioEngine does so from _setState()
    // which has the same requirement
    debugIOLog ("+AppleUSBAudioDevice::streamStopped ()\n");
    
    if (allStreamsStopped()) {
        terminate();
    }
    
    debugIOLog ("-AppleUSBAudioDevice::streamStopped ()\n");
}

bool AppleUSBAudioDevice::allStreamsStopped () {
    OSCollectionIterator *			audioEngineIterator;
    IOAudioEngine *					audioEngine;
    bool							result;

    debug2IOLog ("+AppleUSBAudioDevice[%p]::allStreamsStopped ()\n", this);
    result = TRUE;

    FailIf (NULL == audioEngines, Exit);

    // Need to do this on the IOWorkLoop
    
    audioEngineIterator = OSCollectionIterator::withCollection (audioEngines);

    if (audioEngineIterator) {
        while (audioEngine = (IOAudioEngine *)audioEngineIterator->getNextObject ()) {
            if (OSDynamicCast (AppleUSBAudioEngine, audioEngine)) {	// We only care that the AppleUSBAudioEngines are stopped
                if (audioEngine->getState () != kIOAudioEngineStopped) {
                    result = FALSE;
                    break;
                }
            }
        }
        audioEngineIterator->release ();
    }

Exit:
    debug2IOLog ("-AppleUSBAudioDevice[%p]::allStreamsStopped ()\n", this);
    return result;
}

IOReturn AppleUSBAudioDevice::performPowerStateChange (IOAudioDevicePowerState oldPowerState, IOAudioDevicePowerState newPowerState, UInt32 *microSecsUntilComplete) {
	IOReturn						result;

	debug4IOLog ("+AppleUSBAudioDevice::performPowerStateChange (%d, %d, %p)\n", oldPowerState, newPowerState, microSecsUntilComplete);

	result = super::performPowerStateChange (oldPowerState, newPowerState, microSecsUntilComplete);

	if (oldPowerState == kIOAudioDeviceSleep) {
		debugIOLog ("Waking from sleep - flushing controls to the device.\n");
		flushAudioControls ();
	}

	return result;
}

void AppleUSBAudioDevice::stop (IOService *provider) {
	bool			shouldStop;

	debug5IOLog ("+AppleUSBAudioDevice[%p]::stop (%p) - audioEngines = %p - rc=%d\n", this, provider, audioEngines, getRetainCount());

	shouldStop = TRUE;

	if (shouldStop) {
		performStop (provider);
	}

	debug2IOLog("-AppleUSBAudioDevice[%p]::stop ()\n", this);
}

// Return FALSE if you don't want PRAM updated on a volume change, TRUE if you want it updated.
// Only update PRAM if we're on a Cube and the speakers are Cube, SoundSticks, or Mirconas (somethings).
Boolean AppleUSBAudioDevice::ShouldUpdatePRAM (void) {
	const IORegistryPlane *			usbPlane;
	IORegistryEntry *				usbRegEntry;
	OSObject *						obj;
	OSNumber *						number;
	UInt16							productID;
	UInt16							vendorID;
	Boolean							speakersGood;
	Boolean							connectionGood;
	Boolean							result;

	// Assume failure
	result = FALSE;
	speakersGood = FALSE;
	connectionGood = FALSE;

	// Make sure they're speakers that can support boot beep
	vendorID = controlInterface->GetDevice()->GetVendorID ();
	debug2IOLog ("+ ShouldUpdatePRAM\nspeaker's vendorID = 0x%x\n", vendorID);
	if (kIOUSBVendorIDAppleComputer == vendorID || kIOUSBVendorIDHaronKardon == vendorID || kIOUSBVendorMicronas == vendorID) {
		speakersGood = TRUE;
	}
	debug2IOLog ("speakersGood = %d\n", speakersGood);

	// They have to be plugged into a root hub or a hub in monitor that can support boot beep
	if (TRUE == speakersGood) {
		usbPlane = getPlane (kIOUSBPlane);
		FailIf (NULL == usbPlane, Exit);

		usbRegEntry = controlInterface->GetDevice()->getParentEntry (usbPlane);
		FailIf (NULL == usbRegEntry, Exit);

		obj = usbRegEntry->getProperty (kUSBVendorID);
		number = OSDynamicCast (OSNumber, obj);
		FailIf (NULL == number, Exit);

		vendorID = number->unsigned32BitValue ();
		debug2IOLog ("hub's vendorID = 0x%x\n", vendorID);

		if (kIOUSBVendorIDAppleComputer == vendorID) {
			obj = usbRegEntry->getProperty (kUSBDevicePropertyLocationID);
			number = OSDynamicCast (OSNumber, obj);
			FailIf (NULL == number, Exit);

			if (OSDynamicCast (IOUSBRootHubDevice, usbRegEntry)) {
				// It's connected to the root hub
				connectionGood = TRUE;
				debugIOLog ("Directly connected to the root hub\n");
			} else {
				obj = usbRegEntry->getProperty (kUSBProductID);
				number = OSDynamicCast (OSNumber, obj);
				FailIf (NULL == number, Exit);

				productID = number->unsigned32BitValue ();
				debug2IOLog ("hub's productID = 0x%x\n", productID);

				if (kStudioDisplay15CRT == productID || kStudioDisplay17CRT == productID || kCinemaDisplay == productID || kStudioDisplay17FP == productID) {
					// It's connected to a good monitor
					connectionGood = TRUE;
					debugIOLog ("Connected to a capable monitor\n");
				}
			}
		}
	}
	debug2IOLog ("connectionGood = %d\n", connectionGood);

	// And there CANNOT be a "sound" node in the device tree so that OF will boot beep through them
	if (TRUE == connectionGood && FALSE == FindSoundNode ()) {
		result = TRUE;
	}

Exit:
	debug2IOLog ("- ShouldUpdatePRAM result = %d\n", result);
	return result;
}

Boolean AppleUSBAudioDevice::FindSoundNode (void) {
	const IORegistryPlane *			dtPlane;
	IORegistryEntry *				regEntry;
	IORegistryIterator *			iterator;
	Boolean							found;
	Boolean							done;
	const char *					name;

	found = FALSE;

	dtPlane = IORegistryEntry::getPlane (kIODeviceTreePlane);
	FailIf (NULL == dtPlane, Exit);

	iterator = IORegistryIterator::iterateOver (dtPlane, kIORegistryIterateRecursively);
	FailIf (NULL == iterator, Exit);

	done = FALSE;
	regEntry = iterator->getNextObject ();
	while (NULL != regEntry && FALSE == done) {
		name = regEntry->getName ();
		if (0 == strcmp (name, "mac-io")) {
			// This is where we want to start the search
			iterator->release ();		// release the current iterator and make a new one rooted at "mac-io"
			iterator = IORegistryIterator::iterateOver (regEntry, dtPlane);
			done = TRUE;
		}
		regEntry = iterator->getNextObject ();
	}

	// Now the real search begins...
	regEntry = iterator->getNextObject ();
	while (NULL != regEntry && FALSE == found) {
		name = regEntry->getName ();
		if (0 == strcmp (name, "sound")) {
			found = TRUE;
		}
		regEntry = iterator->getNextObject ();
	}

	iterator->release ();

Exit:
	return found;
}

void AppleUSBAudioDevice::performStop (IOService *provider) {

    debug3IOLog("+AppleUSBAudioDevice[%p]::performStop (%p)\n", this, provider);

	super::stop (provider);  // call the IOAudioDevice generic stop routine

    if (controlInterface) {
        controlInterface->close (this);
        controlInterface = NULL;
    }

    debug3IOLog ("-AppleUSBAudioDevice[%p]::performStop (%p)\n", this, provider);
}

bool AppleUSBAudioDevice::terminate (IOOptionBits options) {
	bool							shouldTerminate;
	bool							result;

	shouldTerminate = TRUE;
	result = TRUE;
	debug3IOLog ("+AppleUSBAudioDevice[%p]::terminate () - rc=%d\n", this, getRetainCount ());

	if (shouldTerminate) {
		result = super::terminate (options);
	}

	debug3IOLog ("-AppleUSBAudioDevice[%p]::terminate () - rc=%d\n", this, getRetainCount ());

	return result;
}

bool AppleUSBAudioDevice::finalize (IOOptionBits options) {
	bool result;
	debug4IOLog ("+AppleUSBAudioDevice[%p]::finalize (%p) - rc=%d\n", this, options, getRetainCount ());

	result = super::finalize (options);

	debug4IOLog ("-AppleUSBAudioDevice[%p]::finalize (%p) - rc=%d\n", this, options, getRetainCount ());

	return result;
}

IOReturn AppleUSBAudioDevice::message (UInt32 type, IOService * provider, void * arg) {
	debug5IOLog ("+AppleUSBAudioDevice[%p]::message (0x%x, %p) - rc=%d\n", this, type, provider, getRetainCount ());

	switch (type) {
		case kIOMessageServiceIsTerminated:
		case kIOMessageServiceIsRequestingClose:
			if (controlInterface != NULL && controlInterface == provider) {
				controlInterface->close (this);
				controlInterface = NULL;
			}
		default:
			;
	}

	debug5IOLog ("-AppleUSBAudioDevice[%p]::message (0x%x, %p) - rc=%d\n", this, type, provider, getRetainCount ());
	return kIOReturnSuccess;
}

IOReturn AppleUSBAudioDevice::createControlsForInterface (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altInterfaceNum) {
    AppleUSBAudioEngine *				usbAudioEngine;
    UInt8								channelNum;
    AppleUSBAudioLevelControl *			speakerControl;
    AppleUSBAudioLevelControl *			micControl;
	AppleUSBAudioLevelControl *			pramControl;
    AppleUSBAudioMuteControl *			muteControl;
    IOReturn							result;
	UInt16								terminalType;
	UInt8								numTerminals;
	UInt8								featureUnitID;
	UInt8								terminalIndex;
	UInt8								controlInterfaceNum;
	Boolean								shouldUpdatePRAM;

    result = kIOReturnError;
	terminatingDriver = FALSE;
	FailIf (NULL == controlInterface, Exit);

    usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, audioEngine);
    FailIf (NULL == usbAudioEngine, Exit);

	controlInterfaceNum = controlInterface->GetInterfaceNumber ();

    if (usbAudioEngine->getDirection () == kIOAudioStreamDirectionOutput) {
        // It's an output device (e.g., a speaker).
		featureUnitID = 0;
		// look for a streaming input terminal that's connected to a non-streaming output terminal
		// for the moment we'll just look for a feature unit connected to a non-streaming output terminal
		numTerminals = usbAudio->GetNumOutputTerminals (controlInterfaceNum, 0);
		debug2IOLog ("num output terminals = %d\n", numTerminals);
		for (terminalIndex = 0; terminalIndex < numTerminals; terminalIndex++) {
			debug2IOLog ("terminalIndex = 0x%X\n", terminalIndex);
			terminalType = usbAudio->GetIndexedOutputTerminalType (controlInterfaceNum, 0, terminalIndex);
			debug2IOLog ("terminalType = 0x%X\n", terminalType);
			if (terminalType != 0x0101) {	// Only look for output terminals that output audio (things we can play to)
				featureUnitID = usbAudio->GetFeatureUnitIDConnectedToOutputTerminal (controlInterfaceNum, 0, usbAudio->GetIndexedOutputTerminalID (controlInterfaceNum, 0, terminalIndex));
				debug2IOLog ("featureUnitID = %d\n", featureUnitID);
				break;	// get out of for loop
			}
		}
		FailWithAction (0 == featureUnitID, result = kIOReturnSuccess, Exit);	// There isn't a feature unit connected to this input terminal
		// The interface was opened in AppleUSBAudioEngine::initHardware
		controlInterface->SetAlternateInterface (this, kRootAlternateSetting);

		shouldUpdatePRAM = ShouldUpdatePRAM ();
		if (shouldUpdatePRAM) {
			pramControl = AppleUSBAudioLevelControl::create (featureUnitID,
															controlInterfaceNum,
															0xff,
															1,
															shouldUpdatePRAM,
															(USBDeviceRequest)&deviceRequest,
															this,
															kIOAudioLevelControlSubTypeVolume,
															kIOAudioControlUsageOutput);
			if (NULL != pramControl) {
				audioEngine->addDefaultAudioControl (pramControl);
				pramControl->release ();
			}
		}

		for (channelNum = 0; channelNum <= usbAudio->GetNumChannels (interfaceNum, altInterfaceNum); channelNum++) {
			if (usbAudio->ChannelHasVolumeControl (controlInterfaceNum, 0, featureUnitID, channelNum)) {
				speakerControl = AppleUSBAudioLevelControl::create (featureUnitID,
																	controlInterfaceNum,
																	VOLUME_CONTROL,
																	channelNum,
																	shouldUpdatePRAM,
																	(USBDeviceRequest)&deviceRequest,
																	this,
																	kIOAudioLevelControlSubTypeVolume,
																	kIOAudioControlUsageOutput);

				if (NULL != speakerControl) {
					audioEngine->addDefaultAudioControl (speakerControl);
					speakerControl->release ();
				} else {
					debug2IOLog ("++AppleUSBAudioDevice::createControlsForInterface () - error creating volume control for channelNum %d\n", channelNum);
				}
			}
		}
		muteControl = NULL;
		for (channelNum = 0; channelNum <= usbAudio->GetNumChannels (interfaceNum, altInterfaceNum); channelNum++) {
			if (usbAudio->ChannelHasMuteControl (controlInterfaceNum, 0, featureUnitID, channelNum)) {
				muteControl = AppleUSBAudioMuteControl::create (featureUnitID,
																controlInterfaceNum,
																channelNum,
																(USBDeviceRequest)&deviceRequest,
																this,
																kIOAudioControlUsageOutput);
				if (NULL != muteControl) {
					audioEngine->addDefaultAudioControl (muteControl);
					muteControl->release ();
				} else {
					debug2IOLog ("++AppleUSBAudioDevice::createControlsForInterface () - error creating mute control for channelNum %d\n", channelNum);
				}
			}
		}
    } else {
        // It's an input device (e.g., a microphone).
		featureUnitID = 0;
		// look for a streaming input terminal that's connected to a non-streaming output terminal
		// for the moment we'll just look for a feature unit connected to a non-streaming output terminal
		numTerminals = usbAudio->GetNumOutputTerminals (controlInterfaceNum, 0);
		debug2IOLog ("num output terminals = %d\n", numTerminals);
		for (terminalIndex = 0; terminalIndex < numTerminals; terminalIndex++) {
			debug2IOLog ("terminalIndex = 0x%X\n", terminalIndex);
			terminalType = usbAudio->GetIndexedOutputTerminalType (controlInterfaceNum, 0, terminalIndex);
			debug2IOLog ("terminalType = 0x%X\n", terminalType);
			if (terminalType == 0x0101) {	// Only look for output terminals that output digital audio data (things we can record from)
				featureUnitID = usbAudio->GetFeatureUnitIDConnectedToOutputTerminal (controlInterfaceNum, 0, usbAudio->GetIndexedOutputTerminalID (controlInterfaceNum, 0, terminalIndex));
				debug2IOLog ("featureUnitID = %d\n", featureUnitID);
				break;	// get out of for loop
			}
		}
		FailWithAction (0 == featureUnitID, result = kIOReturnSuccess, Exit);	// There isn't a feature unit connected to this output terminal
		// The interface was opened in AppleUSBAudioEngine::initHardware
		controlInterface->SetAlternateInterface (this, kRootAlternateSetting);
		for (channelNum = 0; channelNum <= usbAudio->GetNumChannels (interfaceNum, altInterfaceNum); channelNum++) {
			if (usbAudio->ChannelHasVolumeControl (controlInterfaceNum, 0, featureUnitID, channelNum)) {
				micControl = AppleUSBAudioLevelControl::create (featureUnitID,
																controlInterfaceNum,
																VOLUME_CONTROL,
																channelNum,
																FALSE,
																(USBDeviceRequest)&deviceRequest,
																this,
																kIOAudioLevelControlSubTypeVolume,
																kIOAudioControlUsageInput);

				if (NULL != micControl) {
					audioEngine->addDefaultAudioControl (micControl);
					micControl->release ();
				} else {
					debug2IOLog ("++AppleUSBAudioDevice::createControlsForInterface () - error creating volume control for channelNum %d\n", channelNum);
				}
			} else {
				debug2IOLog ("channel %d doesn't have a volume control\n", channelNum);
			}
		}
		muteControl = NULL;
		for (channelNum = 0; channelNum <= usbAudio->GetNumChannels (interfaceNum, altInterfaceNum); channelNum++) {
			if (usbAudio->ChannelHasMuteControl (controlInterfaceNum, 0, featureUnitID, channelNum)) {
				muteControl = AppleUSBAudioMuteControl::create (featureUnitID,
																controlInterfaceNum,
																channelNum,
																(USBDeviceRequest)&deviceRequest,
																this,
																kIOAudioControlUsageInput);
				if (NULL != muteControl) {
					audioEngine->addDefaultAudioControl (muteControl);
					muteControl->release ();
				} else {
					debug2IOLog ("++AppleUSBAudioDevice::createControlsForInterface () - error creating mute control for channelNum %d\n", channelNum);
				}
			}
		}
    }

Exit:
	return result;
}

IOReturn AppleUSBAudioDevice::activateAudioEngine (IOAudioEngine *audioEngine, bool shouldStartAudioEngine, UInt8 interfaceNum, UInt8 altInterfaceNum) {
    IOReturn							result;

    debug5IOLog ("+AppleUSBAudioDevice[%p]::activateAudioEngine (%p, %d) - rc=%d\n", this, audioEngine, shouldStartAudioEngine, getRetainCount());

    FailIf (kIOReturnSuccess != super::activateAudioEngine (audioEngine, shouldStartAudioEngine), Exit);
	result = TRUE;

Exit:
	flushAudioControls ();

    debug4IOLog ("-AppleUSBAudioDevice[%p]::activateAudioEngine (%p) - rc=%d\n", this, audioEngine, getRetainCount ());
    return result;
}

IOReturn AppleUSBAudioDevice::deviceRequest (IOUSBDevRequest *request, AppleUSBAudioDevice * self, IOUSBCompletion *completion) {
	IOReturn						result;

	debug4IOLog ("+AppleUSBAudioDevice[%p]::deviceRequest (%p, %p)\n", self, request, completion);
	result = kIOReturnSuccess;
	if (self->controlInterface && FALSE == self->terminatingDriver) {
		FailIf (NULL == self->interfaceLock, Exit);

        IORecursiveLockLock (self->interfaceLock);
        result = self->controlInterface->DeviceRequest (request, completion);
        IORecursiveLockUnlock (self->interfaceLock);
    }

	debug4IOLog ("-AppleUSBAudioDevice[%p]::deviceRequest (%p, %p)\n", self, request, completion);

Exit:
	return result;
}

bool AppleUSBAudioDevice::willTerminate (IOService * provider, IOOptionBits options) {
	debug3IOLog ("+AppleUSBAudioDevice[%p]::willTerminate (%p)\n", this, provider);

	if (controlInterface == provider) {
		terminatingDriver = TRUE;
	}

	debug2IOLog ("-AppleUSBAudioDevice[%p]::willTerminate\n", this);

	return super::willTerminate (provider, options);
}


#ifdef DEBUG

void AppleUSBAudioDevice::retain() const
{
//    debug3IOLog("AppleUSBAudioDevice(%p)::retain() - rc=%d\n", this, getRetainCount());
    super::retain();
}

void AppleUSBAudioDevice::release() const
{
//    debug3IOLog("AppleUSBAudioDevice(%p)::release() - rc=%d\n", this, getRetainCount());
	super::release();
}

#endif

Generated by GNU enscript 1.6.4.