[plain text]
#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;
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; }
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);
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);
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) {
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);
audioEngineIterator = OSCollectionIterator::withCollection (audioEngines);
if (audioEngineIterator) {
while (audioEngine = (IOAudioEngine *)audioEngineIterator->getNextObject ()) {
if (OSDynamicCast (AppleUSBAudioEngine, audioEngine)) { 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);
}
Boolean AppleUSBAudioDevice::ShouldUpdatePRAM (void) {
const IORegistryPlane * usbPlane;
IORegistryEntry * usbRegEntry;
OSObject * obj;
OSNumber * number;
UInt16 productID;
UInt16 vendorID;
Boolean speakersGood;
Boolean connectionGood;
Boolean result;
result = FALSE;
speakersGood = FALSE;
connectionGood = FALSE;
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);
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)) {
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) {
connectionGood = TRUE;
debugIOLog ("Connected to a capable monitor\n");
}
}
}
}
debug2IOLog ("connectionGood = %d\n", connectionGood);
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")) {
iterator->release (); iterator = IORegistryIterator::iterateOver (regEntry, dtPlane);
done = TRUE;
}
regEntry = iterator->getNextObject ();
}
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);
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::activateAudioEngine (IOAudioEngine *audioEngine, bool shouldStartAudioEngine, 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;
debug5IOLog ("+AppleUSBAudioDevice[%p]::activateAudioEngine (%p, %d) - rc=%d\n", this, audioEngine, shouldStartAudioEngine, getRetainCount());
result = kIOReturnError;
FailIf (NULL == controlInterface, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, audioEngine);
FailIf (NULL == usbAudioEngine, Exit);
controlInterfaceNum = controlInterface->GetInterfaceNumber ();
if (usbAudioEngine->getDirection () == kIOAudioStreamDirectionOutput) {
featureUnitID = 0;
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) { featureUnitID = usbAudio->GetFeatureUnitIDConnectedToOutputTerminal (controlInterfaceNum, 0, usbAudio->GetIndexedOutputTerminalID (controlInterfaceNum, 0, terminalIndex));
debug2IOLog ("featureUnitID = %d\n", featureUnitID);
break; }
}
FailWithAction (0 == featureUnitID, result = kIOReturnSuccess, Finish); 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::activateAudioEngine () - 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::activateAudioEngine () - error creating mute control for channelNum %d\n", channelNum);
}
}
}
} else {
featureUnitID = 0;
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) { featureUnitID = usbAudio->GetFeatureUnitIDConnectedToOutputTerminal (controlInterfaceNum, 0, usbAudio->GetIndexedOutputTerminalID (controlInterfaceNum, 0, terminalIndex));
debug2IOLog ("featureUnitID = %d\n", featureUnitID);
break; }
}
FailWithAction (0 == featureUnitID, result = kIOReturnSuccess, Finish); 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::activateAudioEngine () - 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,
kIOAudioControlUsageInput);
if (NULL != muteControl) {
audioEngine->addDefaultAudioControl (muteControl);
muteControl->release ();
} else {
debug2IOLog ("++AppleUSBAudioDevice::activateAudioEngine () - error creating mute control for channelNum %d\n", channelNum);
}
}
}
}
Finish:
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) {
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;
}
#ifdef DEBUG
void AppleUSBAudioDevice::retain() const
{
super::retain();
}
void AppleUSBAudioDevice::release() const
{
super::release();
}
#endif
Generated by GNU enscript 1.6.4.