[plain text]
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioDictionary.h"
#define super IOAudioDevice
#define LOCALIZABLE FALSE
OSDefineMetaClassAndStructors (AppleUSBAudioDevice, super)
void AppleUSBAudioDevice::free () {
debugIOLog ("+ AppleUSBAudioDevice[%p]::free ()", this);
if (NULL != mUpdateTimer)
{
mUpdateTimer->cancelTimeout ();
mUpdateTimer->release ();
mUpdateTimer = NULL;
}
if (mInterfaceLock)
{
IORecursiveLockFree (mInterfaceLock);
mInterfaceLock = NULL;
}
if (mConfigDictionary)
{
mConfigDictionary->release ();
mConfigDictionary = NULL;
}
if (mRegisteredEngines)
{
mRegisteredEngines->release ();
mRegisteredEngines = NULL;
}
if (mMonoControlsArray)
{
mMonoControlsArray->release ();
mMonoControlsArray = NULL;
}
if (mRetryEQDownloadThread)
{
thread_call_free (mRetryEQDownloadThread);
}
super::free ();
debugIOLog ("- AppleUSBAudioDevice[%p]::free ()", this);
}
bool AppleUSBAudioDevice::ControlsStreamNumber (UInt8 streamNumber) {
OSArray * streamNumberArray = NULL;
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt8 numStreams;
UInt8 streamIndex;
bool doesControl;
doesControl = FALSE;
if (mConfigDictionary)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getControlledStreamNumbers (&streamNumberArray, &numStreams), Exit);
for (streamIndex = 0; streamIndex < numStreams; streamIndex++)
{
FailIf (NULL == (arrayObject = streamNumberArray->getObject (streamIndex)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::ControlsStreamNumber () - Checking stream %d against controled stream %d", this, streamNumber, arrayNumber->unsigned8BitValue());
if (streamNumber == arrayNumber->unsigned8BitValue())
{
doesControl = TRUE;
break; }
}
}
Exit:
return doesControl;
}
bool AppleUSBAudioDevice::start (IOService * provider) {
bool result;
debugIOLog ("+ AppleUSBAudioDevice[%p]::start (%p)", this, provider);
result = FALSE;
mControlInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (FALSE == mControlInterface->open (this), Exit);
mInitHardwareThread = thread_call_allocate ((thread_call_func_t)AppleUSBAudioDevice::initHardwareThread, (thread_call_param_t)this);
FailIf (NULL == mInitHardwareThread, Exit);
result = super::start (provider);
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::start (%p) = result", this, provider, result);
return result;
}
bool AppleUSBAudioDevice::initHardware (IOService * provider) {
bool result;
result = FALSE;
FailIf (NULL == mInitHardwareThread, Exit);
thread_call_enter1 (mInitHardwareThread, (void *)provider);
result = TRUE;
Exit:
return result;
}
void AppleUSBAudioDevice::initHardwareThread (AppleUSBAudioDevice * aua, void * provider) {
IOCommandGate * cg;
IOReturn result;
FailIf (NULL == aua, Exit);
cg = aua->getCommandGate ();
if (cg)
{
result = cg->runAction (aua->initHardwareThreadAction, provider);
}
Exit:
return;
}
IOReturn AppleUSBAudioDevice::initHardwareThreadAction (OSObject * owner, void * provider, void * arg2, void * arg3, void * arg4) {
AppleUSBAudioDevice * aua;
IOReturn result;
result = kIOReturnError;
aua = (AppleUSBAudioDevice *)owner;
FailIf (NULL == aua, Exit);
result = aua->protectedInitHardware ((IOService *)provider);
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::protectedInitHardware (IOService * provider) {
char string[kStringBufferSize];
UInt8 stringIndex;
IOReturn err;
Boolean resultCode;
OSArray * streamNumberArray;
UInt8 numStreamInterfaces;
UInt8 numStreams;
debugIOLog ("+ AppleUSBAudioDevice[%p]::start (%p)", this, provider);
resultCode = FALSE;
FailIf (NULL == mControlInterface, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - %d configuration(s) on this device. This control interface number is %d", this, mControlInterface->GetDevice()->GetNumConfigurations (), mControlInterface->GetInterfaceNumber ());
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - Attempting to create configuration dictionary...", this);
mConfigDictionary = AUAConfigurationDictionary::create (mControlInterface->GetDevice()->GetFullConfigurationDescriptor (0), mControlInterface->GetInterfaceNumber());
FailIf (NULL == mConfigDictionary, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - Successfully created configuration dictionary.", this);
mInterfaceLock = IORecursiveLockAlloc ();
FailIf (NULL == mInterfaceLock, Exit);
mControlGraph = BuildConnectionGraph (mControlInterface->GetInterfaceNumber ());
FailIf (NULL == mControlGraph, Exit);
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
FailIf ( NULL == ( mClockGraph = buildClockGraph ( mControlInterface->GetInterfaceNumber () ) ), Exit );
FailIf ( kIOReturnSuccess != addSampleRatesFromClockSpace (), Exit );
}
FailIf (kIOReturnSuccess != mConfigDictionary->getControlledStreamNumbers (&streamNumberArray, &numStreams), Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getNumStreamInterfaces (&numStreamInterfaces), Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - %d controlled stream(s). %d stream interface(s).", this, numStreams, numStreamInterfaces);
FailIf (0 == numStreams, Exit);
if ( 0 == mControlInterface->GetInterfaceNumber() )
{
FailIf (mConfigDictionary->isiSub(), Exit);
}
err = kIOReturnError;
string[0] = 0;
stringIndex = mControlInterface->GetInterfaceStringIndex ();
if (0 != stringIndex)
{
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
if (kIOReturnSuccess != err)
{
debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - couldn't get string descriptor. Retrying ...", this);
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
}
if (kIOReturnSuccess != err)
{
debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - Still couldn't get string descriptor. Resetting device ...", this);
mControlInterface->GetDevice()->ResetDevice(); IOSleep (50); debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware - Last retry ...", this);
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
}
}
else
{
stringIndex = mControlInterface->GetDevice()->GetProductStringIndex ();
if (0 != stringIndex)
{
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
if (kIOReturnSuccess != err)
{
debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - couldn't get string descriptor. Retrying ...", this);
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
}
if (kIOReturnSuccess != err)
{
debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - Still couldn't get string descriptor. Resetting device ...", this);
mControlInterface->GetDevice()->ResetDevice(); IOSleep (50); debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - Last retry ...", this);
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
}
}
else
{
OSObject * nameObject = NULL;
OSString * nameString = NULL;
debugIOLog ( "! AppleUSBAudioDevice[%p]::protectedInitHardware () - Trying to retrieve the product name from the IOUSBDevice ... ", this );
nameObject = mControlInterface->GetDevice ()->getProperty ( "USB Product Name" );
if ( nameObject )
{
if ( NULL != ( nameString = OSDynamicCast ( OSString, nameObject ) ) )
{
debugIOLog ( "! AppleUSBAudioDevice[%p]::protectedInitHardware () - Retrieved product name %s", this, nameString->getCStringNoCopy () );
strncpy ( string, nameString->getCStringNoCopy(), kStringBufferSize );
err = kIOReturnSuccess;
}
}
}
}
if (0 == string[0] || kIOReturnSuccess != err)
{
strncpy (string, "Unknown USB Audio Device", kStringBufferSize);
}
setDeviceName (string);
err = kIOReturnError;
string[0] = 0;
stringIndex = mControlInterface->GetDevice()->GetManufacturerStringIndex ();
if (0 != stringIndex)
{
err = mControlInterface->GetDevice()->GetStringDescriptor (stringIndex, string, kStringBufferSize);
}
if (0 == string[0] || kIOReturnSuccess != err)
{
strncpy (string, "Unknown Manufacturer", kStringBufferSize);
}
setManufacturerName (string);
setDeviceTransportType (kIOAudioDeviceTransportTypeUSB);
#if LOCALIZABLE
setProperty (kIOAudioDeviceLocalizedBundleKey, "AppleUSBAudio.kext");
#endif
resultCode = super::initHardware (provider);
mLastUSBFrame = 0ull;
mLastWallTime_nanos = 0ull;
mAnchorResetCount = kRefreshCount;
mNewReferenceUSBFrame = 0ull;
resetRateTimer();
mFailingAudioEngine = NULL;
mUpdateTimer = IOTimerEventSource::timerEventSource (this, TimerAction);
FailIf (NULL == mUpdateTimer, Exit);
workLoop->addEventSource (mUpdateTimer);
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - starting rate timer");
TimerAction ( this, mUpdateTimer);
IOService::registerService();
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::start (%p)", this, provider);
return TRUE;
}
IOReturn AppleUSBAudioDevice::performPowerStateChange (IOAudioDevicePowerState oldPowerState, IOAudioDevicePowerState newPowerState, UInt32 *microSecsUntilComplete) {
IOReturn result;
result = super::performPowerStateChange (oldPowerState, newPowerState, microSecsUntilComplete);
if ( (mUpdateTimer)
&& (kIOAudioDeviceSleep == newPowerState))
{
debugIOLog ("? AppleUSBAudioDevice[%p]::performPowerStateChange () - Going to sleep - stopping the rate timer.", this);
mUpdateTimer->cancelTimeout ();
mNewReferenceUSBFrame = 0ull;
mLastUSBFrame = 0ull;
( * (UInt64 *) &mNewReferenceWallTime) = 0ull;
mLastWallTime_nanos = 0ull;
}
if (oldPowerState == kIOAudioDeviceSleep)
{
mAnchorResetCount = kRefreshCount;
resetRateTimer();
#if RESETAFTERSLEEP
FailIf (NULL == mControlInterface, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::performPowerStateChange () - Resetting port after wake from sleep ...", this);
mControlInterface->GetDevice()->ResetDevice();
IOSleep (10);
#endif
debugIOLog ("? AppleUSBAudioDevice[%p]::performPowerStateChange () - Waking from sleep - restarting the rate timer.", this);
TimerAction ( this, mUpdateTimer);
debugIOLog ("? AppleUSBAudioDevice[%p]::performPowerStateChange () - Flushing controls to the device ...", this);
flushAudioControls ();
}
Exit:
return result;
}
void AppleUSBAudioDevice::stop (IOService *provider) {
debugIOLog ("+ AppleUSBAudioDevice[%p]::stop (%p) - audioEngines = %p - rc=%d", this, provider, audioEngines, getRetainCount());
if (mUpdateTimer)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::stop () - Cancelling time stamp rate timer ...", this);
mUpdateTimer->cancelTimeout ();
mUpdateTimer->disable();
}
super::stop (provider);
if (mControlInterface)
{
mControlInterface->close (this);
mControlInterface = NULL;
}
if (mInitHardwareThread)
{
thread_call_cancel (mInitHardwareThread);
thread_call_free (mInitHardwareThread);
mInitHardwareThread = NULL;
}
debugIOLog("- AppleUSBAudioDevice[%p]::stop ()", 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;
FailIf (NULL == mControlInterface, Exit);
vendorID = mControlInterface->GetDevice()->GetVendorID ();
debugIOLog ("? AppleUSBAudioDevice[%p]::ShouldUpdatePRAM () - speaker's vendorID = 0x%x", this, vendorID);
if (kIOUSBVendorIDAppleComputer == vendorID || kIOUSBVendorIDHarmonKardon == vendorID || kIOUSBVendorMicronas == vendorID)
{
speakersGood = TRUE;
}
if (TRUE == speakersGood)
{
usbPlane = getPlane (kIOUSBPlane);
FailIf (NULL == usbPlane, Exit);
usbRegEntry = mControlInterface->GetDevice()->getParentEntry (usbPlane);
FailIf (NULL == usbRegEntry, Exit);
obj = usbRegEntry->getProperty (kUSBVendorID);
number = OSDynamicCast (OSNumber, obj);
FailIf (NULL == number, Exit);
vendorID = number->unsigned32BitValue ();
if (kIOUSBVendorIDAppleComputer == vendorID)
{
obj = usbRegEntry->getProperty (kUSBDevicePropertyLocationID);
number = OSDynamicCast (OSNumber, obj);
FailIf (NULL == number, Exit);
if (OSDynamicCast (IOUSBRootHubDevice, usbRegEntry))
{
connectionGood = TRUE;
debugIOLog ("? AppleUSBAudioDevice[%p]::ShouldUpdatePRAM () - Directly connected to the root hub", this);
}
else
{
obj = usbRegEntry->getProperty (kUSBProductID);
number = OSDynamicCast (OSNumber, obj);
FailIf (NULL == number, Exit);
productID = number->unsigned32BitValue ();
if (kStudioDisplay15CRT == productID || kStudioDisplay17CRT == productID || kCinemaDisplay == productID || kStudioDisplay17FP == productID)
{
connectionGood = TRUE;
}
}
}
}
if (TRUE == connectionGood && FALSE == FindSoundNode ())
{
result = TRUE;
}
Exit:
debugIOLog ("? AppleUSBAudioDevice[%p]::ShouldUpdatePRAM () - result = %d", this, 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;
}
IOReturn AppleUSBAudioDevice::message (UInt32 type, IOService * provider, void * arg) {
AppleUSBAudioEngine * currentEngine = NULL;
OSDictionary * currentEngineInfo = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::message (0x%x, %p) - rc=%d", this, type, provider, getRetainCount ());
switch (type)
{
case kIOMessageServiceIsTerminated:
case kIOMessageServiceIsRequestingClose:
if (mControlInterface != NULL && mControlInterface == provider)
{
mControlInterface->close (this);
mControlInterface = NULL;
}
break;
case kIOUSBMessagePortHasBeenReset:
debugIOLog ("? AppleUSBAudioDevice[%p]::message () - Flushing controls to the device.", this);
flushAudioControls ();
FailIf (NULL == mRegisteredEngines, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::message () - Resetting engines.", this);
for (UInt8 engineIndex = 0; engineIndex < mRegisteredEngines->getCount (); engineIndex++)
{
currentEngineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineIndex));
FailIf (NULL == currentEngineInfo, Exit);
currentEngine = OSDynamicCast (AppleUSBAudioEngine, currentEngineInfo->getObject (kEngine));
FailIf (NULL == currentEngine, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::message () - Resetting engine %p...", this, currentEngine);
currentEngine->pauseAudioEngine ();
if (currentEngine->mStreamInterface)
{
currentEngine->mStreamInterface->close (currentEngine);
}
{
currentEngine->mStreamInterface->open (currentEngine);
}
currentEngine->resumeAudioEngine ();
}
break;
default:
;
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::message (0x%x, %p) - rc=%d", this, type, provider, getRetainCount ());
return kIOReturnSuccess;
}
UInt8 AppleUSBAudioDevice::getDeviceSpeed () {
IOUSBDevice * usbDevice;
UInt8 speed = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
speed = usbDevice->GetSpeed ();
#if DEBUGLOGGING
switch (speed)
{
case kUSBDeviceSpeedLow:
debugIOLog ("? AppleUSBAudioDevice[%p]::getDeviceSpeed () = kUSBDeviceSpeedLow", this);
break;
case kUSBDeviceSpeedFull:
debugIOLog ("? AppleUSBAudioDevice[%p]::getDeviceSpeed () = kUSBDeviceSpeedFull", this);
break;
case kUSBDeviceSpeedHigh:
debugIOLog ("? AppleUSBAudioDevice[%p]::getDeviceSpeed () = kUSBDeviceSpeedHigh", this);
break;
default:
debugIOLog ("? AppleUSBAudioDevice[%p]::getDeviceSpeed () = %d (UNKNOWN)", this, speed);
}
#endif
Exit:
return speed;
}
bool AppleUSBAudioDevice::detectSplitTransactions () {
IOUSBDevice * usbDevice;
const IORegistryPlane * usbPlane = getPlane (kIOUSBPlane);
IORegistryEntry * currentEntry;
UInt8 speed;
bool canStop = false;
bool splitTransactions = false;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
currentEntry = OSDynamicCast (IORegistryEntry, usbDevice);
if (kUSBDeviceSpeedHigh == usbDevice->GetSpeed ())
{
debugIOLog ("? AppleUSBAudioDevice::detectSplitTransactions () - This is a high speed device, so there are no split transactions.");
splitTransactions = false;
canStop = true;
}
while ( (!canStop)
&& (currentEntry)
&& (usbDevice))
{
speed = usbDevice->GetSpeed ();
if (kUSBDeviceSpeedHigh == speed)
{
debugIOLog ("? AppleUSBAudioDevice::detectSplitTransactions () = true");
splitTransactions = true;
canStop = true;
}
else
{
currentEntry = OSDynamicCast (IORegistryEntry, currentEntry->getParentEntry (usbPlane));
usbDevice = OSDynamicCast (IOUSBDevice, currentEntry);
}
}
Exit:
return splitTransactions;
}
Boolean AppleUSBAudioDevice::checkForUHCI () {
Boolean result = FALSE;
IOUSBDevice * usbDevice;
const IORegistryPlane * servicePlane = getPlane (kIOServicePlane);
IOService * currentEntry;
IORegistryEntry * parentEntry;
char serviceName[20];
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
parentEntry = usbDevice->getParentEntry (servicePlane);
FailIf (NULL == parentEntry, Exit);
currentEntry = OSDynamicCast (IOService, parentEntry);
FailIf (NULL == currentEntry, Exit);
strncpy (serviceName, currentEntry->getName (servicePlane), 20);
while ( (currentEntry)
&& strcmp (serviceName, "AppleUSBUHCI")
&& strcmp (serviceName, "AppleUSBOHCI")
&& strcmp (serviceName, "AppleUSBEHCI"))
{
parentEntry = currentEntry->getParentEntry (servicePlane);
FailIf (NULL == parentEntry, Exit);
currentEntry = OSDynamicCast (IOService, parentEntry);
if (currentEntry)
{
strncpy (serviceName, currentEntry->getName (servicePlane), 20);
}
} FailIf (NULL == currentEntry, Exit);
if (!strcmp (serviceName, "AppleUSBUHCI"))
{
debugIOLog ("? AppleUSBAudioDevice::checkForUHCI () - UHCI connection detected!\n");
result = TRUE;
}
Exit:
return result;
}
SInt32 AppleUSBAudioDevice::getEngineInfoIndex (AppleUSBAudioEngine * inAudioEngine) {
OSDictionary * engineInfo;
AppleUSBAudioEngine * usbAudioEngine;
UInt16 engineIndex;
SInt32 returnIndex;
returnIndex = -1;
if (mRegisteredEngines)
{
for (engineIndex = 0; engineIndex < mRegisteredEngines->getCount (); engineIndex++)
{
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineIndex));
if (engineInfo)
{
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
if (inAudioEngine == usbAudioEngine)
{
returnIndex = engineIndex;
break; }
}
}
}
return returnIndex;
}
IOReturn AppleUSBAudioDevice::doControlStuff (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altSettingNum) {
AppleUSBAudioEngine * usbAudioEngine;
IOAudioSelectorControl * inputSelector;
OSArray * arrayOfPathsFromOutputTerminal;
OSArray * aPath;
OSArray * playThroughPaths;
OSNumber * theUnitIDNum;
OSNumber * number;
OSDictionary * engineInfo;
IOReturn result;
UInt32 numUnitsInPath, unitIndexInPath ;
UInt32 outputTerminalIndex;
UInt32 numOutputTerminalArrays;
UInt32 numPathsFromOutputTerminal;
UInt32 pathsToOutputTerminalN;
UInt32 selection;
SInt32 engineIndex;
SInt32 oldEngineIndex;
UInt16 terminalType;
UInt8 numSelectorUnits;
UInt8 subType;
UInt8 numOutputTerminals;
UInt8 selectorUnitID;
UInt8 featureUnitID;
UInt8 controlInterfaceNum;
UInt8 unitID;
UInt8 outputTerminalID;
Boolean done;
bool playthroughCapable;
debugIOLog ("+ AppleUSBAudioDevice::doControlStuff(0x%x, %d, %d)", audioEngine, interfaceNum, altSettingNum);
result = kIOReturnError;
inputSelector = NULL;
done = FALSE;
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, audioEngine);
FailIf (NULL == usbAudioEngine, Exit);
FailIf (NULL == mControlInterface, Exit);
debugIOLog ("? AppleUSBAudioDevice::doControlStuff () - This usbAudioEngine = %p", usbAudioEngine);
if (NULL == mRegisteredEngines)
{
mRegisteredEngines = OSArray::withCapacity (1);
FailIf (NULL == mRegisteredEngines, Exit);
}
engineInfo = OSDictionary::withCapacity (1);
FailIf (NULL == engineInfo, Exit);
engineInfo->setObject (kEngine, usbAudioEngine);
number = OSNumber::withNumber (interfaceNum, 8);
engineInfo->setObject (kInterface, number);
number->release ();
number = OSNumber::withNumber (altSettingNum, 8);
engineInfo->setObject (kAltSetting, number);
number->release ();
oldEngineIndex = getEngineInfoIndex (usbAudioEngine);
if (-1 != oldEngineIndex)
{
mRegisteredEngines->replaceObject (oldEngineIndex, engineInfo);
}
else
{
mRegisteredEngines->setObject (engineInfo);
}
engineInfo->release ();
featureUnitID = 0;
selectorUnitID = 0;
outputTerminalID = 0;
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumOutputTerminals (&numOutputTerminals, controlInterfaceNum, 0), Exit);
if (usbAudioEngine->getDirection () == kIOAudioStreamDirectionOutput)
{
for (outputTerminalIndex = 0; outputTerminalIndex < numOutputTerminals && FALSE == done; outputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalIndex), Exit);
if (terminalType != 0x101)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalID (&outputTerminalID, controlInterfaceNum, 0, outputTerminalIndex), Exit);
numOutputTerminalArrays = mControlGraph->getCount ();
for (pathsToOutputTerminalN = 0; pathsToOutputTerminalN < numOutputTerminalArrays; pathsToOutputTerminalN++)
{
arrayOfPathsFromOutputTerminal = OSDynamicCast (OSArray, mControlGraph->getObject (pathsToOutputTerminalN));
FailIf (NULL == arrayOfPathsFromOutputTerminal, Exit);
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (0));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (0));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
if (unitID == outputTerminalID)
{
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageOutput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating output gain controls");
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageOutput);
featureUnitID = 0;
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageOutput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating output mute controls");
addMuteControl (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageOutput);
featureUnitID = 0;
done = TRUE;
}
}
} } } }
else
{ for (outputTerminalIndex = 0; outputTerminalIndex < numOutputTerminals; outputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalIndex), Exit);
if (0x101 == terminalType)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalID (&outputTerminalID, controlInterfaceNum, 0, outputTerminalIndex), Exit);
break; }
}
numOutputTerminalArrays = mControlGraph->getCount ();
for (pathsToOutputTerminalN = 0; pathsToOutputTerminalN < numOutputTerminalArrays; pathsToOutputTerminalN++)
{
playthroughCapable = false;
arrayOfPathsFromOutputTerminal = OSDynamicCast (OSArray, mControlGraph->getObject (pathsToOutputTerminalN));
FailIf (NULL == arrayOfPathsFromOutputTerminal, Exit);
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (0));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (0));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
if (unitID == outputTerminalID)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
playThroughPaths = getPlaythroughPaths ();
if (playThroughPaths)
{
playthroughCapable = true;
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - performing playthrough setup");
doPlaythroughSetup (usbAudioEngine, playThroughPaths, interfaceNum, altSettingNum);
playThroughPaths->release ();
}
numPathsFromOutputTerminal = arrayOfPathsFromOutputTerminal->getCount ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumSelectorUnits(&numSelectorUnits, controlInterfaceNum, 0), Exit);
if (numPathsFromOutputTerminal > 1 && numSelectorUnits)
{
numUnitsInPath = aPath->getCount ();
for (unitIndexInPath = 1; unitIndexInPath < numUnitsInPath; unitIndexInPath++)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (unitIndexInPath));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
if (SELECTOR_UNIT == subType)
{
if (kIOReturnSuccess == setSelectorSetting (unitID, 1))
{
selectorUnitID = unitID;
engineIndex = getEngineInfoIndex (usbAudioEngine);
if (-1 != engineIndex)
{
selection = (0xFF000000 & (pathsToOutputTerminalN << 24)) | (0x00FF0000 & (0 << 16)) | (0x0000FF00 & (selectorUnitID << 8)) | 1;
inputSelector = IOAudioSelectorControl::createInputSelector (selection, kIOAudioControlChannelIDAll, 0, engineIndex);
FailIf (NULL == inputSelector, Exit);
inputSelector->setValueChangeHandler (controlChangedHandler, this);
usbAudioEngine->addDefaultAudioControl (inputSelector);
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating input gain controls");
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
featureUnitID = 0;
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating input mute controls");
addMuteControl (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
featureUnitID = 0;
}
} } break; } }
if (NULL != inputSelector)
{
addSelectorSourcesToSelectorControl (inputSelector, arrayOfPathsFromOutputTerminal, pathsToOutputTerminalN, unitIndexInPath);
inputSelector->release ();
}
else
{
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating playthrough volume controls");
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
featureUnitID = 0;
}
}
} else
{
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Creating input volume control (no selectors)" );
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
featureUnitID = 0;
}
if ( false == playthroughCapable )
{
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Creating input mute control (no selectors)" );
addMuteControl (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
featureUnitID = 0;
}
}
}
break; }
}
}
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioDevice::doControlStuff(0x%x, %d, %d)", audioEngine, interfaceNum, altSettingNum);
return result;
}
IOReturn AppleUSBAudioDevice::doPlaythroughSetup (AppleUSBAudioEngine * usbAudioEngine, OSArray * playThroughPaths, UInt8 interfaceNum, UInt8 altSettingNum) {
OSArray * aPath;
OSNumber * theUnitIDNum;
OSString * nameString;
IOAudioSelectorControl * playThroughSelector;
OSDictionary * engineInfo;
UInt32 numPlayThroughPaths;
UInt32 pathIndex;
SInt32 engineInfoIndex;
UInt16 terminalType;
UInt8 numControls;
UInt8 channelNum;
UInt8 featureUnitID;
UInt8 inputTerminalID;
UInt8 controlInterfaceNum;
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
engineInfoIndex = getEngineInfoIndex (usbAudioEngine);
FailIf (-1 == engineInfoIndex, Exit);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex));
FailIf (NULL == engineInfo, Exit);
engineInfo->setObject (kPassThruPathsArray, playThroughPaths);
numPlayThroughPaths = playThroughPaths->getCount ();
if (numPlayThroughPaths > 1)
{
playThroughSelector = IOAudioSelectorControl::create (0, kIOAudioControlChannelIDAll, 0, engineInfoIndex, kIOAudioSelectorControlSubTypeInput, kIOAudioControlUsagePassThru);
FailIf (NULL == playThroughSelector, Exit);
playThroughSelector->setValueChangeHandler (controlChangedHandler, this);
usbAudioEngine->addDefaultAudioControl (playThroughSelector);
for (pathIndex = 0; pathIndex < numPlayThroughPaths; pathIndex++)
{
aPath = OSDynamicCast (OSArray, playThroughPaths->getObject (pathIndex));
FailIf (NULL == aPath, Exit);
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
inputTerminalID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getInputTerminalType (&terminalType, controlInterfaceNum, 0, inputTerminalID), Exit);
nameString = OSString::withCString (TerminalTypeString (terminalType));
FailIf (NULL == nameString, Exit);
playThroughSelector->addAvailableSelection (pathIndex, nameString);
nameString->release ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, featureUnitID), Exit);
for (channelNum = 0; channelNum < numControls; channelNum++)
{
setCurVolume (featureUnitID, channelNum, 0);
setCurMute (featureUnitID, channelNum, 0);
}
}
}
aPath = OSDynamicCast (OSArray, playThroughPaths->getObject (0));
FailIf (NULL == aPath, Exit);
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru);
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
addMuteControl (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru);
}
result = kIOReturnSuccess;
} else
{
aPath = OSDynamicCast (OSArray, playThroughPaths->getObject (0));
FailIf (NULL == aPath, Exit);
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsagePassThru, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru);
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsagePassThru, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
addMuteControl (usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru);
}
result = kIOReturnSuccess;
}
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::addSelectorSourcesToSelectorControl (IOAudioSelectorControl * theSelectorControl, OSArray * arrayOfPathsFromOutputTerminal, UInt32 pathsToOutputTerminalN, UInt8 selectorIndex) {
OSArray * aPath;
OSNumber * theUnitIDNum;
OSString * nameString;
UInt32 selectorSourceIndex;
UInt32 pathIndex;
UInt32 selection;
UInt8 numSelectorSources;
UInt8 selectorID;
UInt8 controlInterfaceNum;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (0));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (selectorIndex));
FailIf (NULL == theUnitIDNum, Exit);
selectorID = theUnitIDNum->unsigned8BitValue ();
pathIndex = 0;
FailIf (kIOReturnSuccess != mConfigDictionary->getNumSources (&numSelectorSources, controlInterfaceNum, 0, selectorID), Exit);
for (selectorSourceIndex = 0; selectorSourceIndex < numSelectorSources; selectorSourceIndex++)
{
nameString = getNameForPath (arrayOfPathsFromOutputTerminal, &pathIndex, selectorIndex + 1);
if (NULL != nameString)
{
selection = (0xFF000000 & (pathsToOutputTerminalN << 24)) | (0x00FF0000 & ((pathIndex - 1) << 16)) | (0x0000FF00 & (selectorID << 8)) | (0x000000FF & (selectorSourceIndex + 1));
theSelectorControl->addAvailableSelection (selection, nameString);
nameString->release ();
}
}
Exit:
return kIOReturnSuccess;
}
OSString * AppleUSBAudioDevice::getNameForPath (OSArray * arrayOfPathsFromOutputTerminal, UInt32 * pathIndex, UInt8 startingPoint) {
OSString * theString;
OSString * tempString;
OSArray * aPath;
OSNumber * theUnitIDNum;
UInt32 numElementsInPath;
UInt32 elementIndex;
UInt16 terminalType;
UInt8 unitID;
UInt8 subType;
UInt8 controlInterfaceNum;
Boolean done;
done = FALSE;
theString = NULL;
FailIf (NULL == mControlInterface, Exit);
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (*pathIndex));
FailIf (NULL == aPath, Exit);
numElementsInPath = aPath->getCount ();
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
for (elementIndex = startingPoint; elementIndex < numElementsInPath && FALSE == done; elementIndex++)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (elementIndex));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
switch (subType)
{
case INPUT_TERMINAL:
FailIf (kIOReturnSuccess != mConfigDictionary->getInputTerminalType (&terminalType, controlInterfaceNum, 0, unitID), Exit);
tempString = OSString::withCString (TerminalTypeString (terminalType));
FailIf (NULL == tempString, Exit);
if (!tempString->isEqualTo ("USB streaming"))
{
theString = OSString::withString (tempString);
}
tempString->release ();
(*pathIndex)++;
break;
case MIXER_UNIT:
theString = getNameForMixerPath (arrayOfPathsFromOutputTerminal, pathIndex, elementIndex);
done = TRUE;
break;
}
}
Exit:
return theString;
}
OSString * AppleUSBAudioDevice::getNameForMixerPath (OSArray * arrayOfPathsFromOutputTerminal, UInt32 * pathIndex, UInt8 startingPoint) {
char string[255];
OSString * theString;
OSString * tempString;
OSArray * aPath;
OSNumber * theUnitIDNum;
UInt32 numElementsInPath;
UInt32 mixerSourceIndex;
UInt32 elementIndex;
UInt8 numMixerSources;
UInt8 unitID;
UInt8 subType;
UInt8 controlInterfaceNum;
string[0] = 0;
FailIf (NULL == mControlInterface, Exit);
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (*pathIndex));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (startingPoint));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
numElementsInPath = aPath->getCount ();
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumSources (&numMixerSources, controlInterfaceNum, 0, unitID), Exit);
for (mixerSourceIndex = *pathIndex; mixerSourceIndex < *pathIndex + numMixerSources; )
{
for (elementIndex = startingPoint + 1; elementIndex < numElementsInPath; elementIndex++)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (elementIndex));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
switch (subType)
{
case INPUT_TERMINAL:
tempString = getNameForPath (arrayOfPathsFromOutputTerminal, &mixerSourceIndex, elementIndex);
if (NULL != tempString)
{
strncat (string, tempString->getCStringNoCopy (), 255);
strncat (string, " & ", 255);
tempString->release ();
}
break;
case MIXER_UNIT:
tempString = getNameForMixerPath (arrayOfPathsFromOutputTerminal, &mixerSourceIndex, elementIndex);
if (NULL != tempString)
{
strncat (string, tempString->getCStringNoCopy (), 255);
tempString->release ();
}
break;
}
}
}
*pathIndex = mixerSourceIndex;
if (strlen (string) > 3)
{
string[strlen (string) - 3] = 0;
}
Exit:
theString = OSString::withCString (string);
return theString;
}
void AppleUSBAudioDevice::addVolumeControls (AppleUSBAudioEngine * usbAudioEngine, UInt8 featureUnitID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage) {
OSArray * inputGainControlsArray;
OSArray * passThruVolControlsArray;
OSArray * outputVolControlsArray;
OSDictionary * engineInfo;
IOAudioLevelControl * theLevelControl;
IOFixed deviceMinDB;
IOFixed deviceMaxDB;
SInt32 engineInfoIndex;
SInt16 deviceCur;
SInt16 deviceMin;
SInt16 deviceMax;
UInt16 volRes;
SInt32 controlCur;
SInt32 controlMax;
SInt32 controlMin;
UInt8 channelNum;
UInt8 controlInterfaceNum;
UInt8 numControls;
bool extraStep = false;
debugIOLog ("+ AppleUSBAudioDevice::addVolumeControls (0x%x, %d, %d, %d, %u)", usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, usage);
engineInfoIndex = getEngineInfoIndex (usbAudioEngine);
FailIf (-1 == engineInfoIndex, Exit);
FailIf (NULL == mControlInterface, Exit);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex));
FailIf (NULL == engineInfo, Exit);
inputGainControlsArray = NULL;
passThruVolControlsArray = NULL;
outputVolControlsArray = NULL;
if ( (kIOAudioControlUsageOutput == usage)
&& (NULL != mMonoControlsArray))
{
mMonoControlsArray->release ();
mMonoControlsArray = NULL;
}
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, featureUnitID), Exit);
for (channelNum = 0; channelNum <= numControls; channelNum++)
{
extraStep = false;
if (mConfigDictionary->channelHasVolumeControl (controlInterfaceNum, 0, featureUnitID, channelNum))
{
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Creating volume controls for channel %d", this, channelNum);
FailIf (kIOReturnSuccess != getCurVolume (featureUnitID, channelNum, &deviceCur), Error);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - deviceCur = 0x%04x", this, deviceCur);
FailIf (kIOReturnSuccess != getMinVolume (featureUnitID, channelNum, &deviceMin), Error);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - deviceMin = 0x%04x", this, deviceMin);
FailIf (kIOReturnSuccess != getMaxVolume (featureUnitID, channelNum, &deviceMax), Error);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - deviceMax = 0x%04x", this, deviceMax);
getVolumeResolution (featureUnitID, channelNum, &volRes);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - volRes = 0x%04x", this, volRes);
FailIf (0 == volRes, Error);
if ( ( SInt16 ) kNegativeInfinity != deviceCur )
{
if ( ( deviceCur < deviceMin )
|| ( deviceCur > deviceMax ) )
{
debugIOLog ( "! AppleUSBAudioDevice::addVolumeControls () - deviceCur is not in volume range! Setting to deviceMin ..." );
deviceCur = deviceMin;
}
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Attempting to set volume to current volume ...", this);
FailIf (kIOReturnSuccess != setCurVolume (featureUnitID, channelNum, HostToUSBWord(deviceCur)), Error);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Volume was set successfully.", this);
}
if ( (SInt16) kNegativeInfinity == deviceMin )
{
debugIOLog ( "! AppleUSBAudioDevice[%p]::addVolumeControls () - device violates USB 2.0 audio spec Section 5.2.5.7.2! Setting deviceMin to 0x8001 ..." );
deviceMin = (SInt16) 0x8001;
extraStep = true;
}
deviceMinDB = ConvertUSBVolumeTodB (deviceMin);
deviceMaxDB = ConvertUSBVolumeTodB (deviceMax);
controlMin = 0;
controlMax = ( ( deviceMax - deviceMin ) / volRes ) + ( extraStep ? 1 : 0 );
if ( ( (SInt16) kNegativeInfinity == deviceCur )
|| ( deviceCur == deviceMin ) )
{
controlCur = 0;
}
else if ( deviceCur == deviceMax )
{
controlCur = controlMax;
}
else
{
controlCur = ( ( deviceCur - deviceMin ) / volRes );
}
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Creating control... [%d : %d : %d]", this, controlMin, controlCur, controlMax);
theLevelControl = IOAudioLevelControl::createVolumeControl (controlCur, controlMin, controlMax, deviceMinDB, deviceMaxDB, channelNum, 0, featureUnitID, usage);
FailIf (NULL == theLevelControl, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Created control %p", this, theLevelControl);
theLevelControl->setValueChangeHandler (controlChangedHandler, this);
usbAudioEngine->addDefaultAudioControl (theLevelControl);
switch (usage)
{
case kIOAudioControlUsageInput:
if (NULL == inputGainControlsArray)
{
inputGainControlsArray = OSArray::withObjects ((const OSObject **)&theLevelControl, 1);
}
else
{
inputGainControlsArray->setObject (theLevelControl);
}
break;
case kIOAudioControlUsagePassThru:
if (NULL == passThruVolControlsArray)
{
passThruVolControlsArray = OSArray::withObjects ((const OSObject **)&theLevelControl, 1);
}
else
{
passThruVolControlsArray->setObject (theLevelControl);
}
break;
case kIOAudioControlUsageOutput:
if (NULL == outputVolControlsArray)
{
outputVolControlsArray = OSArray::withObjects ((const OSObject **)&theLevelControl, 1);
}
else
{
outputVolControlsArray->setObject (theLevelControl);
}
if (mDeviceIsInMonoMode)
{
OSNumber *number = OSNumber::withNumber (channelNum, 8);
if (NULL == mMonoControlsArray)
{
mMonoControlsArray = OSArray::withObjects ((const OSObject **) &number, 1);
}
else
{
mMonoControlsArray->setObject (number);
}
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Added channel %d to mono controls array", this, channelNum);
number->release ();
}
break;
default:
debugIOLog ("! AppleUSBAudioDevice[%p]::addVolumeControls () - Control %p has an unknown usage!", this, theLevelControl);
}
theLevelControl->release ();
}
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Channel %d has no volume controls; skipping ...", this, channelNum);
}
goto NoError;
Error:
debugIOLog ("! AppleUSBAudioDevice[%p]::addVolumeControls () - Error creating controls for channel %d!", this, channelNum);
NoError:
debugIOLog ("? AppleUSBAudioDevice[%p]::addVolumeControls () - Done with channel %d", this, channelNum);
}
if (NULL != inputGainControlsArray)
{
engineInfo->setObject (kInputGainControls, inputGainControlsArray);
inputGainControlsArray->release ();
}
if (NULL != passThruVolControlsArray)
{
engineInfo->setObject (kPassThruVolControls, passThruVolControlsArray);
passThruVolControlsArray->release ();
}
if (NULL != outputVolControlsArray)
{
engineInfo->setObject (kOutputVolControls, outputVolControlsArray);
outputVolControlsArray->release ();
}
Exit:
debugIOLog ("- AppleUSBAudioDevice::addVolumeControls (0x%x, %d, %d, %d, %u)", usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, usage);
return;
}
void AppleUSBAudioDevice::addMuteControl (AppleUSBAudioEngine * usbAudioEngine, UInt8 featureUnitID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage)
{
OSArray * inputMuteControlsArray;
OSDictionary * engineInfo;
IOAudioToggleControl * theMuteControl;
SInt32 engineInfoIndex;
SInt16 deviceCur;
UInt8 channelNum;
UInt8 controlInterfaceNum;
UInt8 numControls;
IOReturn resultCode;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::addMuteControl ( %p, %d, %d, %d, 0%x )", this, usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, usage );
engineInfoIndex = getEngineInfoIndex ( usbAudioEngine );
FailIf ( -1 == engineInfoIndex, Exit );
FailIf ( NULL == mControlInterface, Exit );
engineInfo = OSDynamicCast ( OSDictionary, mRegisteredEngines->getObject ( engineInfoIndex ) );
FailIf ( NULL == engineInfo, Exit );
inputMuteControlsArray = NULL;
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf ( kIOReturnSuccess != mConfigDictionary->getNumControls ( &numControls, controlInterfaceNum, 0, featureUnitID ), Exit );
for ( channelNum = 0; channelNum <= numControls; channelNum++ )
{
if ( mConfigDictionary->channelHasMuteControl ( controlInterfaceNum, 0, featureUnitID, channelNum ) )
{
resultCode = getCurMute ( featureUnitID, channelNum, &deviceCur );
debugIOLog ( "? AppleUSBAudioDevice::addMuteControl () - channel %d, feature unit %d has current mute value 0x%x", channelNum, featureUnitID, deviceCur );
if ( ( 0 != deviceCur )
&& ( kIOAudioControlUsageInput == usage ) )
{
debugIOLog ("! AppleUSBAudioDevice::addMuteControl () - forcing channel %d of this device to unmute in hardware.", channelNum );
deviceCur = 0x0;
}
theMuteControl = IOAudioToggleControl::createMuteControl ( deviceCur, channelNum, 0, featureUnitID, usage );
FailIf ( NULL == theMuteControl, Exit );
setCurMute ( featureUnitID, channelNum, HostToUSBWord( deviceCur ) );
theMuteControl->setValueChangeHandler ( controlChangedHandler, this );
usbAudioEngine->addDefaultAudioControl ( theMuteControl );
switch (usage)
{
case kIOAudioControlUsageInput:
if ( NULL == inputMuteControlsArray )
{
inputMuteControlsArray = OSArray::withObjects ( ( const OSObject ** ) &theMuteControl, 1 );
}
else
{
inputMuteControlsArray->setObject ( theMuteControl );
}
break;
case kIOAudioControlUsagePassThru:
break;
case kIOAudioControlUsageOutput:
break;
}
theMuteControl->release ();
}
}
if ( NULL != inputMuteControlsArray )
{
engineInfo->setObject ( kInputMuteControls, inputMuteControlsArray );
inputMuteControlsArray->release ();
}
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::addMuteControl ( %p, %d, %d, %d, 0x%x )", this, usbAudioEngine, featureUnitID, interfaceNum, altSettingNum, usage );
return;
}
IOFixed AppleUSBAudioDevice::ConvertUSBVolumeTodB (SInt16 volume) {
IOFixed dBVolumeFixed;
if (volume == (SInt16)0x8000)
{
dBVolumeFixed = ((SInt16)0x8000 * 256) << 8; }
else
{
dBVolumeFixed = volume * 256;
}
return dBVolumeFixed;
}
IOReturn AppleUSBAudioDevice::getFeatureUnitRange (UInt8 controlSelector, UInt8 unitID, UInt8 channelNumber, UInt8 requestType, SubRange16 * target) {
IOReturn result;
IOUSBDevRequestDesc devReq;
struct {
UInt16 wNumSubRanges;
SubRange16 subRanges[1];
} theSetting;
IOBufferMemoryDescriptor * theSettingDesc = NULL;
UInt8 length = sizeof( theSetting );
result = kIOReturnError;
theSetting.subRanges[0].wMIN = 0;
theSetting.subRanges[0].wMAX = 0;
theSetting.subRanges[0].wRES = 0;
FailIf (NULL == target, Exit);
FailIf (NULL == mControlInterface, Exit);
theSettingDesc = IOBufferMemoryDescriptor::withOptions (kIODirectionIn, length);
FailIf (NULL == theSettingDesc, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = requestType;
devReq.wValue = (controlSelector << 8) | channelNumber;
devReq.wIndex = (0xFF00 & (unitID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = length;
devReq.pData = theSettingDesc;
result = deviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
memcpy (&theSetting, theSettingDesc->getBytesNoCopy (), length);
Exit:
if (NULL != theSettingDesc)
{
theSettingDesc->release ();
}
if (NULL != target)
{
if ( USBToHostWord (theSetting.wNumSubRanges) > 0 )
{
target->wMIN = USBToHostWord (theSetting.subRanges[0].wMIN);
target->wMAX = USBToHostWord (theSetting.subRanges[0].wMAX);
target->wRES = USBToHostWord (theSetting.subRanges[0].wRES);
}
}
return result;
}
IOReturn AppleUSBAudioDevice::getFeatureUnitSetting (UInt8 controlSelector, UInt8 unitID, UInt8 channelNumber, UInt8 requestType, SInt16 * target) {
IOReturn result;
IOUSBDevRequestDesc devReq;
UInt16 theSetting;
IOBufferMemoryDescriptor * theSettingDesc = NULL;
UInt8 length;
result = kIOReturnError;
theSetting = 0;
FailIf (NULL == target, Exit);
FailIf (NULL == mControlInterface, Exit);
switch (controlSelector)
{
case MUTE_CONTROL:
length = 1;
break;
case VOLUME_CONTROL:
length = 2;
break;
default:
length = 0;
}
theSettingDesc = IOBufferMemoryDescriptor::withOptions (kIODirectionIn, length);
FailIf (NULL == theSettingDesc, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = requestType;
devReq.wValue = (controlSelector << 8) | channelNumber;
devReq.wIndex = (0xFF00 & (unitID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = length;
devReq.pData = theSettingDesc;
result = deviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
memcpy (&theSetting, theSettingDesc->getBytesNoCopy (), length);
Exit:
if (NULL != theSettingDesc)
{
theSettingDesc->release ();
}
if (NULL != target)
{
*target = USBToHostWord (theSetting);
}
return result;
}
IOReturn AppleUSBAudioDevice::setFeatureUnitSetting (UInt8 controlSelector, UInt8 unitID, UInt8 channelNumber, UInt8 requestType, UInt16 newValue, UInt16 newValueLen) {
IOUSBDevRequestDesc devReq;
IOBufferMemoryDescriptor * theSettingDesc = NULL;
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
theSettingDesc = OSTypeAlloc (IOBufferMemoryDescriptor);
FailIf (NULL == theSettingDesc, Exit);
theSettingDesc->initWithBytes (&newValue, newValueLen, kIODirectionOut);
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface);
devReq.bRequest = requestType;
devReq.wValue = (controlSelector << 8) | channelNumber;
devReq.wIndex = (0xFF00 & (unitID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = newValueLen;
devReq.pData = theSettingDesc;
FailIf ((TRUE == isInactive()), DeviceInactive); result = deviceRequest (&devReq);
Exit:
if (NULL != theSettingDesc)
{
theSettingDesc->release ();
}
return result;
DeviceInactive:
debugIOLog("? AppleUSBAudioLevelControl::setFeatureUnitSetting () - ERROR attempt to send a device request to an inactive device");
goto Exit;
}
IOReturn AppleUSBAudioDevice::getCurMute (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
return getFeatureUnitSetting (MUTE_CONTROL, unitID, channelNumber, USBAUDIO_0200::CUR, target);
}
else
{
return getFeatureUnitSetting (MUTE_CONTROL, unitID, channelNumber, GET_CUR, target);
}
}
IOReturn AppleUSBAudioDevice::getCurVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
return getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, USBAUDIO_0200::CUR, target);
}
else
{
return getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, GET_CUR, target);
}
}
IOReturn AppleUSBAudioDevice::getMaxVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
SubRange16 subRange;
result = getFeatureUnitRange (VOLUME_CONTROL, unitID, channelNumber, USBAUDIO_0200::RANGE, &subRange);
if ( target )
{
memcpy ( target, &subRange.wMAX, 2 );
}
}
else
{
result = getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, GET_MAX, target);
}
return result;
}
IOReturn AppleUSBAudioDevice::getMinVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
SubRange16 subRange;
result = getFeatureUnitRange (VOLUME_CONTROL, unitID, channelNumber, USBAUDIO_0200::RANGE, &subRange);
if ( target )
{
memcpy ( target, &subRange.wMIN, 2 );
}
}
else
{
result = getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, GET_MIN, target);
}
return result;
}
IOReturn AppleUSBAudioDevice::getVolumeResolution (UInt8 unitID, UInt8 channelNumber, UInt16 * target) {
IOReturn result;
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
SubRange16 subRange;
result = getFeatureUnitRange (VOLUME_CONTROL, unitID, channelNumber, USBAUDIO_0200::RANGE, &subRange);
if ( target )
{
memcpy ( target, &subRange.wRES, 2 );
}
}
else
{
result = getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, GET_RES, (SInt16 *) target);
}
return result;
}
IOReturn AppleUSBAudioDevice::setCurVolume (UInt8 unitID, UInt8 channelNumber, SInt16 volume) {
return setFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, SET_CUR, volume, 2);
}
IOReturn AppleUSBAudioDevice::setCurMute (UInt8 unitID, UInt8 channelNumber, SInt16 mute) {
return setFeatureUnitSetting (MUTE_CONTROL, unitID, channelNumber, SET_CUR, mute, 1);
}
IOReturn AppleUSBAudioDevice::controlChangedHandler (OSObject * target, IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
AppleUSBAudioDevice * self;
result = kIOReturnError;
self = OSDynamicCast (AppleUSBAudioDevice, target);
FailIf (NULL == self, Exit);
result = self->protectedControlChangedHandler (audioControl, oldValue, newValue);
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::protectedControlChangedHandler (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
result = kIOReturnError;
switch (audioControl->getType ())
{
case kIOAudioControlTypeLevel:
result = doVolumeControlChange (audioControl, oldValue, newValue);
break;
case kIOAudioControlTypeToggle:
result = doToggleControlChange (audioControl, oldValue, newValue);
break;
case kIOAudioControlTypeSelector:
result = doSelectorControlChange (audioControl, oldValue, newValue);
break;
}
return result;
}
IOReturn AppleUSBAudioDevice::doSelectorControlChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
result = kIOReturnError;
switch (audioControl->getUsage ())
{
case kIOAudioControlUsageInput:
result = doInputSelectorChange (audioControl, oldValue, newValue);
break;
case kIOAudioControlUsageOutput:
break;
case kIOAudioControlUsagePassThru:
result = doPassThruSelectorChange (audioControl, oldValue, newValue);
break;
}
return result;
}
IOReturn AppleUSBAudioDevice::doVolumeControlChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
SInt16 newVolume;
SInt16 deviceMin;
SInt16 offset;
UInt16 volRes;
UInt8 unitID;
UInt8 channelNum;
debugIOLog ("+ AppleUSBAudioDevice[%p]::doVolumeControlChange( %p, 0x%x, 0x%x )", this, audioControl, oldValue, newValue);
unitID = audioControl->getControlID ();
channelNum = audioControl->getChannelID ();
result = kIOReturnError;
if ( (kIOAudioControlUsageInput == audioControl->getUsage())
|| (FALSE == mDeviceIsInMonoMode))
{
getMinVolume (unitID, channelNum, &deviceMin);
offset = -deviceMin;
if (newValue < 0)
{
newVolume = 0x8000;
}
else
{
getVolumeResolution (unitID, channelNum, &volRes);
if (newValue > 0)
{
newVolume = ((newValue - 1) * volRes) - offset;
}
else
{
newVolume = (newValue * volRes) - offset;
}
}
debugIOLog ("? AppleUSBAudioDevice[%p]::doVolumeControlChange () - Setting channel %d (unit %d) volume to 0x%x", this, channelNum, unitID, newVolume);
result = setCurVolume (unitID, channelNum, HostToUSBWord (newVolume));
}
else
{ UInt8 i;
FailIf (NULL == mMonoControlsArray, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::doVolumeControlChange () - Performing mono volume control change", this);
for (i = 0; i < mMonoControlsArray->getCount (); i++)
{
channelNum = ((OSNumber *) mMonoControlsArray->getObject(i))->unsigned8BitValue ();
getMinVolume (unitID, channelNum, &deviceMin);
offset = -deviceMin;
if (newValue < 0)
{
newVolume = 0x8000;
}
else
{
getVolumeResolution (unitID, channelNum, &volRes);
if (newValue > 0)
{
newVolume = ((newValue - 1) * volRes) - offset;
}
else
{
newVolume = (newValue * volRes) - offset;
}
}
result = setCurVolume (unitID, channelNum, HostToUSBWord (newVolume));
debugIOLog ("? AppleUSBAudioDevice[%p]::doVolumeControlChange () - Set volume for channel %d to 0x%x = %d", this, channelNum, newVolume, result);
}
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::doVolumeControlChange( %p, 0x%x, 0x%x ) = 0x%x", this, audioControl, oldValue, newValue, result);
return result;
}
IOReturn AppleUSBAudioDevice::doToggleControlChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
UInt8 unitID;
UInt8 channelNum;
unitID = audioControl->getControlID ();
channelNum = audioControl->getChannelID ();
result = setCurMute (unitID, channelNum, HostToUSBWord (newValue));
return result;
}
IOReturn AppleUSBAudioDevice::doPassThruSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
AppleUSBAudioEngine * usbAudioEngine;
OSArray * playThroughPaths;
OSArray * passThruVolControlsArray;
OSArray * thePath;
OSNumber * number;
OSDictionary * engineInfo;
UInt32 i;
UInt32 numPassThruControls;
UInt8 interfaceNum;
UInt8 altSetting;
UInt8 featureUnitID;
UInt8 pathIndex;
pathIndex = (newValue & 0x000000FF);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (audioControl->getControlID ()));
FailIf (NULL == engineInfo, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
FailIf (NULL == usbAudioEngine, Exit);
number = OSDynamicCast (OSNumber, engineInfo->getObject (kInterface));
FailIf (NULL == number, Exit);
interfaceNum = number->unsigned8BitValue ();
number = OSDynamicCast (OSNumber, engineInfo->getObject (kAltSetting));
FailIf (NULL == number, Exit);
altSetting = number->unsigned8BitValue ();
passThruVolControlsArray = OSDynamicCast (OSArray, engineInfo->getObject (kPassThruVolControls));
FailIf (NULL == passThruVolControlsArray, Exit);
numPassThruControls = passThruVolControlsArray->getCount ();
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
for (i = 0; i < numPassThruControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)passThruVolControlsArray->getObject (i));
}
passThruVolControlsArray->flushCollection ();
playThroughPaths = OSDynamicCast (OSArray, engineInfo->getObject (kPassThruPathsArray));
FailIf (NULL == playThroughPaths, Exit);
thePath = OSDynamicCast (OSArray, playThroughPaths->getObject (pathIndex));
FailIf (NULL == thePath, Exit);
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsagePassThru, interfaceNum, altSetting, kVolumeControl);
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSetting, kIOAudioControlUsagePassThru);
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
Exit:
return kIOReturnSuccess;
}
IOReturn AppleUSBAudioDevice::doInputSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
AppleUSBAudioEngine * usbAudioEngine;
OSArray * inputGainControlsArray;
OSArray * arrayOfPathsFromOutputTerminal;
OSArray * thePath;
OSNumber * number;
OSDictionary * engineInfo;
IOReturn result;
UInt32 i;
UInt32 numGainControls;
UInt8 interfaceNum;
UInt8 altSetting;
UInt8 featureUnitID;
UInt8 selectorUnitID;
UInt8 selectorPosition;
UInt8 pathsToOutputTerminal;
UInt8 pathIndex;
pathsToOutputTerminal = (newValue & 0xFF000000) >> 24;
pathIndex = (newValue & 0x00FF0000) >> 16;
selectorUnitID = (newValue & 0x0000FF00) >> 8;
selectorPosition = newValue & 0x000000FF;
result = setSelectorSetting (selectorUnitID, selectorPosition);
FailIf (kIOReturnSuccess != result, Exit);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (audioControl->getControlID ()));
FailIf (NULL == engineInfo, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
FailIf (NULL == usbAudioEngine, Exit);
number = OSDynamicCast (OSNumber, engineInfo->getObject (kInterface));
FailIf (NULL == number, Exit);
interfaceNum = number->unsigned8BitValue ();
number = OSDynamicCast (OSNumber, engineInfo->getObject (kAltSetting));
FailIf (NULL == number, Exit);
altSetting = number->unsigned8BitValue ();
inputGainControlsArray = OSDynamicCast (OSArray, engineInfo->getObject (kInputGainControls));
FailIf (NULL == inputGainControlsArray, Exit);
numGainControls = inputGainControlsArray->getCount ();
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
for (i = 0; i < numGainControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)inputGainControlsArray->getObject (i));
}
inputGainControlsArray->flushCollection ();
arrayOfPathsFromOutputTerminal = OSDynamicCast (OSArray, mControlGraph->getObject (pathsToOutputTerminal));
FailIf (NULL == arrayOfPathsFromOutputTerminal, Exit);
thePath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (pathIndex));
FailIf (NULL == thePath, Exit);
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsageInput, interfaceNum, altSetting, kVolumeControl);
addVolumeControls (usbAudioEngine, featureUnitID, interfaceNum, altSetting, kIOAudioControlUsageInput);
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
Exit:
return result;
}
OSArray * AppleUSBAudioDevice::getPlaythroughPaths () {
OSArray * arrayOfPathsFromOutputTerminal;
OSArray * playThroughPaths;
OSArray * aPath;
OSNumber * theUnitIDNum;
UInt32 numOutputTerminalArrays;
UInt32 numPathsFromOutputTerminal;
UInt32 pathsToOutputTerminalN;
UInt32 pathNumber;
UInt16 terminalType;
UInt8 controlInterfaceNum;
UInt8 unitID;
playThroughPaths = NULL;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
numOutputTerminalArrays = mControlGraph->getCount ();
for (pathsToOutputTerminalN = 0; pathsToOutputTerminalN < numOutputTerminalArrays; pathsToOutputTerminalN++)
{
arrayOfPathsFromOutputTerminal = OSDynamicCast (OSArray, mControlGraph->getObject (pathsToOutputTerminalN));
FailIf (NULL == arrayOfPathsFromOutputTerminal, Exit);
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (0));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (0));
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getOutputTerminalType (&terminalType, controlInterfaceNum, 0, unitID), Exit);
if (0x101 == terminalType) continue;
numPathsFromOutputTerminal = arrayOfPathsFromOutputTerminal->getCount ();
for (pathNumber = 0; pathNumber < numPathsFromOutputTerminal; pathNumber++)
{
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (pathNumber));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getInputTerminalType (&terminalType, controlInterfaceNum, 0, unitID), Exit);
if (terminalType != 0x101)
{
if (NULL == playThroughPaths)
{
playThroughPaths = OSArray::withObjects ((const OSObject **)&aPath, 1);
}
else
{
playThroughPaths->setObject (aPath);
}
}
}
}
Exit:
return playThroughPaths;
}
UInt8 AppleUSBAudioDevice::getBestFeatureUnitInPath (OSArray * thePath, UInt32 direction, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 controlTypeWanted) {
OSNumber * theUnitIDNum;
UInt32 numUnitsInPath;
UInt8 featureUnitID;
UInt8 unitIndex;
UInt8 controlInterfaceNum;
UInt8 unitID;
UInt8 subType;
UInt8 channelNum;
bool requireUniqueness = false;
UInt8 numChannels;
Boolean found;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::getBestFeatureUnitInPath (%p, %lu, %d, %d, %lu)", this, thePath, direction, interfaceNum, altSettingNum, controlTypeWanted );
featureUnitID = 0;
FailIf (NULL == mControlInterface, Exit);
FailIf (NULL == thePath, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
numUnitsInPath = thePath->getCount ();
found = FALSE;
switch (direction)
{
case kIOAudioControlUsagePassThru:
requireUniqueness = true;
case kIOAudioControlUsageInput:
for (unitIndex = numUnitsInPath - 2; unitIndex > 0; unitIndex--)
{
theUnitIDNum = OSDynamicCast (OSNumber, thePath->getObject (unitIndex));
if (NULL != theUnitIDNum)
{
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
if ( (FEATURE_UNIT == subType)
&& ( (false == requireUniqueness)
|| ( 1 == pathsContaining (unitID) ) ) )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumChannels (&numChannels, interfaceNum, altSettingNum), Exit);
for (channelNum = 0; channelNum <= numChannels; channelNum++)
{
switch (controlTypeWanted)
{
case kVolumeControl:
if (mConfigDictionary->channelHasVolumeControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
found = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
found = TRUE;
}
break;
} } } } else
{
debugIOLog ( "! AppleUSBAudioDevice::getBestFeatureUnitInPath () - something is wrong here!!!" );
}
} break;
case kIOAudioControlUsageOutput:
default:
debugIOLog ("? AppleUSBAudioDevice::getBestFeatureUnitInPath () - kIOAudioControlUsageOutput ");
for (unitIndex = 1; unitIndex < numUnitsInPath && !found; unitIndex++)
{
theUnitIDNum = OSDynamicCast (OSNumber, thePath->getObject (unitIndex));
if (NULL != theUnitIDNum)
{
unitID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
if (FEATURE_UNIT == subType)
{
debugIOLog ( " examining feature unit %d ...", unitID );
FailIf (kIOReturnSuccess != mConfigDictionary->getNumChannels (&numChannels, interfaceNum, altSettingNum), Exit);
for (channelNum = 0; channelNum <= numChannels; channelNum++)
{
switch (controlTypeWanted)
{
case kVolumeControl:
if (mConfigDictionary->channelHasVolumeControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
found = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
found = TRUE;
}
break;
} } } } else
{
debugIOLog ( "! AppleUSBAudioDevice::getBestFeatureUnitInPath () - something is wrong here!!!" );
}
} break;
}
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::getBestFeatureUnitInPath () = %d", this, featureUnitID );
return featureUnitID;
}
UInt8 AppleUSBAudioDevice::pathsContaining (UInt8 unitID)
{
OSArray * thisPathGroup = NULL;
OSArray * thisPath = NULL;
OSNumber * unitNumber = NULL;
UInt8 numPaths = 0;
if ( mControlGraph )
{
for ( UInt8 pathGroupIndex = 0; pathGroupIndex < mControlGraph->getCount(); pathGroupIndex++ )
{
thisPathGroup = OSDynamicCast ( OSArray, mControlGraph->getObject ( pathGroupIndex ) );
if ( thisPathGroup )
{
for (UInt8 pathIndex = 0; pathIndex < thisPathGroup->getCount(); pathIndex++ )
{
thisPath = OSDynamicCast ( OSArray, thisPathGroup->getObject (pathIndex) );
if ( thisPath )
{
for ( UInt8 unitIndex = 0; unitIndex < thisPath->getCount (); unitIndex++ )
{
unitNumber = OSDynamicCast ( OSNumber, thisPath->getObject (unitIndex) );
if ( unitID == unitNumber->unsigned8BitValue() )
{
numPaths++;
break;
}
}
}
}
}
}
}
return numPaths;
}
UInt8 AppleUSBAudioDevice::getSelectorSetting (UInt8 selectorID) {
IOUSBDevRequestDesc devReq;
IOReturn result;
UInt8 setting;
IOBufferMemoryDescriptor * settingDesc = NULL;
setting = 0;
FailIf (NULL == mControlInterface, Exit);
settingDesc = IOBufferMemoryDescriptor::withOptions (kIODirectionIn, 1);
FailIf (NULL == settingDesc, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() ) ? USBAUDIO_0200::CUR : GET_CUR;
devReq.wValue = 0;
devReq.wIndex = (0xFF00 & (selectorID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = 1;
devReq.pData = settingDesc;
result = deviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
memcpy (&setting, settingDesc->getBytesNoCopy (), 1);
Exit:
if (NULL != settingDesc)
{
settingDesc->release ();
}
return setting;
}
IOReturn AppleUSBAudioDevice::setSelectorSetting (UInt8 selectorID, UInt8 setting) {
IOUSBDevRequestDesc devReq;
IOReturn result;
IOBufferMemoryDescriptor * settingDesc = NULL;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
settingDesc = OSTypeAlloc (IOBufferMemoryDescriptor);
FailIf (NULL == settingDesc, Exit);
settingDesc->initWithBytes (&setting, 1, kIODirectionIn);
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface);
devReq.bRequest = SET_CUR;
devReq.wValue = 0;
devReq.wIndex = (0xFF00 & (selectorID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = 1;
devReq.pData = settingDesc;
result = deviceRequest (&devReq);
Exit:
if (NULL != settingDesc)
{
settingDesc->release ();
}
return result;
}
void AppleUSBAudioDevice::setMonoState (Boolean state)
{
mDeviceIsInMonoMode = state;
}
IOReturn AppleUSBAudioDevice::createControlsForInterface (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altSettingNum) {
AppleUSBAudioEngine * usbAudioEngine;
IOReturn result;
debugIOLog ("? AppleUSBAudioDevice[%p]::createControlsForInterface () - Interface %d alternate setting %d", this, interfaceNum, altSettingNum);
result = kIOReturnError;
mTerminatingDriver = FALSE;
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, audioEngine);
FailIf (NULL == usbAudioEngine, Exit);
doControlStuff (audioEngine, interfaceNum, altSettingNum);
Exit:
return result;
}
OSArray * AppleUSBAudioDevice::getOptimalClockPath ( AppleUSBAudioEngine * thisEngine, UInt8 streamInterface, UInt8 altSetting, UInt32 sampleRate, Boolean * otherEngineNeedSampleRateChange )
{
OSNumber * clockSourceIDNumber = NULL;
OSArray * pathGroupArray = NULL;
OSArray * pathArray = NULL;
OSArray * optimalPathArray = NULL;
UInt8 pathIndex;
UInt8 terminalID;
UInt8 clockSourceID;
UInt32 clockPathUnitUsage = 0xFFFFFFFF;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::getOptimalClockPath ( %d, %d, %d )", this, streamInterface, altSetting, sampleRate );
FailIf ( NULL == mConfigDictionary, Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getTerminalLink ( &terminalID, streamInterface, altSetting ), Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getClockSourceID ( &clockSourceID, mControlInterface->GetInterfaceNumber (), 0, terminalID ), Exit );
debugIOLog (" ? AppleUSBAudioDevice::getOptimalClockPath () - interface %d, alt setting %d, clock source ID %d", streamInterface, altSetting, clockSourceID );
for ( UInt8 pathGroupIndex = 0; pathGroupIndex < mClockGraph->getCount (); pathGroupIndex++ )
{
FailIf ( NULL == ( pathGroupArray = OSDynamicCast ( OSArray, mClockGraph->getObject ( pathGroupIndex ) ) ), Exit );
FailIf ( NULL == ( pathArray = OSDynamicCast ( OSArray, pathGroupArray->getObject ( 0 ) ) ), Exit );
FailIf ( NULL == ( clockSourceIDNumber = OSDynamicCast ( OSNumber, pathArray->getObject ( 0 ) ) ), Exit );
if ( clockSourceID == clockSourceIDNumber->unsigned8BitValue () )
{
break;
}
else
{
pathGroupArray = NULL;
}
}
FailIf ( NULL == pathGroupArray, Exit );
for ( pathIndex = 0; pathIndex < pathGroupArray->getCount (); pathIndex++ )
{
FailIf ( NULL == ( pathArray = OSDynamicCast ( OSArray, pathGroupArray->getObject ( pathIndex ) ) ), Exit );
if ( supportSampleRateInClockPath ( pathArray, sampleRate ) )
{
UInt32 usageCount = determineClockPathUnitUsage ( thisEngine, pathArray );
if ( usageCount < clockPathUnitUsage )
{
clockPathUnitUsage = usageCount;
optimalPathArray = pathArray;
}
if ( 0 == clockPathUnitUsage )
{
break;
}
}
}
Exit:
if ( NULL != otherEngineNeedSampleRateChange )
{
* otherEngineNeedSampleRateChange = ( clockPathUnitUsage > 0 );
}
debugIOLog ( "- AppleUSBAudioDevice[%p]::getOptimalClockPath ( %d, %d, %d ) = %p", this, streamInterface, altSetting, sampleRate, optimalPathArray );
return optimalPathArray;
}
Boolean AppleUSBAudioDevice::supportSampleRateInClockPath ( OSArray * pathArray, UInt32 sampleRate )
{
Boolean sampleRateSupported = false;
UInt8 numRange;
UInt8 rangeIndex;
SubRange32 subRange;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::supportSampleRateInClockPath ()", this );
FailIf ( kIOReturnSuccess != getNumSampleRatesForClockPath ( &numRange, pathArray ), Exit );
for ( rangeIndex = 0; rangeIndex < numRange; rangeIndex++ )
{
if ( kIOReturnSuccess == getIndexedSampleRatesForClockPath ( &subRange, pathArray, rangeIndex ) )
{
if ( 0 != subRange.dRES )
{
for ( UInt16 sampleRateIndex = 0; sampleRateIndex < ( ( subRange.dMAX - subRange.dMIN) / subRange.dRES ); sampleRateIndex++ )
{
if ( sampleRate == ( subRange.dMIN + sampleRateIndex * subRange.dRES ) )
{
sampleRateSupported = true;
break;
}
}
}
else
{
if ( ( sampleRate == subRange.dMIN ) || ( sampleRate == subRange.dMAX ) )
{
sampleRateSupported = true;
}
}
}
if ( sampleRateSupported )
{
break;
}
}
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::supportSampleRateInClockPath () = %d", this, sampleRateSupported );
return sampleRateSupported;
}
UInt32 AppleUSBAudioDevice::determineClockPathUnitUsage ( AppleUSBAudioEngine * thisEngine, OSArray * thisClockPath )
{
UInt32 usageCount = 0;
SInt32 engineIndex;
OSDictionary * otherAudioEngineInfo = NULL;
AppleUSBAudioEngine * otherAudioEngine = NULL;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::determineClockPathUnitUsage ( %p, %p )", this, thisEngine, thisClockPath );
if ( NULL != mRegisteredEngines )
{
for ( engineIndex = 0; ; engineIndex++ )
{
if ( NULL == ( otherAudioEngineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineIndex) ) ) )
{
break;
}
if ( NULL == ( otherAudioEngine = OSDynamicCast (AppleUSBAudioEngine, otherAudioEngineInfo->getObject (kEngine) ) ) )
{
break;
}
if (thisEngine != otherAudioEngine)
{
if ( NULL != otherAudioEngine->mActiveClockPath )
{
if ( clockPathCrossed ( thisClockPath, otherAudioEngine->mActiveClockPath ) )
{
usageCount++;
}
}
}
}
}
debugIOLog ( "+ AppleUSBAudioDevice[%p]::determineClockPathUnitUsage ( %p, %p ) = %d", this, thisEngine, thisClockPath, usageCount );
return usageCount;
}
Boolean AppleUSBAudioDevice::clockPathCrossed ( OSArray * clockPathA, OSArray * clockPathB )
{
OSNumber * clockIDNumberA = NULL;
OSNumber * clockIDNumberB = NULL;
Boolean pathCrossed = false;
for ( UInt8 pathItemA = 0; pathItemA < clockPathA->getCount(); pathItemA++ )
{
FailIf ( NULL == ( clockIDNumberA = OSDynamicCast ( OSNumber, clockPathA->getObject (pathItemA) ) ), Exit );
for ( UInt8 pathItemB = 0; pathItemB < clockPathB->getCount(); pathItemB++ )
{
FailIf ( NULL == ( clockIDNumberB = OSDynamicCast ( OSNumber, clockPathB->getObject (pathItemB) ) ), Exit );
if ( clockIDNumberA->unsigned8BitValue () == clockIDNumberB->unsigned8BitValue () )
{
pathCrossed = true;
break;
}
}
if ( pathCrossed )
{
break;
}
}
Exit:
return pathCrossed;
}
IOReturn AppleUSBAudioDevice::addSampleRatesFromClockSpace ()
{
IOReturn result = kIOReturnError;
OSNumber * clockSourceIDNumber = NULL;
OSNumber * streamInterfaceNumber = NULL;
OSArray * streamInterfaceNumbers = NULL;
OSArray * pathGroupArray = NULL;
OSArray * pathArray = NULL;
UInt8 streamInterface;
UInt8 numStreamInterfaces;
UInt8 numAltSettings;
UInt8 terminalID;
UInt8 clockSourceID;
bool startAtZero;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::addSampleRatesFromClockSpace ()", this );
FailIf ( NULL == mConfigDictionary, Exit );
FailIf ( NULL == mClockGraph, Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getControlledStreamNumbers ( &streamInterfaceNumbers, &numStreamInterfaces ), Exit );
for ( UInt8 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumbers->getCount (); streamInterfaceIndex++ )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, streamInterfaceNumbers->getObject ( streamInterfaceIndex ) ) ), Exit );
streamInterface = streamInterfaceNumber->unsigned8BitValue ();
startAtZero = mConfigDictionary->alternateSettingZeroCanStream ( streamInterface );
FailIf ( kIOReturnSuccess != mConfigDictionary->getNumAltSettings ( &numAltSettings, streamInterface ), Exit );
for ( UInt8 altSettingIndex = ( startAtZero ? 0 : 1 );
altSettingIndex < numAltSettings;
altSettingIndex++ )
{
FailIf ( kIOReturnSuccess != mConfigDictionary->getTerminalLink ( &terminalID, streamInterface, altSettingIndex ), Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getClockSourceID ( &clockSourceID, mControlInterface->GetInterfaceNumber (), 0, terminalID ), Exit );
debugIOLog (" ? AppleUSBAudioDevice::addSampleRatesFromClockSpace () - interface %d, alt setting %d, clock source ID %d", streamInterface, altSettingIndex, clockSourceID );
for ( UInt8 pathGroupIndex = 0; pathGroupIndex < mClockGraph->getCount (); pathGroupIndex++ )
{
FailIf ( NULL == ( pathGroupArray = OSDynamicCast ( OSArray, mClockGraph->getObject ( pathGroupIndex ) ) ), Exit );
FailIf ( NULL == ( pathArray = OSDynamicCast ( OSArray, pathGroupArray->getObject ( 0 ) ) ), Exit );
FailIf ( NULL == ( clockSourceIDNumber = OSDynamicCast ( OSNumber, pathArray->getObject ( 0 ) ) ), Exit );
if ( clockSourceID == clockSourceIDNumber->unsigned8BitValue () )
{
break;
}
else
{
pathGroupArray = NULL;
}
}
FailIf ( NULL == pathGroupArray, Exit );
for ( UInt8 pathIndex = 0; pathIndex < pathGroupArray->getCount (); pathIndex++ )
{
FailIf ( NULL == ( pathArray = OSDynamicCast ( OSArray, pathGroupArray->getObject ( pathIndex ) ) ), Exit );
FailIf ( kIOReturnSuccess != addSampleRatesFromClockPath ( pathArray, streamInterface, altSettingIndex ), Exit );
}
}
}
result = kIOReturnSuccess;
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::addSampleRatesFromClockSpace () = 0x%x", this, result );
return result;
}
IOReturn AppleUSBAudioDevice::addSampleRatesFromClockPath ( OSArray * path, UInt8 streamInterface, UInt8 altSetting )
{
IOReturn result = kIOReturnError;
OSNumber * clockSourceNumber;
OSArray * sampleRates;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::addSampleRatesFromClockPath ( %p, %d, %d )", this, path, streamInterface, altSetting );
FailIf ( NULL == path, Exit );
FailIf ( NULL == mConfigDictionary, Exit );
FailIf ( NULL == ( clockSourceNumber = OSDynamicCast ( OSNumber, path->getLastObject () ) ), Exit );
FailIf ( kIOReturnSuccess != getClockSourceSampleRates ( &sampleRates, clockSourceNumber->unsigned8BitValue () ), Exit );
FailIf ( kIOReturnSuccess != ( result = mConfigDictionary->addSampleRatesToStreamDictionary ( sampleRates, streamInterface, altSetting ) ), Exit );
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::addSampleRatesFromClockPath ( %p, %d, %d ) = 0x%x", this, path, streamInterface, altSetting, result );
return result;
}
IOReturn AppleUSBAudioDevice::getClockSourceSampleRates ( OSArray ** sampleRates, UInt8 clockSource )
{
IOReturn result = kIOReturnError;
OSNumber * sampleRateNumber = NULL;
SubRange32 subRange;
UInt32 sampleRate;
UInt16 numSampleRanges;
bool clockIsValid;
bool subRangeIsValid;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::getClockSourceSampleRates ( %p, %d )", this, sampleRates, clockSource );
FailIf ( NULL == mConfigDictionary, Exit );
FailIf ( NULL == sampleRates, Exit );
FailIf ( 0 == clockSource, Exit );
* sampleRates = NULL;
if ( mConfigDictionary->clockSourceHasFrequencyControl ( mControlInterface->GetInterfaceNumber (), 0, clockSource ) )
{
FailIf ( kIOReturnSuccess != ( result = getNumClockSourceSamplingFrequencySubRanges ( clockSource, &numSampleRanges ) ), Exit ) ;
for ( UInt8 sampleRangeIndex = 0; sampleRangeIndex < numSampleRanges; sampleRangeIndex++ )
{
FailIf ( kIOReturnSuccess != ( result = getIndexedClockSourceSamplingFrequencySubRange ( clockSource, &subRange, sampleRangeIndex ) ), Exit );
subRangeIsValid = ( ( subRange.dMIN <= subRange.dMAX )
&& ( ( 0 == subRange.dRES )
|| ( 0 == ( subRange.dMAX - subRange.dMIN ) % subRange.dRES ) ) );
if ( ! subRangeIsValid )
{
debugIOLog ( "! AppleUSBAudioDevice[%p]::getClockSourceSampleRates () - invalid subrange, skipping ...", this );
debugIOLog ( " subRange.dMIN = %lu", subRange.dMIN );
debugIOLog ( " subRange.dMAX = %lu", subRange.dMAX );
debugIOLog ( " subRange.dRES = %lu", subRange.dRES );
continue;
}
FailWithAction ( NULL == ( sampleRateNumber = OSNumber::withNumber ( subRange.dMIN, SIZEINBITS( sizeof ( UInt32 ) ) ) ), result = kIOReturnError, Exit );
if ( * sampleRates )
{
(* sampleRates)->setObject ( sampleRateNumber );
}
else
{
* sampleRates = OSArray::withObjects ( ( const OSObject ** ) &sampleRateNumber, 1 );
}
sampleRateNumber->release ();
sampleRateNumber = NULL;
if ( 0 != subRange.dRES )
{
for ( UInt16 sampleRateIndex = 0; sampleRateIndex < ( ( subRange.dMAX - subRange.dMIN) / subRange.dRES ) - 1; sampleRateIndex++ )
{
sampleRate = subRange.dMIN + ( 1 + sampleRateIndex ) * subRange.dRES;
FailWithAction ( NULL == ( sampleRateNumber = OSNumber::withNumber ( sampleRate, SIZEINBITS( sizeof ( UInt32 ) ) ) ), result = kIOReturnError, Exit );
(* sampleRates)->setObject ( sampleRateNumber );
sampleRateNumber->release ();
sampleRateNumber = NULL;
}
}
if ( subRange.dMAX != subRange.dMIN )
{
FailWithAction ( NULL == ( sampleRateNumber = OSNumber::withNumber ( subRange.dMAX, SIZEINBITS( sizeof ( UInt32 ) ) ) ), result = kIOReturnError, Exit );
(* sampleRates)->setObject ( sampleRateNumber );
sampleRateNumber->release ();
sampleRateNumber = NULL;
}
}
}
else
{
FailIf ( kIOReturnSuccess != ( result = getCurClockSourceSamplingFrequency ( clockSource, &sampleRate, &clockIsValid ) ), Exit );
FailWithAction ( NULL == ( sampleRateNumber = OSNumber::withNumber ( sampleRate, SIZEINBITS( sizeof ( UInt32 ) ) ) ), result = kIOReturnError, Exit );
* sampleRates = OSArray::withObjects ( ( const OSObject ** ) &sampleRateNumber, 1 );
sampleRateNumber->release ();
sampleRateNumber = NULL;
}
result = kIOReturnSuccess;
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::getClockSourceSampleRates ( %p, %d ) = 0x%x", this, sampleRates, clockSource, result );
return result;
}
OSArray * AppleUSBAudioDevice::buildClockGraph ( UInt8 controlInterfaceNum )
{
OSArray * allClockPaths = NULL;
OSArray * terminalClockEntities = NULL;
OSArray * pathsFromClockEntityN = NULL;
OSArray * thisPath = NULL;
OSArray * thisGroup = NULL;
OSNumber * clockIDNum = NULL;
UInt8 clockID;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::buildClockGraph ( %d )", this, controlInterfaceNum );
allClockPaths = OSArray::withCapacity ( 1 );
FailIf ( NULL == allClockPaths, Exit );
pathsFromClockEntityN = OSArray::withCapacity ( 1 );
FailIf ( NULL == pathsFromClockEntityN, Exit );
FailIf ( NULL == ( terminalClockEntities = mConfigDictionary->getTerminalClockEntities ( controlInterfaceNum, 0 ) ), Exit );
for ( UInt8 clockIndex = 0; clockIndex < terminalClockEntities->getCount (); clockIndex++)
{
FailIf ( NULL == ( clockIDNum = OSDynamicCast ( OSNumber, terminalClockEntities->getObject ( clockIndex ) ) ), Exit );
clockID = clockIDNum->unsigned8BitValue ();
debugIOLog ( "? AppleUSBAudioDevice[%p]::buildClockGraph () - Building clock paths from ID %d", this, clockID );
buildClockPath (controlInterfaceNum, clockID, pathsFromClockEntityN, thisPath);
allClockPaths->setObject ( pathsFromClockEntityN );
pathsFromClockEntityN->release ();
pathsFromClockEntityN = OSArray::withCapacity ( 1 );
FailIf ( NULL == pathsFromClockEntityN, Exit );
}
char pathLine[256];
char tempString[10];
debugIOLog ( "? AppleUSBAudioDevice[%p]::buildClockGraph ( %d ) - Displaying graph ...", this, controlInterfaceNum, allClockPaths->getCount() );
for ( UInt8 groupIndex = 0; ( allClockPaths && groupIndex < allClockPaths->getCount () ); groupIndex++ )
{
debugIOLog (" Path Group # %d", groupIndex );
FailIf ( NULL == ( thisGroup = OSDynamicCast ( OSArray, allClockPaths->getObject ( groupIndex ) ) ), Exit );
for ( UInt8 pathIndex = 0; pathIndex < thisGroup->getCount(); pathIndex++ )
{
* pathLine = '\0';
snprintf ( tempString, 10, "%2d: ", pathIndex );
strncat ( pathLine, tempString, 256 );
FailIf ( NULL == ( thisPath = OSDynamicCast ( OSArray, thisGroup->getObject ( pathIndex ) ) ), Exit );
for ( UInt8 pathItem = 0; pathItem < thisPath->getCount(); pathItem++ )
{
FailIf ( NULL == ( clockIDNum = ( OSNumber * ) thisPath->getObject ( pathItem ) ), Exit );
snprintf ( tempString, 10, "%d ", clockIDNum->unsigned8BitValue ());
strncat ( pathLine, tempString, 256 );
}
debugIOLog ( " %s", pathLine );
}
}
Exit:
if ( NULL != pathsFromClockEntityN )
{
pathsFromClockEntityN->release();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::buildClockGraph (%d) = %p", this, controlInterfaceNum, allClockPaths );
return allClockPaths;
}
OSArray * AppleUSBAudioDevice::buildClockPath ( UInt8 controlInterfaceNum, UInt8 startingUnitID, OSArray * allPaths, OSArray * startingPath )
{
OSArray * curPath = NULL;
OSArray * sourceArray = NULL;
OSNumber * arrayNumber = NULL;
OSNumber * thisUnitIDNum;
UInt8 thisUnitID;
UInt8 numSources;
UInt8 sourceID;
UInt8 subType;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::buildClockPath ( %d, %d, %p, %p )", controlInterfaceNum, startingUnitID, allPaths, startingPath );
FailIf ( NULL == mConfigDictionary, Exit );
thisUnitID = startingUnitID;
FailIf ( NULL == ( thisUnitIDNum = OSNumber::withNumber ( thisUnitID, 8 ) ), Exit);
if ( NULL != startingPath )
{
curPath = OSArray::withArray ( startingPath );
}
if ( NULL == curPath )
{
curPath = OSArray::withObjects ( ( const OSObject ** ) &thisUnitIDNum, 1 );
}
else
{
curPath->setObject ( thisUnitIDNum );
}
thisUnitIDNum->release ();
thisUnitIDNum = NULL;
FailIf ( kIOReturnSuccess != mConfigDictionary->getSubType ( &subType, controlInterfaceNum, 0, thisUnitID ), Exit );
while ( ( 0 != subType )
&& ( curPath )
&& ( USBAUDIO_0200::CLOCK_SOURCE != subType ) )
{
if ( USBAUDIO_0200::CLOCK_SELECTOR == subType )
{
debugIOLog ( " found clock selector @ ID %d", thisUnitID );
FailIf ( kIOReturnSuccess != mConfigDictionary->getNumSources ( &numSources, controlInterfaceNum, 0, thisUnitID ), Exit );
debugIOLog ( " found clock selector %d has %d sources", thisUnitID, numSources );
FailIf ( kIOReturnSuccess != mConfigDictionary->getSourceIDs ( &sourceArray, controlInterfaceNum, 0, thisUnitID ), Exit );
for ( UInt8 sourceIndex = 0; sourceIndex < numSources; sourceIndex++ )
{
FailIf ( NULL == sourceArray, Exit );
FailIf ( NULL == ( arrayNumber = OSDynamicCast ( OSNumber, sourceArray->getObject ( sourceIndex ) ) ), Exit);
buildClockPath ( controlInterfaceNum, arrayNumber->unsigned8BitValue(), allPaths, curPath );
}
subType = 0;
}
else
{
debugIOLog ( " found clock multiplier @ ID %d", thisUnitID );
if ( 1 != curPath->getCount () )
{
thisUnitIDNum = OSNumber::withNumber ( thisUnitID, 8 );
if ( NULL != thisUnitIDNum )
{
curPath->setObject ( thisUnitIDNum );
thisUnitIDNum->release ();
thisUnitIDNum = NULL;
}
}
FailIf (kIOReturnSuccess != mConfigDictionary->getSourceID ( &sourceID, controlInterfaceNum, 0, thisUnitID ), Exit );
thisUnitID = sourceID;
FailIf ( kIOReturnSuccess != mConfigDictionary->getSubType ( &subType, controlInterfaceNum, 0, thisUnitID ), Exit );
}
}
if ( USBAUDIO_0200::CLOCK_SOURCE == subType )
{
debugIOLog ( " found clock source @ ID %d", thisUnitID );
debugIOLog ( " adding path..." );
allPaths->setObject ( curPath );
}
Exit:
if ( curPath )
{
curPath->release ();
curPath = NULL;
}
debugIOLog ( "- AppleUSBAudioDevice[%p]::buildClockPath () = %p", curPath );
return curPath;
}
OSArray * AppleUSBAudioDevice::BuildConnectionGraph (UInt8 controlInterfaceNum)
{
OSArray * allOutputTerminalPaths = NULL;
OSArray * pathsFromOutputTerminalN = NULL;
OSArray * thisPath = NULL;
UInt8 terminalIndex;
UInt8 numTerminals;
UInt8 terminalID;
debugIOLog ("+ AppleUSBAudioDevice[%p]::BuildConnectionGraph (%d)", this, controlInterfaceNum);
allOutputTerminalPaths = OSArray::withCapacity (1);
FailIf (NULL == allOutputTerminalPaths, Exit);
pathsFromOutputTerminalN = OSArray::withCapacity (1);
FailIf (NULL == pathsFromOutputTerminalN, Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getNumOutputTerminals (&numTerminals, controlInterfaceNum, 0), Exit);
for (terminalIndex = 0; terminalIndex < numTerminals; terminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalID (&terminalID, controlInterfaceNum, 0, terminalIndex), Exit);
BuildPath (controlInterfaceNum, terminalID, pathsFromOutputTerminalN, thisPath);
allOutputTerminalPaths->setObject (pathsFromOutputTerminalN);
pathsFromOutputTerminalN->release ();
pathsFromOutputTerminalN = OSArray::withCapacity (1);
FailIf (NULL == pathsFromOutputTerminalN, Exit);
}
Exit:
if (NULL != pathsFromOutputTerminalN)
{
pathsFromOutputTerminalN->release();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::BuildConnectionGraph (%d) = %p", this, controlInterfaceNum, allOutputTerminalPaths);
return allOutputTerminalPaths;
}
OSArray * AppleUSBAudioDevice::BuildPath (UInt8 controlInterfaceNum, UInt8 startingUnitID, OSArray * allPaths, OSArray * startingPath) {
OSArray * curPath = NULL;
OSArray * tempPath = NULL;
OSArray * sourceArray = NULL;
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
OSNumber * thisUnitIDNum;
UInt8 unitID;
UInt32 i;
UInt8 thisUnitID;
UInt8 numSources;
UInt8 sourceID;
UInt8 startingSubType;
UInt8 subType;
UInt16 adcVersion;
FailIf (kIOReturnSuccess != mConfigDictionary->getADCVersion (&adcVersion), Exit);
thisUnitID = startingUnitID;
FailIf (NULL == (thisUnitIDNum = OSNumber::withNumber (thisUnitID, 8)), Exit);
if (NULL != startingPath)
{
curPath = OSArray::withArray (startingPath);
}
if (NULL == curPath)
{
curPath = OSArray::withObjects ((const OSObject **)&thisUnitIDNum, 1);
}
else
{
curPath->setObject (thisUnitIDNum);
}
thisUnitIDNum->release ();
thisUnitIDNum = NULL;
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, thisUnitID), Exit);
while (INPUT_TERMINAL != subType && subType != 0)
{
if (((kAUAUSBSpec1_0 == adcVersion) && ((MIXER_UNIT == subType) || (SELECTOR_UNIT == subType) || (EXTENSION_UNIT == subType) || (PROCESSING_UNIT == subType))) ||
((kAUAUSBSpec2_0 == adcVersion) && ((USBAUDIO_0200::MIXER_UNIT == subType) || (USBAUDIO_0200::SELECTOR_UNIT == subType) || (USBAUDIO_0200::EXTENSION_UNIT == subType) || (USBAUDIO_0200::PROCESSING_UNIT == subType))))
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumSources (&numSources, controlInterfaceNum, 0, thisUnitID), Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getSourceIDs (&sourceArray, controlInterfaceNum, 0, thisUnitID), Exit);
tempPath = OSArray::withArray (curPath);
for (i = 0; i < numSources; i++)
{
if (NULL == curPath)
{
curPath = OSArray::withCapacity (1);
}
FailIf (NULL == curPath, Exit);
FailIf (NULL == (arrayObject = sourceArray->getObject (i)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
curPath = BuildPath (controlInterfaceNum, arrayNumber->unsigned8BitValue(), allPaths, tempPath);
if (curPath && curPath->getCount ())
{
thisUnitIDNum = OSDynamicCast (OSNumber, curPath->getLastObject ());
FailIf (NULL == thisUnitIDNum, Exit);
unitID = thisUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, unitID), Exit);
if (unitID && subType == INPUT_TERMINAL)
{
allPaths->setObject (curPath);
}
}
if (curPath)
{
curPath->release ();
curPath = NULL;
}
}
tempPath->release ();
subType = 0;
}
else
{
FailIf (kIOReturnSuccess != mConfigDictionary->getSourceID (&sourceID, controlInterfaceNum, 0, thisUnitID), Exit);
thisUnitID = sourceID;
thisUnitIDNum = OSNumber::withNumber (thisUnitID, 8);
if (NULL != thisUnitIDNum)
{
curPath->setObject (thisUnitIDNum);
thisUnitIDNum->release ();
thisUnitIDNum = NULL;
}
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, thisUnitID), Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getSubType (&startingSubType, controlInterfaceNum, 0, startingUnitID), Exit);
if (subType == INPUT_TERMINAL && startingSubType == OUTPUT_TERMINAL)
{
allPaths->setObject (curPath);
}
}
}
Exit:
return curPath;
}
char * AppleUSBAudioDevice::TerminalTypeString (UInt16 terminalType)
{
char * terminalTypeString;
switch (terminalType) {
case 0x101: terminalTypeString = "USB streaming"; break;
#if LOCALIZABLE
case INPUT_UNDEFINED: terminalTypeString = "StringInputUndefined"; break;
case INPUT_MICROPHONE: terminalTypeString = "StringMicrophone"; break;
case INPUT_DESKTOP_MICROPHONE: terminalTypeString = "StringDesktopMicrophone"; break;
case INPUT_PERSONAL_MICROPHONE: terminalTypeString = "StringPersonalMicrophone"; break;
case INPUT_OMNIDIRECTIONAL_MICROPHONE: terminalTypeString = "StringOmnidirectionalMicrophone"; break;
case INPUT_MICROPHONE_ARRAY: terminalTypeString = "StringMicrophoneArray"; break;
case INPUT_PROCESSING_MICROPHONE_ARRAY: terminalTypeString = "StringProcessingMicrophoneArray"; break;
case INPUT_MODEM_AUDIO: terminalTypeString = "StringModemAudio"; break;
case OUTPUT_UNDEFINED: terminalTypeString = "StringOutputUndefined"; break;
case OUTPUT_SPEAKER: terminalTypeString = "StringSpeaker"; break;
case OUTPUT_HEADPHONES: terminalTypeString = "StringHeadphones"; break;
case OUTPUT_HEAD_MOUNTED_DISPLAY_AUDIO: terminalTypeString = "StringHeadMountedDisplayAudio"; break;
case OUTPUT_DESKTOP_SPEAKER: terminalTypeString = "StringDesktopSpeaker"; break;
case OUTPUT_ROOM_SPEAKER: terminalTypeString = "StringRoomSpeaker"; break;
case OUTPUT_COMMUNICATION_SPEAKER: terminalTypeString = "StringCommunicationSpeaker"; break;
case OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER: terminalTypeString = "StringLowFrequencyEffectsSpeaker"; break;
case BIDIRECTIONAL_UNDEFINED: terminalTypeString = "StringBidirectionalUndefined"; break;
case BIDIRECTIONAL_HANDSET: terminalTypeString = "StringBidirectionalHandset"; break;
case BIDIRECTIONAL_HEADSET: terminalTypeString = "StringBidirectionalHeadset"; break;
case BIDIRECTIONAL_SPEAKERPHONE_NO_ECHO_REDX: terminalTypeString = "StringBidirectionalSpeakerphoneNoEchoRedx"; break;
case BIDIRECTIONAL_ECHO_SUPPRESSING_SPEAKERPHONE: terminalTypeString = "StringBidirectionalEchoSuppressingSpeakerphone"; break;
case BIDIRECTIONAL_ECHO_CANCELING_SPEAKERPHONE: terminalTypeString = "StringBidirectionalEchoCancelingSpeakerphone"; break;
case TELEPHONY_UNDEFINED: terminalTypeString = "StringTelephoneUndefined"; break;
case TELEPHONY_PHONE_LINE: terminalTypeString = "StringTelephoneLine"; break;
case TELEPHONY_TELEPHONE: terminalTypeString = "StringTelephone"; break;
case TELEPHONY_DOWN_LINE_PHONE: terminalTypeString = "StringDownLinePhone"; break;
case EXTERNAL_UNDEFINED: terminalTypeString = "StringExternalUndefined"; break;
case EXTERNAL_ANALOG_CONNECTOR: terminalTypeString = "StringExternalAnalogConnector"; break;
case EXTERNAL_DIGITAL_AUDIO_INTERFACE: terminalTypeString = "StringExternalDigitalAudioInterface"; break;
case EXTERNAL_LINE_CONNECTOR: terminalTypeString = "StringExternalLineConnector"; break;
case EXTERNAL_LEGACY_AUDIO_CONNECTOR: terminalTypeString = "StringExternalLegacyAudioConnector"; break;
case EXTERNAL_SPDIF_INTERFACE: terminalTypeString = "StringExternalSPDIFInterface"; break;
case EXTERNAL_1394_DA_STREAM: terminalTypeString = "StringExternal1394DAStream"; break;
case EXTERNAL_1394_DV_STREAM_SOUNDTRACK: terminalTypeString = "StringExternal1394DVStreamSoundtrack"; break;
case EMBEDDED_UNDEFINED: terminalTypeString = "StringEmbeddedUndefined"; break;
case EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE: terminalTypeString = "StringEmbeddedLevelCalibrationNoiseSource"; break;
case EMBEDDED_EQUALIZATION_NOISE: terminalTypeString = "StringEmbeddedEqualizationNoise"; break;
case EMBEDDED_CD_PLAYER: terminalTypeString = "StringEmbeddedCDPlayer"; break;
case EMBEDDED_DAT: terminalTypeString = "StringEmbeddedDAT"; break;
case EMBEDDED_DCC: terminalTypeString = "StringEmbeddedDCC"; break;
case EMBEDDED_MINIDISK: terminalTypeString = "StringEmbeddedMiniDisc"; break;
case EMBEDDED_ANALOG_TAPE: terminalTypeString = "StringEmbeddedAnalogTape"; break;
case EMBEDDED_PHONOGRAPH: terminalTypeString = "StringEmbeddedPhonograph"; break;
case EMBEDDED_VCR_AUDIO: terminalTypeString = "StringEmbeddedVCRAudio"; break;
case EMBEDDED_VIDEO_DISC_AUDIO: terminalTypeString = "StringEmbeddedVideoDiscAudio"; break;
case EMBEDDED_DVD_AUDIO: terminalTypeString = "StringEmbeddedDVDAudio"; break;
case EMBEDDED_TV_TUNER_AUDIO: terminalTypeString = "StringEmbeddedTVTunerAudio"; break;
case EMBEDDED_SATELLITE_RECEIVER_AUDIO: terminalTypeString = "StringEmbeddedSatelliteReceiverAudio"; break;
case EMBEDDED_CABLE_TUNER_AUDIO: terminalTypeString = "StringEmbeddedCableTunerAudio"; break;
case EMBEDDED_DSS_AUDIO: terminalTypeString = "StringEmbeddedDSSAudio"; break;
case EMBEDDED_RADIO_RECEIVER: terminalTypeString = "StringEmbeddedRadioReceiver"; break;
case EMBEDDED_RADIO_TRANSMITTER: terminalTypeString = "StringEmbeddedRadioTransmitter"; break;
case EMBEDDED_MULTITRACK_RECORDER: terminalTypeString = "StringEmbeddedMultitrackRecorder"; break;
case EMBEDDED_SYNTHESIZER: terminalTypeString = "StringEmbeddedSynthesizer"; break;
default: terminalTypeString = "StringUnknown"; break;
#else
case INPUT_UNDEFINED: terminalTypeString = "InputUndefined"; break;
case INPUT_MICROPHONE: terminalTypeString = "Microphone"; break;
case INPUT_DESKTOP_MICROPHONE: terminalTypeString = "Desktop Microphone"; break;
case INPUT_PERSONAL_MICROPHONE: terminalTypeString = "Personal Microphone"; break;
case INPUT_OMNIDIRECTIONAL_MICROPHONE: terminalTypeString = "Omnidirectional Microphone"; break;
case INPUT_MICROPHONE_ARRAY: terminalTypeString = "Microphone Array"; break;
case INPUT_PROCESSING_MICROPHONE_ARRAY: terminalTypeString = "Processing Microphone Array"; break;
case INPUT_MODEM_AUDIO: terminalTypeString = "Modem Audio"; break;
case OUTPUT_UNDEFINED: terminalTypeString = "Output Undefined"; break;
case OUTPUT_SPEAKER: terminalTypeString = "Speaker"; break;
case OUTPUT_HEADPHONES: terminalTypeString = "Headphones"; break;
case OUTPUT_HEAD_MOUNTED_DISPLAY_AUDIO: terminalTypeString = "Head Mounted Display Audio"; break;
case OUTPUT_DESKTOP_SPEAKER: terminalTypeString = "Desktop Speaker"; break;
case OUTPUT_ROOM_SPEAKER: terminalTypeString = "Room Speaker"; break;
case OUTPUT_COMMUNICATION_SPEAKER: terminalTypeString = "Communication Speaker"; break;
case OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER: terminalTypeString = "Low Frequency Effects Speaker"; break;
case BIDIRECTIONAL_UNDEFINED: terminalTypeString = "Bidirectional Undefined"; break;
case BIDIRECTIONAL_HANDSET: terminalTypeString = "Bidirectional Handset"; break;
case BIDIRECTIONAL_HEADSET: terminalTypeString = "Bidirectional Headset"; break;
case BIDIRECTIONAL_SPEAKERPHONE_NO_ECHO_REDX: terminalTypeString = "Bidirectional Speakerphone No Echo Redx"; break;
case BIDIRECTIONAL_ECHO_SUPPRESSING_SPEAKERPHONE: terminalTypeString = "Bidirectional Echo Suppressing Speakerphone"; break;
case BIDIRECTIONAL_ECHO_CANCELING_SPEAKERPHONE: terminalTypeString = "Bidirectional Echo Canceling Speakerphone"; break;
case TELEPHONY_UNDEFINED: terminalTypeString = "Telephone Undefined"; break;
case TELEPHONY_PHONE_LINE: terminalTypeString = "Telephone Line"; break;
case TELEPHONY_TELEPHONE: terminalTypeString = "Telephone"; break;
case TELEPHONY_DOWN_LINE_PHONE: terminalTypeString = "Down Line Phone"; break;
case EXTERNAL_UNDEFINED: terminalTypeString = "External Undefined"; break;
case EXTERNAL_ANALOG_CONNECTOR: terminalTypeString = "External Analog Connector"; break;
case EXTERNAL_DIGITAL_AUDIO_INTERFACE: terminalTypeString = "External Digital Audio Interface"; break;
case EXTERNAL_LINE_CONNECTOR: terminalTypeString = "External Line Connector"; break;
case EXTERNAL_LEGACY_AUDIO_CONNECTOR: terminalTypeString = "External Legacy Audio Connector"; break;
case EXTERNAL_SPDIF_INTERFACE: terminalTypeString = "External SPDIF Interface"; break;
case EXTERNAL_1394_DA_STREAM: terminalTypeString = "External 1394 DA Stream"; break;
case EXTERNAL_1394_DV_STREAM_SOUNDTRACK: terminalTypeString = "External 1394 DV Stream Soundtrack"; break;
case EMBEDDED_UNDEFINED: terminalTypeString = "Embedded Undefined"; break;
case EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE: terminalTypeString = "Embedded Level Calibration Noise Source"; break;
case EMBEDDED_EQUALIZATION_NOISE: terminalTypeString = "Embedded Equalization Noise"; break;
case EMBEDDED_CD_PLAYER: terminalTypeString = "Embedded CD Player"; break;
case EMBEDDED_DAT: terminalTypeString = "Embedded DAT"; break;
case EMBEDDED_DCC: terminalTypeString = "Embedded DCC"; break;
case EMBEDDED_MINIDISK: terminalTypeString = "Embedded Mini Disc"; break;
case EMBEDDED_ANALOG_TAPE: terminalTypeString = "Embedded Analog Tape"; break;
case EMBEDDED_PHONOGRAPH: terminalTypeString = "Embedded Phonograph"; break;
case EMBEDDED_VCR_AUDIO: terminalTypeString = "Embedded VCR Audio"; break;
case EMBEDDED_VIDEO_DISC_AUDIO: terminalTypeString = "Embedded Video Disc Audio"; break;
case EMBEDDED_DVD_AUDIO: terminalTypeString = "Embedded DVD Audio"; break;
case EMBEDDED_TV_TUNER_AUDIO: terminalTypeString = "Embedded TV Tuner Audio"; break;
case EMBEDDED_SATELLITE_RECEIVER_AUDIO: terminalTypeString = "Embedded Satellite Receiver Audio"; break;
case EMBEDDED_CABLE_TUNER_AUDIO: terminalTypeString = "Embedded Cable Tuner Audio"; break;
case EMBEDDED_DSS_AUDIO: terminalTypeString = "Embedded DSS Audio"; break;
case EMBEDDED_RADIO_RECEIVER: terminalTypeString = "Embedded Radio Receiver"; break;
case EMBEDDED_RADIO_TRANSMITTER: terminalTypeString = "Embedded Radio Transmitter"; break;
case EMBEDDED_MULTITRACK_RECORDER: terminalTypeString = "Embedded Multitrack Recorder"; break;
case EMBEDDED_SYNTHESIZER: terminalTypeString = "Embedded Synthesizer"; break;
default: terminalTypeString = "Unknown"; break;
#endif
}
return terminalTypeString;
}
IOReturn AppleUSBAudioDevice::deviceRequest (IOUSBDevRequestDesc * request, IOUSBCompletion * completion) {
IOReturn result;
UInt32 timeout;
Boolean done;
result = kIOReturnSuccess;
FailIf (NULL == mInterfaceLock, Exit);
IORecursiveLockLock (mInterfaceLock);
if (FALSE == mTerminatingDriver)
{
done = FALSE;
timeout = 5;
while (!done && timeout && mControlInterface)
{
result = mControlInterface->DeviceRequest (request, completion);
if (result != kIOReturnSuccess)
{
timeout--;
IOSleep (1);
}
else
{
done = TRUE;
}
}
}
IORecursiveLockUnlock (mInterfaceLock);
#if LOGDEVICEREQUESTS
debugIOLog ("? AppleUSBAudioDevice[%p]::deviceRequest (%p, %p) = %lx", this, request, completion, result);
#endif
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::deviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion) {
IOReturn result;
UInt32 timeout;
Boolean done;
result = kIOReturnSuccess;
FailIf (NULL == mInterfaceLock, Exit);
IORecursiveLockLock (mInterfaceLock);
if (FALSE == mTerminatingDriver)
{
done = FALSE;
timeout = 5;
while (!done && timeout && mControlInterface)
{
result = mControlInterface->DeviceRequest (request, completion);
if (result != kIOReturnSuccess)
{
timeout--;
IOSleep (1);
}
else
{
done = TRUE;
}
}
}
IORecursiveLockUnlock (mInterfaceLock);
#if LOGDEVICEREQUESTS
debugIOLog ("? AppleUSBAudioDevice[%p]::deviceRequest (%p, %p) = %lx", this, request, completion, result);
#endif
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::deviceRequest (IOUSBDevRequest *request, AppleUSBAudioDevice * self, IOUSBCompletion *completion) {
IOReturn result;
UInt32 timeout;
Boolean done;
result = kIOReturnSuccess;
FailIf (NULL == self->mInterfaceLock, Exit);
IORecursiveLockLock (self->mInterfaceLock);
if (FALSE == self->mTerminatingDriver)
{
done = FALSE;
timeout = 5;
while (!done && timeout && self->mControlInterface)
{
result = self->mControlInterface->DeviceRequest (request, completion);
if (result != kIOReturnSuccess)
{
timeout--;
IOSleep (1);
}
else
{
done = TRUE;
}
}
}
IORecursiveLockUnlock (self->mInterfaceLock);
#if LOGDEVICEREQUESTS
debugIOLog ("? AppleUSBAudioDevice[%p]::deviceRequest (%p, %p) = %lx", self, request, completion, result);
#endif
Exit:
return result;
}
bool AppleUSBAudioDevice::willTerminate (IOService * provider, IOOptionBits options) {
debugIOLog ("+ AppleUSBAudioDevice[%p]::willTerminate (%p)", this, provider);
if (mControlInterface == provider)
{
mTerminatingDriver = TRUE;
}
debugIOLog ("- AppleUSBAudioDevice[%p]::willTerminate ()", this);
return super::willTerminate (provider, options);
}
void AppleUSBAudioDevice::setConfigurationApp (const char *bundleID) {
setConfigurationApplicationBundle (bundleID);
}
#ifdef DEBUG
void AppleUSBAudioDevice::retain() const
{
super::retain();
}
void AppleUSBAudioDevice::release() const
{
super::release();
}
#endif
bool AppleUSBAudioDevice::matchPropertyTable(OSDictionary * table, SInt32 *score)
{
bool returnValue = false;
OSObject * deviceName;
deviceName = table->getObject(kIOAudioDeviceNameKey);
if (deviceName)
{
if (getProperty (kIOAudioDeviceNameKey))
{
returnValue = true;
}
else
{
returnValue = false;
}
}
else
{
returnValue = super::matchPropertyTable (table, score);
}
if ( (deviceName)
&& (returnValue))
{
debugIOLog ("? AppleUSBAudioDevice[%p]::matchPropertyTable (%p, %p) = %d (custom dictionary match)",
this, table, score, returnValue);
}
return returnValue;
}
#pragma mark Anchored Time Stamps Methods
#if DEBUGANCHORS
void AppleUSBAudioDevice::accumulateAnchor (UInt64 anchorFrame, AbsoluteTime timeStamp)
{
UInt32 i;
if (mAnchorFrames[(kAnchorsToAccumulate - 1)] == 0ull)
{
for ( i = 0; i < kAnchorsToAccumulate ; i++)
{
if (0 == mAnchorFrames[i])
{
mAnchorFrames[i] = anchorFrame;
mAnchorTimes[i] = timeStamp;
break;
}
}
}
if (mAnchorFrames[(kAnchorsToAccumulate - 1)] != 0ull)
{
UInt64 time_nanos;
debugIOLog ("? AppleUSBAudioDevice::accumulateAnchor () - Frame # %d accumulated.", kAnchorsToAccumulate);
for (i = 0; i < kAnchorsToAccumulate ; i++)
{
absolutetime_to_nanoseconds (mAnchorTimes[i], &time_nanos);
debugIOLog (" - %llu \t %llu", mAnchorFrames[i], time_nanos);
}
for (i = 0; i < kAnchorsToAccumulate ; i++)
{
mAnchorFrames[i] = 0ull;
}
}
}
#endif
IOReturn AppleUSBAudioDevice::getAnchorFrameAndTimeStamp (UInt64 *frame, AbsoluteTime *time) {
AbsoluteTime finishTime;
AbsoluteTime offset;
AbsoluteTime curTime;
AbsoluteTime thisTime;
UInt64 thisFrame;
IOReturn result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
if (NULL == frame)
{
frame = &mNewReferenceUSBFrame;
}
if (NULL == time)
{
time = &mNewReferenceWallTime;
}
nanoseconds_to_absolutetime (1100000, &offset);
clock_get_uptime (&finishTime);
ADD_ABSOLUTETIME (&finishTime, &offset);
thisFrame = mControlInterface->GetDevice()->GetBus()->GetFrameNumber ();
do
{
clock_get_uptime (&curTime);
} while ( (mControlInterface)
&& (thisFrame == mControlInterface->GetDevice()->GetBus()->GetFrameNumber ())
&& (CMP_ABSOLUTETIME (&finishTime, &curTime) > 0));
clock_get_uptime (&thisTime);
FailIf (CMP_ABSOLUTETIME (&finishTime, &curTime) < 0, Exit); *frame = ++thisFrame;
*time = thisTime;
result = kIOReturnSuccess;
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::getFrameAndTimeStamp (UInt64 *frame, AbsoluteTime *time)
{
IOReturn result = kIOReturnError;
do
{
FailIf (NULL == mControlInterface, Exit);
*frame = mControlInterface->GetDevice()->GetBus()->GetFrameNumber ();
clock_get_uptime (time);
} while ( (mControlInterface)
&& (*frame != mControlInterface->GetDevice()->GetBus()->GetFrameNumber ()));
result = kIOReturnSuccess;
Exit:
return result;
}
UInt64 AppleUSBAudioDevice::getWallTimeInNanos (void)
{
AbsoluteTime time;
UInt64 timeInNanos;
clock_get_uptime (&time);
absolutetime_to_nanoseconds (time, &timeInNanos);
return timeInNanos;
}
UInt64 AppleUSBAudioDevice::jitterFilter (UInt64 invCoefficient, UInt64 prev, UInt64 curr)
{
UInt64 filteredValue;
if (0llu != invCoefficient)
{
filteredValue = curr + (invCoefficient - 1) * prev;
filteredValue += invCoefficient / 2;
filteredValue /= invCoefficient;
}
else
{
filteredValue = curr;
}
return filteredValue;
}
void AppleUSBAudioDevice::resetRateTimer ()
{
UInt64 time_nanos = 0ull;
mWallTimePerUSBCycle = 1000000ull * kWallTimeExtraPrecision;
if ( kIOReturnSuccess != getAnchorFrameAndTimeStamp (&mNewReferenceUSBFrame, &mNewReferenceWallTime) )
{
debugIOLog ( "! AppleUSBAudioDevice::resetRateTimer () - could not update anchor!" );
}
else
{
absolutetime_to_nanoseconds ( mNewReferenceWallTime, &time_nanos);
debugIOLog ( "! AppleUSBAudioDevice::resetRateTimer () - mNewReferenceUSBFrame = %llu, mNewReferenceWallTime (ns) = %llu", mNewReferenceUSBFrame, time_nanos );
}
}
void AppleUSBAudioDevice::updateWallTimePerUSBCycle ()
{
UInt64 currentUSBFrame;
UInt64 newWallTimePerUSBCycle;
AbsoluteTime time;
UInt64 time_nanos;
#if DEBUGTIMER
debugIOLog ("+ AppleUSBAudioDevice::updateWallTimePerUSBCycle ()");
#endif
FailIf (NULL == mControlInterface, Exit);
FailIf (kIOReturnSuccess != getFrameAndTimeStamp (¤tUSBFrame, &time), Exit);
if (0ull == mNewReferenceUSBFrame)
{
if (kIOReturnSuccess != getAnchorFrameAndTimeStamp (&mNewReferenceUSBFrame, &mNewReferenceWallTime))
{
debugIOLog ("! AppleUSBAudioDevice[%p]::updateWallTimePerUSBCycle () - Couldn't get a solid first anchor!", this);
mNewReferenceUSBFrame = currentUSBFrame;
mNewReferenceWallTime = time;
}
debugIOLog ("? AppleUSBAudioDevice[%p]::updateWallTimePerUSBCycle () - NOTICE: reference frame = %llu", this, mNewReferenceUSBFrame);
}
else
{
absolutetime_to_nanoseconds (time, &time_nanos);
}
if (0ull == mLastUSBFrame)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::updateWallTimePerUSBCycle () - NOTICE: initializing last USB frame and last wall time", this);
mLastUSBFrame = mNewReferenceUSBFrame;
absolutetime_to_nanoseconds (mNewReferenceWallTime, &mLastWallTime_nanos);
}
else
{
FailIf (currentUSBFrame == mLastUSBFrame, Exit);
newWallTimePerUSBCycle = (time_nanos - mLastWallTime_nanos) * kWallTimeExtraPrecision / (currentUSBFrame - mLastUSBFrame);
if (0ull == mWallTimePerUSBCycle)
{
mWallTimePerUSBCycle = newWallTimePerUSBCycle;
debugIOLog ("! NOTICE: Initializing mWallTimePerUSBCycle = %llu", mWallTimePerUSBCycle);
}
else
{
UInt64 a = 1024;
mWallTimePerUSBCycle = jitterFilter (a, mWallTimePerUSBCycle, newWallTimePerUSBCycle);
#if LOGWALLTIMEPERUSBCYCLE
debugIOLog ("? AppleUSBAudioDevice[%p]::updateWallTimePerUSBCycle - mWallTimePerUSBCycle * kExtraPrecision = %llu", this, mWallTimePerUSBCycle);
#endif
}
UInt64 max = kMaxWallTimePerUSBCycle * kWallTimeExtraPrecision;
UInt64 min = kMinWallTimePerUSBCycle * kWallTimeExtraPrecision;
if ( ( mWallTimePerUSBCycle > max )
|| ( mWallTimePerUSBCycle < min ) )
{
if ( mWallTimePerUSBCycle > max )
{
debugIOLog ( "! AppleUSBAudioDevice::updateWallTimePerUSBCycle () - mWallTimePerUSBCycle = %llu > %llu", mWallTimePerUSBCycle, max );
}
else
{
debugIOLog ( "! AppleUSBAudioDevice::updateWallTimePerUSBCycle () - mWallTimePerUSBCycle = %llu < %llu", mWallTimePerUSBCycle, min );
}
IOLog ( "WARNING: AppleUSBAudio has detected that clock_get_uptime () value changed radically from previous values\n" );
resetRateTimer();
}
mLastUSBFrame = currentUSBFrame;
mLastWallTime_nanos = time_nanos;
}
Exit:
#if DEBUGTIMER
debugIOLog ("- AppleUSBAudioDevice::updateWallTimePerUSBCycle ()");
#endif
return;
}
void AppleUSBAudioDevice::TimerAction (OSObject * owner, IOTimerEventSource * sender)
{
AppleUSBAudioDevice * self;
#if DEBUGTIMER
debugIOLog ("+ AppleUSBAudioDevice::TimerAction (%p, %p)", owner, sender);
#endif
FailIf (NULL == owner, Exit);
self = (AppleUSBAudioDevice *) owner;
FailIf (NULL == self, Exit);
self->doTimerAction ( sender );
Exit:
#if DEBUGTIMER
debugIOLog ("- AppleUSBAudioDevice::TimerAction ()");
#endif
return;
}
void AppleUSBAudioDevice::doTimerAction (IOTimerEventSource * timer)
{
#if DEBUGTIMER
debugIOLog ("+ AppleUSBAudioDevice::doTimerAction (%p)", timer);
#endif
FailIf (NULL == timer, Exit);
updateWallTimePerUSBCycle ();
mAnchorResetCount++;
if (mFailingAudioEngine)
{
debugIOLog ("! AppleUSBAudioDevice[%p]::doTimerAction () - Detected failing audio engine (%p)! Performing emergency format change.", this, mFailingAudioEngine);
formatChangeController (mFailingAudioEngine, NULL, NULL, NULL);
mFailingAudioEngine = NULL;
setSingleSampleRateDevice (true);
}
else if ( ( mEngineToRestart )
&& ( mEngineToRestart->mUSBStreamRunning ) )
{
debugIOLog ( "! AppleUSBAudioDevice[%p]::doTimerAction () - Restarting engine %p", this, mEngineToRestart );
mEngineToRestart->pauseAudioEngine();
mEngineToRestart->resumeAudioEngine();
mEngineToRestart = NULL;
}
if (mShouldAttemptDeviceRecovery)
{
attemptDeviceRecovery ();
mShouldAttemptDeviceRecovery = false;
}
if ( mAnchorResetCount >= kRefreshCount)
{
FailIf (NULL == mControlInterface, Exit);
if (kIOReturnSuccess == getAnchorFrameAndTimeStamp (&mNewReferenceUSBFrame, &mNewReferenceWallTime))
{
#if DEBUGTIMESTAMPS
UInt64 newReferenceWallTime_nanos;
absolutetime_to_nanoseconds (mNewReferenceWallTime, &newReferenceWallTime_nanos);
debugIOLog ("? AppleUSBAudioDevice::doTimerAction () - New anchor! mNewReferenceUSBFrame = %llu, mNewReferenceWallTime = %llu", mNewReferenceUSBFrame, newReferenceWallTime_nanos);
#endif
#if DEBUGANCHORS
accumulateAnchor (mNewReferenceUSBFrame, mNewReferenceWallTime);
#endif
}
else
{
#if DEBUGTIMESTAMPS
debugIOLog ("! AppleUSBAudioDevice::doTimerAction () - ERROR: Couldn't get new anchor! Keeping old anchor ...\n");
#endif
}
mAnchorResetCount = 0;
}
if (timer)
{
timer->setTimeoutMS ( kRefreshInterval );
}
Exit:
#if DEBUGTIMER
debugIOLog ("- AppleUSBAudioDevice::doTimerAction ()");
#endif
return;
}
#pragma mark Format Change Methods
UInt32 AppleUSBAudioDevice::formatChangeController (IOAudioEngine *audioEngine, IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate)
{
AppleUSBAudioEngine * thisAudioEngine = NULL;
AppleUSBAudioEngine * otherAudioEngine = NULL;
IOAudioStream * thisStream = NULL;
IOAudioStream * otherStream = NULL;
const IOAudioStreamFormat * thisFormat;
const IOAudioStreamFormat * otherFormat;
const IOAudioSampleRate * thisSampleRate;
const IOAudioSampleRate * otherSampleRate;
UInt32 result = kAUAFormatChangeError;
IOReturn formatChangeReturnCode = kIOReturnError;
UInt8 altSetting;
bool mustMatchFormats;
bool enginesPaused = false;
Boolean otherEngineNeedSampleRateChange = false;
debugIOLog ("+ AppleUSBAudioDevice[%p]::formatChangeController (%p, %p, %p, %p)", this, audioEngine, audioStream, newFormat, newSampleRate);
thisAudioEngine = (AppleUSBAudioEngine *) audioEngine;
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
if ( ( newFormat ) && ( newSampleRate ) )
{
getOptimalClockPath ( thisAudioEngine, (UInt8)(newFormat->fDriverTag >> 16), (UInt8)(newFormat->fDriverTag), newSampleRate->whole, &otherEngineNeedSampleRateChange );
}
}
mustMatchFormats = ( ( ( mRegisteredEngines)
&& ( 2 == mRegisteredEngines->getCount () )
&& ( ( true == mSingleSampleRateDevice )
|| ( NULL == audioStream ) ) )
|| ( true == otherEngineNeedSampleRateChange ) );
if (mustMatchFormats)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - Attempting to match this format with the format for the other stream interface.", this);
result = kAUAFormatChangeForceFailure;
if (NULL == thisAudioEngine)
{
FailIf (kIOReturnSuccess != getBothEngines (&thisAudioEngine, &otherAudioEngine), Exit);
}
else
{
otherAudioEngine = otherEngine (thisAudioEngine);
}
FailIf (NULL == thisAudioEngine, Exit);
FailIf (NULL == otherAudioEngine, Exit);
thisAudioEngine->pauseAudioEngine ();
otherAudioEngine->pauseAudioEngine ();
enginesPaused = true;
thisStream = thisAudioEngine->mMainStream;
otherStream = otherAudioEngine->mMainStream;
FailIf (NULL == thisStream, Exit);
FailIf (NULL == otherStream, Exit);
thisFormat = thisStream->getFormat ();
otherFormat = otherStream->getFormat ();
FailIf (NULL == thisFormat, Exit);
FailIf (NULL == otherFormat, Exit);
thisSampleRate = thisAudioEngine->getSampleRate ();
otherSampleRate = otherAudioEngine->getSampleRate ();
FailIf (NULL == thisSampleRate, Exit);
FailIf (NULL == otherSampleRate, Exit);
debugIOLog ("\n");
debugIOLog ("-------------------- BEFORE --------------------");
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - engine %p (interface %d, alternateSetting %d) info:", this, thisAudioEngine, thisAudioEngine->mInterfaceNumber, thisAudioEngine->mAlternateSettingID);
debugIOLog (" thisFormat = %p", thisFormat);
debugIOLog (" fNumChannels = %d", thisFormat->fNumChannels);
debugIOLog (" fBitDepth = %d", thisFormat->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", thisFormat->fDriverTag);
debugIOLog (" thisSampleRate->whole = %lu", thisSampleRate->whole);
debugIOLog ("\n");
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - engine %p (interface %d, alternateSetting %d) info:", this, otherAudioEngine, otherAudioEngine->mInterfaceNumber, otherAudioEngine->mAlternateSettingID);
debugIOLog (" otherFormat = %p", otherFormat);
debugIOLog (" fNumChannels = %d", otherFormat->fNumChannels);
debugIOLog (" fBitDepth = %d", otherFormat->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", otherFormat->fDriverTag);
debugIOLog (" otherSampleRate->whole = %lu", otherSampleRate->whole);
debugIOLog ("\n");
debugIOLog (" AppleUSBAudioDevice[%p]::formatChangeController () - newFormat = %p", this, newFormat);
if (newFormat)
{
debugIOLog (" fNumChannels = %d", newFormat->fNumChannels);
debugIOLog (" fBitDepth = %d", newFormat->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", newFormat->fDriverTag);
}
debugIOLog ( " AppleUSBAudioDevice[%p]::formatChangeController () - newSampleRate = %p", this, newSampleRate );
if ( newSampleRate )
{
debugIOLog (" whole = %d", newSampleRate->whole );
}
debugIOLog ("------------------------------------------------");
debugIOLog ("\n");
if ( ( false == mSingleSampleRateDevice ) && ( false == otherEngineNeedSampleRateChange ) )
{
if (kIOReturnSuccess == mConfigDictionary->getAltSettingWithSettings (&altSetting, thisAudioEngine->mInterfaceNumber, thisFormat->fNumChannels, thisFormat->fBitDepth, otherSampleRate->whole))
{
formatChangeReturnCode = thisAudioEngine->controlledFormatChange (NULL, NULL, otherSampleRate);
if (kIOReturnSuccess == formatChangeReturnCode)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - This engine (%p) sample rate changed successfully to %lu.", this, thisAudioEngine, otherSampleRate->whole);
result = kAUAFormatChangeForced;
thisAudioEngine->hardwareSampleRateChanged (otherSampleRate);
}
}
else if (kIOReturnSuccess == mConfigDictionary->getAltSettingWithSettings (&altSetting, otherAudioEngine->mInterfaceNumber, otherFormat->fNumChannels, otherFormat->fBitDepth, thisSampleRate->whole))
{
formatChangeReturnCode = otherAudioEngine->controlledFormatChange (NULL, NULL, thisSampleRate);
if (kIOReturnSuccess == formatChangeReturnCode)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - Other engine (%p) sample rate changed succsesfully to %lu.", this, otherAudioEngine, thisSampleRate->whole);
result = kAUAFormatChangeForced;
otherAudioEngine->hardwareSampleRateChanged (thisSampleRate);
}
}
else
{
debugIOLog ("! AppleUSBAudioDevice[%p]::formatChangeController () - Restoring both engines to their default settings.", this);
thisStream->setFormat ( &(thisAudioEngine->mDefaultAudioStreamFormat), false );
formatChangeReturnCode = thisAudioEngine->controlledFormatChange (thisStream, &(thisAudioEngine->mDefaultAudioStreamFormat), &(thisAudioEngine->mDefaultAudioSampleRate));
if (kIOReturnSuccess == formatChangeReturnCode)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - This engine (%p) restored to default settings succsesfully.", this, thisAudioEngine);
result = kAUAFormatChangeForced;
thisAudioEngine->hardwareSampleRateChanged (&(thisAudioEngine->mDefaultAudioSampleRate));
}
otherStream->setFormat ( &(otherAudioEngine->mDefaultAudioStreamFormat), false );
formatChangeReturnCode = otherAudioEngine->controlledFormatChange (otherStream, &(otherAudioEngine->mDefaultAudioStreamFormat), &(otherAudioEngine->mDefaultAudioSampleRate));
if (kIOReturnSuccess == formatChangeReturnCode)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - Other engine (%p) restored to default settings succsesfully.", this, otherAudioEngine);
otherAudioEngine->hardwareSampleRateChanged (&(otherAudioEngine->mDefaultAudioSampleRate));
}
else
{
result = kAUAFormatChangeForceFailure;
}
}
} else
{
if ( (newSampleRate)
&& (newSampleRate->whole != otherSampleRate->whole))
{
if (kIOReturnSuccess == mConfigDictionary->getAltSettingWithSettings (&altSetting, otherAudioEngine->mInterfaceNumber, otherFormat->fNumChannels, otherFormat->fBitDepth, newSampleRate->whole))
{
thisStream->setFormat ( newFormat, false );
formatChangeReturnCode = thisAudioEngine->controlledFormatChange (thisStream, newFormat, newSampleRate);
if (kIOReturnSuccess == formatChangeReturnCode)
{
result = kAUAFormatChangeForced;
thisAudioEngine->hardwareSampleRateChanged (newSampleRate);
formatChangeReturnCode = otherAudioEngine->controlledFormatChange (otherStream, otherFormat, newSampleRate);
if (kIOReturnSuccess != formatChangeReturnCode)
{
result = kAUAFormatChangeForceFailure;
}
else
{
otherAudioEngine->hardwareSampleRateChanged (newSampleRate);
}
}
}
else
{
debugIOLog ("! AppleUSBAudioDevice[%p]::formatChangeController () - Other audio engine (%p) does not support sample rate %lu at %d bit %d channel(s). Failing.",
this, otherAudioEngine, newSampleRate->whole, otherFormat->fBitDepth, otherFormat->fNumChannels);
result = kAUAFormatChangeForceFailure;
}
}
else
{
result = kAUAFormatChangeNormal;
thisStream->setFormat ( newFormat, false );
formatChangeReturnCode = (thisAudioEngine->controlledFormatChange (audioStream, newFormat, newSampleRate));
}
}
FailIf (NULL == thisAudioEngine, Exit);
FailIf (NULL == otherAudioEngine, Exit);
thisStream = thisAudioEngine->mMainStream;
otherStream = otherAudioEngine->mMainStream;
FailIf (NULL == thisStream, Exit);
FailIf (NULL == otherStream, Exit);
thisFormat = thisStream->getFormat ();
otherFormat = otherStream->getFormat ();
FailIf (NULL == thisFormat, Exit);
FailIf (NULL == otherFormat, Exit);
debugIOLog ("\n");
debugIOLog ("-------------------- AFTER --------------------");
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - engine %p (interface %d, alternateSetting %d) info:", this, thisAudioEngine, thisAudioEngine->mInterfaceNumber, thisAudioEngine->mAlternateSettingID);
debugIOLog (" thisFormat = %p", thisFormat);
debugIOLog (" fNumChannels = %d", thisFormat->fNumChannels);
debugIOLog (" fBitDepth = %d", thisFormat->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", thisFormat->fDriverTag);
debugIOLog (" thisSampleRate->whole = %lu", thisSampleRate->whole);
debugIOLog ("\n");
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - engine %p (interface %d, alternateSetting %d) info:", this, otherAudioEngine, otherAudioEngine->mInterfaceNumber, otherAudioEngine->mAlternateSettingID);
debugIOLog (" otherFormat = %p", otherFormat);
debugIOLog (" fNumChannels = %d", otherFormat->fNumChannels);
debugIOLog (" fBitDepth = %d", otherFormat->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", otherFormat->fDriverTag);
debugIOLog (" otherSampleRate->whole = %lu", otherSampleRate->whole);
debugIOLog ("-----------------------------------------------");
debugIOLog ("\n");
}
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - Attempting normal format change request.", this);
result = kAUAFormatChangeNormal;
formatChangeReturnCode = thisAudioEngine->controlledFormatChange (audioStream, newFormat, newSampleRate);
}
if (kIOReturnSuccess != formatChangeReturnCode)
{
result = kAUAFormatChangeError;
debugIOLog ("! AppleUSBAudioDevice[%p]::formatChangeController () - This format change failed with error 0x%x.", this, result);
}
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - This format change was successful.", this);
if ( (kAUAFormatChangeNormal != result)
&& (kAUAFormatChangeForced != result))
{
debugIOLog ("! AppleUSBAudioDevice[%p]::formatChangeController () - Forced format change failed.", this);
result = kAUAFormatChangeForceFailure;
}
}
Exit:
if (enginesPaused)
{
thisAudioEngine->resumeAudioEngine ();
otherAudioEngine->resumeAudioEngine ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::formatChangeController (%p, %p, %p, %p) = 0x%x", this, audioEngine, audioStream, newFormat, newSampleRate, result);
return result;
}
AppleUSBAudioEngine * AppleUSBAudioDevice::otherEngine (AppleUSBAudioEngine * thisEngine)
{
SInt32 engineIndex;
SInt32 otherEngineIndex;
OSDictionary * otherAudioEngineInfo = NULL;
AppleUSBAudioEngine * otherAudioEngine = NULL;
FailIf (NULL == thisEngine, Exit);
FailIf (NULL == mRegisteredEngines, Exit);
engineIndex = getEngineInfoIndex (thisEngine);
FailIf (-1 == engineIndex, Exit);
otherEngineIndex = ((1 == engineIndex) ? 0 : 1);
otherAudioEngineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (otherEngineIndex));
FailIf (NULL == otherAudioEngineInfo, Exit);
otherAudioEngine = OSDynamicCast (AppleUSBAudioEngine, otherAudioEngineInfo->getObject (kEngine));
FailIf (NULL == otherAudioEngine, Exit);
Exit:
return otherAudioEngine;
}
IOReturn AppleUSBAudioDevice::getBothEngines (AppleUSBAudioEngine ** firstEngine, AppleUSBAudioEngine ** secondEngine)
{
SInt32 engineIndex;
OSDictionary * firstAudioEngineInfo = NULL;
IOReturn result = kIOReturnError;
FailIf (NULL == mRegisteredEngines, Exit);
engineIndex = 0;
firstAudioEngineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineIndex));
FailIf (NULL == firstAudioEngineInfo, Exit);
*firstEngine = OSDynamicCast (AppleUSBAudioEngine, firstAudioEngineInfo->getObject (kEngine));
FailIf (NULL == *firstEngine, Exit);
*secondEngine = otherEngine (*firstEngine);
FailIf (NULL == secondEngine, Exit);
result = kIOReturnSuccess;
Exit:
return result;
}
#pragma mark Device Recovery
void AppleUSBAudioDevice::attemptDeviceRecovery ()
{
debugIOLog ("+ AppleUSBAudioDevice[%p]::attemptDeviceRecovery ()", this);
FailIf (NULL == mControlInterface, Exit);
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::attemptDeviceRecovery ()", this);
}
#pragma mark Clock Entity Requests
IOReturn AppleUSBAudioDevice::getClockSetting (UInt8 controlSelector, UInt8 unitID, UInt8 requestType, void * target, UInt16 length) {
IOReturn result;
IOUSBDevRequestDesc devReq;
UInt16 theSetting;
IOBufferMemoryDescriptor * theSettingDesc = NULL;
result = kIOReturnError;
theSetting = 0;
FailIf (NULL == target, Exit);
FailIf (NULL == mControlInterface, Exit);
theSettingDesc = IOBufferMemoryDescriptor::withOptions (kIODirectionIn, length);
FailIf (NULL == theSettingDesc, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBIn, kUSBClass, kUSBInterface);
devReq.bRequest = requestType;
devReq.wValue = (controlSelector << 8);
devReq.wIndex = (0xFF00 & (unitID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = length;
devReq.pData = theSettingDesc;
result = deviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
if (NULL != target)
{
memcpy (target, theSettingDesc->getBytesNoCopy (), length);
}
Exit:
if (NULL != theSettingDesc)
{
theSettingDesc->release ();
}
return result;
}
IOReturn AppleUSBAudioDevice::setClockSetting (UInt8 controlSelector, UInt8 unitID, UInt8 requestType, void * target, UInt16 length) {
IOUSBDevRequestDesc devReq;
IOBufferMemoryDescriptor * theSettingDesc = NULL;
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
theSettingDesc = OSTypeAlloc (IOBufferMemoryDescriptor);
FailIf (NULL == theSettingDesc, Exit);
theSettingDesc->initWithBytes (target, length, kIODirectionOut);
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface);
devReq.bRequest = requestType;
devReq.wValue = (controlSelector << 8);
devReq.wIndex = (0xFF00 & (unitID << 8)) | (0x00FF & mControlInterface->GetInterfaceNumber ());
devReq.wLength = length;
devReq.pData = theSettingDesc;
FailIf ((TRUE == isInactive()), DeviceInactive); result = deviceRequest (&devReq);
Exit:
if (NULL != theSettingDesc)
{
theSettingDesc->release ();
}
return result;
DeviceInactive:
debugIOLog("? AppleUSBAudioDevice::setClockSourceSetting () - ERROR attempt to send a device request to an inactive device");
goto Exit;
}
IOReturn AppleUSBAudioDevice::getNumClockSourceSamplingFrequencySubRanges (UInt8 unitID, UInt16 * numSubRanges) {
struct {
UInt16 wNumSubRanges;
SubRange32 SubRanges[1];
} rangeParameterBlock;
IOReturn result;
rangeParameterBlock.wNumSubRanges = 0;
result = kIOReturnError;
FailIf (NULL == numSubRanges, Exit);
result = getClockSetting (USBAUDIO_0200::CS_SAM_FREQ_CONTROL, unitID, USBAUDIO_0200::RANGE, &rangeParameterBlock, sizeof(rangeParameterBlock));
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != numSubRanges)
{
*numSubRanges = USBToHostWord (rangeParameterBlock.wNumSubRanges);
}
return result;
}
IOReturn AppleUSBAudioDevice::getIndexedClockSourceSamplingFrequencySubRange (UInt8 unitID, SubRange32 * subRange, UInt16 subRangeIndex) {
struct {
UInt16 wNumSubRanges;
SubRange32 SubRanges[1];
} rangeParameterBlock;
void * theRangeParameterBlock;
UInt32 theRangeParameterBlockLength;
SubRange32 * theSubRanges;
IOReturn result;
rangeParameterBlock.wNumSubRanges = 0;
theRangeParameterBlock = NULL;
result = kIOReturnError;
FailIf (NULL == subRange, Exit);
result = getClockSetting (USBAUDIO_0200::CS_SAM_FREQ_CONTROL, unitID, USBAUDIO_0200::RANGE, &rangeParameterBlock, sizeof(rangeParameterBlock));
FailIf (kIOReturnSuccess != result, Exit);
rangeParameterBlock.wNumSubRanges = USBToHostWord (rangeParameterBlock.wNumSubRanges);
result = kIOReturnError;
FailIf (subRangeIndex >= rangeParameterBlock.wNumSubRanges, Exit);
theRangeParameterBlockLength = 2 + (rangeParameterBlock.wNumSubRanges * sizeof(SubRange32));
theRangeParameterBlock = IOMalloc(theRangeParameterBlockLength);
FailIf (NULL == theRangeParameterBlock, Exit);
result = getClockSetting (USBAUDIO_0200::CS_SAM_FREQ_CONTROL, unitID, USBAUDIO_0200::RANGE, theRangeParameterBlock, theRangeParameterBlockLength);
FailIf (kIOReturnSuccess != result, Exit);
theSubRanges = (SubRange32 *)(((UInt8 *) theRangeParameterBlock) + 2);
subRange->dMIN = USBToHostLong (theSubRanges[subRangeIndex].dMIN);
subRange->dMAX = USBToHostLong (theSubRanges[subRangeIndex].dMAX);
subRange->dRES = USBToHostLong (theSubRanges[subRangeIndex].dRES);
Exit:
if (NULL != theRangeParameterBlock)
{
IOFree (theRangeParameterBlock, theRangeParameterBlockLength);
}
return result;
}
IOReturn AppleUSBAudioDevice::getCurClockSourceSamplingFrequency (UInt8 unitID, UInt32 * samplingFrequency, bool * validity) {
UInt32 clockFrequency;
Boolean clockValidity;
IOReturn result;
clockValidity = false;
result = getClockSetting (USBAUDIO_0200::CS_SAM_FREQ_CONTROL, unitID, USBAUDIO_0200::CUR, &clockFrequency, 4);
FailIf (kIOReturnSuccess != result, Exit);
result = getClockSetting (USBAUDIO_0200::CS_CLOCK_VALID_CONTROL, unitID, USBAUDIO_0200::CUR, &clockValidity, 1);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != samplingFrequency)
{
*samplingFrequency = USBToHostLong (clockFrequency);
}
if (NULL != validity)
{
*validity = clockValidity;
}
return result;
}
IOReturn AppleUSBAudioDevice::setCurClockSourceSamplingFrequency (UInt8 unitID, UInt32 samplingFrequency) {
UInt32 frequency;
frequency = USBToHostLong(samplingFrequency);
return setClockSetting (USBAUDIO_0200::CS_SAM_FREQ_CONTROL, unitID, USBAUDIO_0200::CUR, &frequency, 4);
}
IOReturn AppleUSBAudioDevice::getCurClockSelector (UInt8 unitID, UInt8 * selector) {
return getClockSetting (USBAUDIO_0200::CX_CLOCK_SELECTOR_CONTROL, unitID, USBAUDIO_0200::CUR, selector, 1);
}
IOReturn AppleUSBAudioDevice::setCurClockSelector (UInt8 unitID, UInt8 selector) {
return setClockSetting (USBAUDIO_0200::CX_CLOCK_SELECTOR_CONTROL, unitID, USBAUDIO_0200::CUR, &selector, 1);
}
IOReturn AppleUSBAudioDevice::getCurClockMultiplier (UInt8 unitID, UInt16 * numerator, UInt16 * denominator) {
UInt8 clockNumerator;
Boolean clockDenominator;
IOReturn result;
result = getClockSetting (USBAUDIO_0200::CM_NUMERATOR_CONTROL, unitID, USBAUDIO_0200::CUR, &clockNumerator, 2);
FailIf (kIOReturnSuccess != result, Exit);
result = getClockSetting (USBAUDIO_0200::CM_DENOMINATOR_CONTROL, unitID, USBAUDIO_0200::CUR, &clockDenominator, 2);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (NULL != numerator)
{
*numerator = USBToHostWord (clockNumerator);
}
if (NULL != denominator)
{
*denominator = USBToHostWord (clockDenominator);
}
return result;
}
#pragma mark Clock Path Sample Rates Discovery and Requests
IOReturn AppleUSBAudioDevice::getNumSampleRatesForClockPath (UInt8 * numSampleRates, OSArray * clockPath) {
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt8 clockID;
UInt8 subType;
UInt16 numSubRanges;
IOReturn result;
numSubRanges = 0;
result = kIOReturnError;
FailIf (NULL == numSampleRates, Exit);
FailIf (NULL == (arrayObject = clockPath->getLastObject ()), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
clockID = arrayNumber->unsigned8BitValue();
FailIf (kIOReturnSuccess != (result = mConfigDictionary->getSubType (&subType, mControlInterface->GetInterfaceNumber(), 0, clockID)), Exit);
if (USBAUDIO_0200::CLOCK_SOURCE == subType)
{
FailIf (kIOReturnSuccess != (result = getNumClockSourceSamplingFrequencySubRanges (clockID, &numSubRanges)), Exit);
}
Exit:
if (NULL != numSampleRates)
{
*numSampleRates = numSubRanges;
}
return result;
}
IOReturn AppleUSBAudioDevice::getIndexedSampleRatesForClockPath (SubRange32 * sampleRates, OSArray * clockPath, UInt32 rangeIndex) {
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt32 clockIndex;
UInt8 clockID;
UInt8 subType;
SubRange32 subRange;
UInt16 numerator;
UInt16 denominator;
IOReturn result;
subRange.dMIN = subRange.dMAX = subRange.dRES = 0;
result = kIOReturnError;
FailIf (NULL == sampleRates, Exit);
for (clockIndex = clockPath->getCount (); clockIndex > 0 ; clockIndex--)
{
FailIf (NULL == (arrayObject = clockPath->getObject (clockIndex - 1)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
clockID = arrayNumber->unsigned8BitValue();
FailIf (kIOReturnSuccess != (result = mConfigDictionary->getSubType (&subType, mControlInterface->GetInterfaceNumber(), 0, clockID)), Exit);
if (USBAUDIO_0200::CLOCK_SOURCE == subType)
{
FailIf (kIOReturnSuccess != (result = getIndexedClockSourceSamplingFrequencySubRange (clockID, &subRange, rangeIndex)), Exit);
}
else if (USBAUDIO_0200::CLOCK_MULTIPLIER == subType)
{
FailIf (kIOReturnSuccess != (result = getCurClockMultiplier (clockID, &numerator, &denominator)), Exit);
subRange.dMIN = subRange.dMIN * numerator / denominator;
subRange.dMAX = subRange.dMAX * numerator / denominator;
subRange.dRES = subRange.dRES * numerator / denominator;
}
}
Exit:
if (NULL != sampleRates)
{
*sampleRates = subRange;
}
return result;
}
IOReturn AppleUSBAudioDevice::getClockPathCurSampleRate (UInt32 * sampleRate, Boolean * validity, OSArray * clockPath) {
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt32 clockIndex;
UInt8 clockID;
UInt8 subType;
UInt32 clockRate;
bool clockValidity;
UInt16 numerator;
UInt16 denominator;
IOReturn result;
debugIOLog ("+ AppleUSBAudioDevice[%p]::getClockPathCurSampleRate", this);
clockRate = 0;
clockValidity = false;
result = kIOReturnError;
FailIf (NULL == sampleRate, Exit);
for (clockIndex = clockPath->getCount (); clockIndex > 0 ; clockIndex--)
{
FailIf (NULL == (arrayObject = clockPath->getObject (clockIndex - 1)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
clockID = arrayNumber->unsigned8BitValue();
FailIf (kIOReturnSuccess != (result = mConfigDictionary->getSubType (&subType, mControlInterface->GetInterfaceNumber(), 0, clockID)), Exit);
if (USBAUDIO_0200::CLOCK_SOURCE == subType)
{
FailIf (kIOReturnSuccess != (result = getCurClockSourceSamplingFrequency (clockID, &clockRate, &clockValidity)), Exit);
}
else if (USBAUDIO_0200::CLOCK_MULTIPLIER == subType)
{
FailIf (kIOReturnSuccess != (result = getCurClockMultiplier (clockID, &numerator, &denominator)), Exit);
clockRate = clockRate * numerator / denominator;
}
}
Exit:
if (NULL != sampleRate)
{
*sampleRate = clockRate;
}
if (NULL != validity)
{
*validity = clockValidity;
}
debugIOLog ("- AppleUSBAudioDevice[%p]::getClockPathCurSampleRate (%d, %d) = %d", this, clockRate, clockValidity, result);
return result;
}
IOReturn AppleUSBAudioDevice::setClockPathCurSampleRate (UInt32 sampleRate, OSArray * clockPath) {
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt32 clockIndex;
UInt8 clockID;
UInt8 subType;
UInt16 numerator;
UInt16 denominator;
OSArray * clockSourceIDs = NULL;
UInt32 clockSourceIndex;
UInt8 nextClockID;
IOReturn result;
debugIOLog ("+ AppleUSBAudioDevice[%p]::setClockPathCurSampleRate (%d)", this, sampleRate);
result = kIOReturnError;
for (clockIndex = 0; clockIndex < clockPath->getCount (); clockIndex++)
{
FailIf (NULL == (arrayObject = clockPath->getObject (clockIndex)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
clockID = arrayNumber->unsigned8BitValue();
FailIf (kIOReturnSuccess != (result = mConfigDictionary->getSubType (&subType, mControlInterface->GetInterfaceNumber(), 0, clockID)), Exit);
if (USBAUDIO_0200::CLOCK_SOURCE == subType)
{
FailIf (kIOReturnSuccess != (result = setCurClockSourceSamplingFrequency (clockID, sampleRate)), Exit);
break;
}
else if (USBAUDIO_0200::CLOCK_SELECTOR == subType)
{
FailIf (kIOReturnSuccess != (result = mConfigDictionary->getClockSelectorSources (&clockSourceIDs, mControlInterface->GetInterfaceNumber(), 0, clockID)), Exit);
FailIf (NULL == (arrayObject = clockPath->getObject (clockIndex + 1)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
nextClockID = arrayNumber->unsigned8BitValue();
for (clockSourceIndex = 0; clockSourceIndex < clockSourceIDs->getCount (); clockSourceIndex++)
{
FailIf (NULL == (arrayObject = clockSourceIDs->getObject (clockSourceIndex)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
if (arrayNumber->unsigned8BitValue() == nextClockID)
{
setCurClockSelector(clockID, clockSourceIndex + 1);
break;
}
}
}
else if (USBAUDIO_0200::CLOCK_MULTIPLIER == subType)
{
FailIf (kIOReturnSuccess != (result = getCurClockMultiplier (clockID, &numerator, &denominator)), Exit);
sampleRate = sampleRate * denominator / numerator;
}
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::setClockPathCurSampleRate (%d) = %d", this, sampleRate, result);
return result;
}
Generated by GNU enscript 1.6.4.