[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 (mInterruptEndpointMemoryDescriptor)
{
mInterruptEndpointMemoryDescriptor->release ();
mInterruptEndpointMemoryDescriptor = NULL;
}
if (mStatusInterruptBuffer)
{
IOFreeContiguous (mStatusInterruptBuffer, ( kAudioStatusWordFormat == mStatusInterruptBufferType ) ? sizeof (AudioStatusWordFormat) : sizeof (USBAUDIO_0200::InterruptDataMessageFormat) );
mStatusInterruptBuffer = NULL;
}
if (mInterfaceLock)
{
IORecursiveLockFree (mInterfaceLock);
mInterfaceLock = NULL;
}
if (mRegisteredEnginesMutex)
{
IORecursiveLockFree (mRegisteredEnginesMutex);
mRegisteredEnginesMutex = NULL;
}
if (mRegisteredStreamsMutex)
{
IORecursiveLockFree (mRegisteredStreamsMutex);
mRegisteredStreamsMutex = NULL;
}
if (mConfigDictionary)
{
mConfigDictionary->release ();
mConfigDictionary = NULL;
}
if (mRegisteredEngines)
{
mRegisteredEngines->release ();
mRegisteredEngines = NULL;
}
if (mRegisteredStreams)
{
mRegisteredStreams->release ();
mRegisteredStreams = NULL;
}
if ( 0 != mEngineArray )
{
for ( UInt32 engineIndex = 0; engineIndex < mEngineArray->getCount (); engineIndex++ )
{
AppleUSBAudioEngine * engine = OSDynamicCast ( AppleUSBAudioEngine, mEngineArray->getObject ( engineIndex ) );
if ( 0 != engine )
{
engine->release ();
}
}
mEngineArray->release ();
mEngineArray = 0;
}
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:
if ( !result )
{
stop ( provider );
}
debugIOLog ("- AppleUSBAudioDevice[%p]::start (%p) = result = %d", this, provider, result);
return result;
}
bool AppleUSBAudioDevice::initHardware (IOService * provider) {
bool result;
result = FALSE;
FailIf (NULL == mInitHardwareThread, Exit);
retain ();
if (TRUE == thread_call_enter1 (mInitHardwareThread, (void *)provider))
{
release ();
}
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);
}
aua->release (); 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;
OSObject * nameObject = NULL;
OSString * nameString = NULL;
OSString * localizedBundle = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::protectedInitHardware (%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 (getConfigurationDescriptor(), mControlInterface->GetInterfaceNumber()); FailIf (NULL == mConfigDictionary, Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - Successfully created configuration dictionary.", this);
if ( !mConfigDictionary->hasAudioStreamingInterfaces () )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - No audio streaming interfaces in configuration dictionary.", this);
goto Exit;
}
mInterfaceLock = IORecursiveLockAlloc ();
FailIf (NULL == mInterfaceLock, Exit);
mRegisteredEnginesMutex = IORecursiveLockAlloc ();
FailIf (NULL == mRegisteredEnginesMutex, Exit);
mRegisteredStreamsMutex = IORecursiveLockAlloc ();
FailIf (NULL == mRegisteredStreamsMutex, Exit);
mControlGraph = BuildConnectionGraph (mControlInterface->GetInterfaceNumber ());
FailIf ( NULL == mControlGraph, Exit );
FailIf ( 0 == mControlGraph->getCount (), 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;
debugIOLog ( "? AppleUSBAudioDevice[%p]::protectedInitHardware () - Trying to retrieve the USB Interface Name... ", this );
nameObject = mControlInterface->getProperty ( "USB Interface Name" );
if ( nameObject )
{
if ( NULL != ( nameString = OSDynamicCast ( OSString, nameObject ) ) )
{
debugIOLog ( "? AppleUSBAudioDevice[%p]::protectedInitHardware () - Retrieved product name %s from registry", this, nameString->getCStringNoCopy () );
strncpy ( string, nameString->getCStringNoCopy(), kStringBufferSize );
err = kIOReturnSuccess;
}
}
else
{
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
{
nameObject = NULL;
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 from registry", this, nameString->getCStringNoCopy () );
strncpy ( string, nameString->getCStringNoCopy(), kStringBufferSize );
err = kIOReturnSuccess;
}
}
else
{
debugIOLog ("! AppleUSBAudioDevice[%p]::protectedInitHardware () - There was no USB Product Name", this);
err = kIOReturnBadArgument;
}
}
}
if (0 == string[0] || kIOReturnSuccess != err)
{
strncpy (string, "Unknown USB Audio Device", kStringBufferSize);
}
setDeviceName (string);
err = kIOReturnError;
string[0] = 0;
nameObject = mControlInterface->GetDevice ()->getProperty ( "USB Vendor Name" );
if ( nameObject )
{
if ( NULL != ( nameString = OSDynamicCast ( OSString, nameObject ) ) )
{
debugIOLog ( "? AppleUSBAudioDevice[%p]::protectedInitHardware () - Retrieved vendor name %s from registry", this, nameString->getCStringNoCopy () );
strncpy ( string, nameString->getCStringNoCopy (), kStringBufferSize );
err = kIOReturnSuccess;
}
}
else
{
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);
localizedBundle = OSDynamicCast ( OSString, mControlInterface->getProperty ( kIOAudioDeviceLocalizedBundleKey ) );
if ( NULL == localizedBundle )
{
localizedBundle = OSDynamicCast ( OSString, mControlInterface->GetDevice()->getProperty ( kIOAudioDeviceLocalizedBundleKey ) );
}
if ( NULL != localizedBundle )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - setting kIOAudioDeviceLocalizedBundleKey property to %s", this, localizedBundle->getCStringNoCopy () );
setProperty ( kIOAudioDeviceLocalizedBundleKey, localizedBundle );
}
#if LOCALIZABLE
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::protectedInitHardware () - setting kIOAudioDeviceLocalizedBundleKey property to AppleUSBAudio.kext", this);
setProperty ( kIOAudioDeviceLocalizedBundleKey, "AppleUSBAudio.kext" );
}
#endif
resultCode = createAudioEngines ();
FailIf ( FALSE == resultCode, Exit );
resultCode = activateAudioEngines ();
FailIf ( FALSE == resultCode, Exit );
resultCode = super::initHardware (provider);
FailIf ( FALSE == resultCode, Exit );
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", this);
TimerAction ( this, mUpdateTimer);
mProcessStatusInterruptThread = thread_call_allocate ( ( thread_call_func_t )processStatusInterrupt, ( thread_call_param_t )this );
FailIf ( NULL == mProcessStatusInterruptThread, Exit );
checkForStatusInterruptEndpoint ();
IOService::registerService();
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::protectedInitHardware (%p)", this, provider);
return ( resultCode ? kIOReturnSuccess : kIOReturnError ); }
void AppleUSBAudioDevice::checkForStatusInterruptEndpoint( void )
{
IOUSBFindEndpointRequest interruptEndpoint;
UInt8 endpointAddress;
UInt8 controlInterfaceNum;
UInt32 messageLength;
debugIOLog ("+ AppleUSBAudioDevice[%p]::checkForStatusInterruptEndpoint ()", this);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
if ( mConfigDictionary->hasInterruptEndpoint ( controlInterfaceNum, 0 ) && ( kIOReturnSuccess == mConfigDictionary->getInterruptEndpointAddress( &endpointAddress, controlInterfaceNum, 0 ) ) )
{
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol () )
{
mStatusInterruptBufferType = kInterruptDataMessageFormat;
messageLength = sizeof(USBAUDIO_0200::InterruptDataMessageFormat);
}
else
{
mStatusInterruptBufferType = kAudioStatusWordFormat;
messageLength = sizeof(AudioStatusWordFormat);
}
interruptEndpoint.type = kUSBInterrupt;
interruptEndpoint.direction = kUSBIn; interruptEndpoint.maxPacketSize = messageLength;
interruptEndpoint.interval = 0xFF;
mInterruptPipe = mControlInterface->FindNextPipe ( NULL, &interruptEndpoint );
FailIf ( NULL == mInterruptPipe, Exit );
if ( NULL == mInterruptEndpointMemoryDescriptor )
{
mStatusInterruptBuffer = IOMallocContiguous ( messageLength, messageLength, NULL );
FailIf ( NULL == mStatusInterruptBuffer, Exit );
bzero ( mStatusInterruptBuffer, messageLength );
mInterruptEndpointMemoryDescriptor = IOMemoryDescriptor::withAddress ( mStatusInterruptBuffer, messageLength, kIODirectionIn ); FailIf ( NULL == mInterruptEndpointMemoryDescriptor, Exit );
}
mStatusInterruptCompletion.target = ( void * )this;
mStatusInterruptCompletion.action = statusInterruptHandler;
mStatusInterruptCompletion.parameter = NULL;
mInterruptPipe->retain ();
FailMessage ( kIOReturnSuccess != mInterruptPipe->Read ( mInterruptEndpointMemoryDescriptor, 0, 0, mInterruptEndpointMemoryDescriptor->getLength(), &mStatusInterruptCompletion ) );
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::checkForStatusInterruptEndpoint ()", this);
}
void AppleUSBAudioDevice::statusInterruptHandler( void * target, void * parameter, IOReturn status, UInt32 bufferSizeRemaining )
{
AppleUSBAudioDevice * self;
FailIf ( NULL == target, Exit );
self = ( AppleUSBAudioDevice * )target;
debugIOLog ("+ AppleUSBAudioDevice[%p]::statusInterruptHandler ()", self);
if ( kIOReturnAborted == status || self->isInactive () )
{
debugIOLog ("! AppleUSBAudioDevice[%p]::statusInterruptHandler () error from USB: 0x%X or IOService inactive: %u, NOT reposting read to interrupt pipe", self, status, self->isInactive ());
}
else
{
if ( kIOUSBPipeStalled == status )
{
debugIOLog ("! AppleUSBAudioDevice[%p]::statusInterruptHandler () clearing stall, reposting read to interrupt pipe", self);
self->mInterruptPipe->ClearPipeStall ( true );
}
else if ( kIOReturnSuccess != status )
{
debugIOLog ("! AppleUSBAudioDevice[%p]::statusInterruptHandler () error from USB: 0x%X, reposting read to interrupt pipe", self, status);
}
self->retain ();
if ( TRUE == thread_call_enter1 ( ( thread_call_t )self->mProcessStatusInterruptThread, ( thread_call_param_t )self ) )
{
self->release ();
}
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::statusInterruptHandler ()", self);
return;
}
void AppleUSBAudioDevice::processStatusInterrupt ( void * arg )
{
AppleUSBAudioDevice * self;
IOCommandGate * cg;
FailIf ( NULL == arg, Exit );
self = ( AppleUSBAudioDevice * )arg;
cg = self->getCommandGate ();
if ( cg )
{
cg->runAction ( self->runStatusInterruptTask, ( void * )0, ( void * )0 );
}
self->release ();
Exit:
return;
}
IOReturn AppleUSBAudioDevice::runStatusInterruptTask( OSObject * target, void * arg0, void * arg1, void * arg2, void * arg3 )
{
AppleUSBAudioDevice * self;
FailIf ( NULL == target, Exit );
self = ( AppleUSBAudioDevice * )target;
self->handleStatusInterrupt ();
Exit:
return kIOReturnSuccess;
}
void AppleUSBAudioDevice::handleStatusInterrupt ( void )
{
AudioStatusWordFormatPtr audioStatusWord;
USBAUDIO_0200::InterruptDataMessageFormatPtr interruptDataMessage;
UInt8 subType;
AppleUSBAudioEngine * currentEngine = NULL;
OSDictionary * currentEngineInfo = NULL;
IOUSBDevRequestDesc devReq;
OSSet * defaultAudioControls;
bool interruptPending = false;
bool originatedFromACInterface = false;
UInt8 bOriginator;
debugIOLog ("+ AppleUSBAudioDevice[%p]::handleStatusInterrupt ()", this);
FailIf ( NULL == mControlInterface, Exit );
if ( kAudioStatusWordFormat == mStatusInterruptBufferType )
{
audioStatusWord = ( AudioStatusWordFormatPtr )mStatusInterruptBuffer;
interruptPending = ( 0 != ( audioStatusWord->bStatusType & 0x80 ) );
originatedFromACInterface = ( 0 == ( audioStatusWord->bStatusType & 0x0F ) );
bOriginator = audioStatusWord->bOriginator;
}
else {
interruptDataMessage = ( USBAUDIO_0200::InterruptDataMessageFormatPtr )mStatusInterruptBuffer;
interruptPending = ( 0 == ( interruptDataMessage->bInfo & 0x1 ) ); originatedFromACInterface = ( 0 == ( interruptDataMessage->bInfo & 0x02 ) ) && ( ( interruptDataMessage->wIndex & 0xFF ) == mControlInterface->GetInterfaceNumber () );
bOriginator = (UInt8)( ( interruptDataMessage->wIndex >> 8 ) & 0xFF );
}
if ( interruptPending )
{
if ( originatedFromACInterface ) {
mConfigDictionary->getSubType ( &subType, mControlInterface->GetInterfaceNumber (), 0, bOriginator );
if ( ( FEATURE_UNIT == subType ) || ( SELECTOR_UNIT == subType ) ) {
FailIf ( NULL == mRegisteredEngines, Exit );
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 );
defaultAudioControls = currentEngine->copyDefaultAudioControls ();
controlHasChangedOnDevice ( bOriginator, defaultAudioControls );
defaultAudioControls->release ();
defaultAudioControls = NULL;
}
}
else if ( USBAUDIO_0200::CLOCK_SOURCE == subType )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::handleStatusInterrupt () - CLOCK_SOURCE : %d", this, bOriginator );
FailIf ( NULL == mRegisteredEngines, Exit );
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 );
currentEngine->updateClockStatus ( bOriginator );
}
}
}
}
if ( kAudioStatusWordFormat == mStatusInterruptBufferType )
{
devReq.bmRequestType = USBmakebmRequestType ( kUSBIn, kUSBClass, kUSBInterface );
devReq.bRequest = GET_STAT;
devReq.wValue = 0;
FailIf ( NULL == mControlInterface, Exit );
devReq.wIndex = ( 0xFF00 & ( bOriginator << 8 ) ) | ( 0x00FF & mControlInterface->GetInterfaceNumber () );
devReq.wLength = 0;
devReq.pData = NULL;
FailIf ( kIOReturnSuccess != deviceRequest ( &devReq ), Exit );
}
else
{
}
bzero ( mStatusInterruptBuffer, ( kAudioStatusWordFormat == mStatusInterruptBufferType ) ? sizeof (AudioStatusWordFormat) : sizeof (USBAUDIO_0200::InterruptDataMessageFormat) );
if ( mInterruptPipe )
{
FailMessage ( kIOReturnSuccess != mInterruptPipe->Read ( mInterruptEndpointMemoryDescriptor, 0, 0, mInterruptEndpointMemoryDescriptor->getLength (), &mStatusInterruptCompletion ) );
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::handleStatusInterrupt ()", this);
return;
}
void AppleUSBAudioDevice::controlHasChangedOnDevice ( UInt8 controlID, OSSet * defaultAudioControls )
{
UInt32 controlSubType;
SInt16 deviceCur;
SInt16 deviceMin;
SInt16 deviceMax;
UInt16 volRes;
SInt32 controlCur;
OSNumber * settingNumber = NULL;
UInt8 numControls;
UInt8 channelNum;
IOAudioControl * controlObject = NULL ;
OSCollectionIterator * controlsIterator = NULL;
controlsIterator = OSCollectionIterator::withCollection( defaultAudioControls );
if ( controlsIterator )
{
while ( NULL != ( controlObject = OSDynamicCast( IOAudioControl, controlsIterator->getNextObject () ) ) )
{
if ( controlID == ( ( UInt8 )controlObject->getControlID () & 0xFF ) ) {
controlSubType = 0;
controlSubType = controlObject->getSubType();
switch ( controlSubType )
{
case kIOAudioLevelControlSubTypeVolume:
FailIf ( NULL == mControlInterface, Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getNumControls ( &numControls, mControlInterface->GetInterfaceNumber (), 0, controlID ), Exit );
for ( channelNum = 0; channelNum <= numControls; channelNum++ )
{
if ( controlObject->getChannelID () == channelNum )
{
if ( mConfigDictionary->channelHasVolumeControl ( mControlInterface->GetInterfaceNumber (), 0, controlID, channelNum ) )
{
FailIf ( kIOReturnSuccess != getCurVolume ( controlID, channelNum, &deviceCur ), Exit );
FailIf ( kIOReturnSuccess != getMinVolume ( controlID, channelNum, &deviceMin ), Exit );
FailIf ( kIOReturnSuccess != getMaxVolume ( controlID, channelNum, &deviceMax ), Exit );
getVolumeResolution ( controlID, channelNum, &volRes );
FailIf ( 0 == volRes, Exit );
if ( ( (SInt16) kNegativeInfinity == deviceCur )
|| ( deviceCur == deviceMin ) )
{
controlCur = 0;
}
else
{
controlCur = ( ( deviceCur - deviceMin ) / volRes );
}
FailIf ( NULL == ( settingNumber = OSNumber::withNumber ( controlCur, SIZEINBITS(SInt32) ) ), Exit );
controlObject->hardwareValueChanged ( settingNumber );
settingNumber->release ();
settingNumber = NULL;
}
break; }
}
break;
case kIOAudioToggleControlSubTypeMute:
FailIf ( NULL == mControlInterface, Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getNumControls ( &numControls, mControlInterface->GetInterfaceNumber (), 0, controlID ), Exit );
for ( channelNum = 0; channelNum <= numControls; channelNum++ )
{
if ( controlObject->getChannelID () == channelNum )
{
if ( mConfigDictionary->channelHasMuteControl ( mControlInterface->GetInterfaceNumber (), 0, controlID, channelNum ) )
{
FailIf ( kIOReturnSuccess != getCurMute ( controlID, controlObject->getChannelID (), &deviceCur ), Exit );
FailIf ( NULL == ( settingNumber = OSNumber::withNumber ( deviceCur, SIZEINBITS(SInt16) ) ), Exit );
controlObject->hardwareValueChanged ( settingNumber );
settingNumber->release ();
settingNumber = NULL;
}
break; }
}
break;
case kIOAudioSelectorControlSubTypeInput:
if ( kIOAudioControlTypeSelector == controlObject->getType() )
{
UInt8 oldSelectorPosition;
UInt8 newSelectorPosition;
FailIf ( NULL == mControlInterface, Exit );
oldSelectorPosition = controlObject->getIntValue () & 0x000000FF;
newSelectorPosition = getSelectorSetting ( controlID );
if ( oldSelectorPosition != newSelectorPosition )
{
OSArray * availableSelections = OSDynamicCast ( OSArray, controlObject->getProperty ( kIOAudioSelectorControlAvailableSelectionsKey ) );
if ( NULL != availableSelections )
{
for ( UInt32 index = 0; index < availableSelections->getCount (); index++ )
{
OSDictionary * selectionDictionary = OSDynamicCast ( OSDictionary, availableSelections->getObject ( index ) );
if ( NULL != selectionDictionary )
{
OSNumber * selectionNumber = OSDynamicCast ( OSNumber, selectionDictionary->getObject ( kIOAudioSelectorControlSelectionValueKey ) );
if ( NULL != selectionNumber )
{
SInt32 selection = (SInt32)selectionNumber->unsigned32BitValue ();
if ( ( selection & 0x000000FF ) == newSelectorPosition )
{
debugIOLog ( "? AppleUSBAudioDevice[%p]::controlHasChangedOnDevice () - Switch input selector over to selection = 0x%x", this, selection );
controlObject->setValue ( selection );
break;
}
}
}
}
}
}
}
break;
} } } }
Exit:
controlsIterator->release ();
}
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);
if ( kIOReturnSuccess == mControlInterface->GetDevice()->message(kIOUSBMessageHubIsDeviceConnected, NULL, 0) )
{
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 ( NULL != mInterruptPipe )
{
mInterruptPipe->Abort ();
mInterruptPipe->release ();
mInterruptPipe = NULL;
}
if ( mProcessStatusInterruptThread )
{
thread_call_cancel ( mProcessStatusInterruptThread );
thread_call_free ( mProcessStatusInterruptThread );
mProcessStatusInterruptThread = NULL;
}
if (mUpdateTimer)
{
debugIOLog ("? AppleUSBAudioDevice[%p]::stop () - Cancelling time stamp rate timer ...", this);
mUpdateTimer->cancelTimeout ();
mUpdateTimer->disable();
}
if ( 0 != mEngineArray )
{
for ( UInt32 engineIndex = 0; engineIndex < mEngineArray->getCount (); engineIndex++ )
{
AppleUSBAudioEngine * engine = OSDynamicCast ( AppleUSBAudioEngine, mEngineArray->getObject ( engineIndex ) );
if ( 0 != engine )
{
engine->release ();
}
}
mEngineArray->release ();
mEngineArray = 0;
}
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);
}
bool AppleUSBAudioDevice::createAudioEngines (void) {
OSArray * streamNumberArray;
UInt8 numStreams;
OSNumber * streamInterfaceNumber;
UInt8 numStreamInterfaces;
bool result = false;
OSBoolean * useSingleAudioEngine = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::createAudioEngines ()", this);
FailIf (NULL == mControlInterface, Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getControlledStreamNumbers (&streamNumberArray, &numStreams), Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getNumStreamInterfaces (&numStreamInterfaces), Exit);
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - streamNumberArray = %p, numStreams = %lu, numStreamInterfaces = %lu", this, streamNumberArray, numStreams, numStreamInterfaces);
useSingleAudioEngine = OSDynamicCast ( OSBoolean, mControlInterface->getProperty ( "UseSingleAudioEngine" ) );
if (NULL != useSingleAudioEngine)
{
if (useSingleAudioEngine->isTrue())
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - Forced (via override kext) single audio engine", this);
FailMessage ( false == ( result = createAudioEngine ( streamNumberArray ) ) );
}
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - Forced (via override kext) separate audio engines", this);
for (UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < numStreamInterfaces; streamInterfaceIndex++)
{
FailIf (NULL == (streamInterfaceNumber = OSDynamicCast (OSNumber, streamNumberArray->getObject (streamInterfaceIndex))), Exit);
OSArray * streamInterfaceNumberArray = OSArray::withCapacity ( 1 );
FailIf ( 0 == streamInterfaceNumberArray, Exit );
streamInterfaceNumberArray->setObject ( streamInterfaceNumber );
result = createAudioEngine ( streamInterfaceNumberArray );
FailWithAction ( !result, streamInterfaceNumberArray->release (), Exit );
streamInterfaceNumberArray->release ();
}
}
}
else if (getMultipleAudioEngineDevice ())
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - Known devices that requires separate audio engines", this);
for (UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < numStreamInterfaces; streamInterfaceIndex++)
{
FailIf (NULL == (streamInterfaceNumber = OSDynamicCast (OSNumber, streamNumberArray->getObject (streamInterfaceIndex))), Exit);
OSArray * streamInterfaceNumberArray = OSArray::withCapacity ( 1 );
FailIf ( 0 == streamInterfaceNumberArray, Exit );
streamInterfaceNumberArray->setObject ( streamInterfaceNumber );
result = createAudioEngine ( streamInterfaceNumberArray );
FailWithAction ( !result, streamInterfaceNumberArray->release (), Exit );
streamInterfaceNumberArray->release ();
}
}
else
{
if (getSingleSampleRateDevice ())
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - Known single sample rate device", this);
FailMessage ( false == ( result = createAudioEngine ( streamNumberArray ) ) );
}
else
{
OSArray * commonSampleRatesStreamList = NULL;
OSArray * availableStreamsList = OSArray::withArray ( streamNumberArray );
FailIf ( 0 == availableStreamsList, Exit );
while ( NULL != ( commonSampleRatesStreamList = findStreamsWithCommonSampleRates ( availableStreamsList ) ) )
{
OSArray * compatibleEndpointsStreamList = NULL;
while ( NULL != ( compatibleEndpointsStreamList = findStreamsWithCompatibleEndpoints ( commonSampleRatesStreamList ) ) )
{
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol () )
{
OSArray * commonClockStreamList = NULL;
while ( NULL != ( commonClockStreamList = findStreamsWithCommonClocks ( compatibleEndpointsStreamList ) ) )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - USB Audio 2.0 device", this);
FailMessage ( false == ( result = createAudioEngine ( commonClockStreamList ) ) );
commonClockStreamList->release ();
if (!result) break;
}
}
else
{
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngines () - USB Audio 1.0 device", this);
FailMessage ( false == ( result = createAudioEngine ( compatibleEndpointsStreamList ) ) );
}
compatibleEndpointsStreamList->release ();
if (!result) break;
}
commonSampleRatesStreamList->release ();
if (!result) break;
}
availableStreamsList->release ();
}
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::createAudioEngines () - 0x%x", this, result);
return result;
}
bool AppleUSBAudioDevice::activateAudioEngines (void) {
bool result = true;
debugIOLog ("+ AppleUSBAudioDevice[%p]::activateAudioEngines ()", this);
if ( 0 != mEngineArray )
{
for ( UInt32 engineIndex = 0; engineIndex < mEngineArray->getCount (); engineIndex++ )
{
AppleUSBAudioEngine * engine = OSDynamicCast ( AppleUSBAudioEngine, mEngineArray->getObject ( engineIndex ) );
FailWithAction ( 0 == engine, result = false, Exit );
FailWithAction ( kIOReturnSuccess != activateAudioEngine ( engine ), result = false, Exit );
}
}
Exit:
if ( !result )
{
deactivateAllAudioEngines ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::activateAudioEngines () - 0x%x", this, result);
return result;
}
bool AppleUSBAudioDevice::createAudioEngine (OSArray * streamInterfaceNumberArray) {
AppleUSBAudioEngine * engine = NULL;
bool result = false;
debugIOLog ("+ AppleUSBAudioDevice[%p]::createAudioEngine ()", this );
FailIf ( NULL == streamInterfaceNumberArray, Exit );
#ifdef DEBUGLOGGING
debugIOLog ("? AppleUSBAudioDevice[%p]::createAudioEngine () - create audio engine with stream interfaces:", this );
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumberArray->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, streamInterfaceNumberArray->getObject ( streamInterfaceIndex ) );
FailMessage ( NULL == streamInterfaceNumber );
if ( NULL != streamInterfaceNumber )
{
debugIOLog ("--> #%u", streamInterfaceNumber->unsigned8BitValue () );
}
}
#endif
if ( 0 == mEngineArray )
{
mEngineArray = OSArray::withCapacity ( 1 );
FailIf ( 0 == mEngineArray, Exit );
}
engine = OSTypeAlloc ( AppleUSBAudioEngine );
FailIf ( 0 == engine, Exit );
if ( engine->init ( streamInterfaceNumberArray ) )
{
if ( !mEngineArray->setObject ( engine ) )
{
engine->release ();
}
}
else
{
engine->release ();
}
result = true;
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::createAudioEngine ()", this );
return result;
}
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)
{
currentEngine->closeStreamInterfaces ();
currentEngine->openStreamInterfaces ();
}
currentEngine->resumeAudioEngine ();
}
break;
default:
;
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::message (0x%x, %p) - rc=%d", this, type, provider, getRetainCount ());
return kIOReturnSuccess;
}
IOUSBInterface * AppleUSBAudioDevice::getUSBInterface ( UInt8 interfaceNumber ) {
IOUSBInterface * interface = NULL;
OSIterator * iterator = NULL;
OSObject * object = NULL;
FailIf ( NULL == mControlInterface, Exit );
iterator = mControlInterface->GetDevice()->getChildIterator ( gIOServicePlane );
FailIf ( NULL == iterator, Exit );
object = iterator->getNextObject ();
while ( 0 != object )
{
interface = OSDynamicCast ( IOUSBInterface, object );
if ( 0 != interface )
{
if ( interface->GetInterfaceNumber () == interfaceNumber )
{
break;
}
}
object = iterator->getNextObject ();
}
Exit:
return interface;
}
const IOUSBConfigurationDescriptor * AppleUSBAudioDevice::getConfigurationDescriptor () {
IOUSBDevice * usbDevice;
const IOUSBConfigurationDescriptor * configDescriptor = NULL;
UInt8 currentConfigValue = 0;
UInt8 numConfigs = 0;
UInt8 index;
debugIOLog ("+ AppleUSBAudioDevice[%p]::getConfigurationDescriptor ()", this);
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
numConfigs = usbDevice->GetNumConfigurations ();
debugIOLog ("? AppleUSBAudioDevice[%p]::getConfigurationDescriptor () - numConfigs = %d", this, numConfigs);
if (1 < numConfigs)
{
usbDevice->GetConfiguration (¤tConfigValue);
debugIOLog ("? AppleUSBAudioDevice[%p]::getConfigurationDescriptor () - currentConfigValue = %d", this, currentConfigValue);
for (index = 0; index < numConfigs; index++)
{
const IOUSBConfigurationDescriptor * descriptor = usbDevice->GetFullConfigurationDescriptor (index);
if ((NULL != descriptor) && (descriptor->bConfigurationValue == currentConfigValue))
{
debugIOLog ("? AppleUSBAudioDevice[%p]::getConfigurationDescriptor () - Found config %d (%p) at index %d", this, currentConfigValue, descriptor, index);
configDescriptor = descriptor;
break;
}
}
}
else
{
configDescriptor = usbDevice->GetFullConfigurationDescriptor (0);
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::getConfigurationDescriptor () - configDescriptor=%p", this, configDescriptor);
return configDescriptor;
}
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;
}
UInt64 AppleUSBAudioDevice::getUSBFrameNumber () {
IOUSBDevice * usbDevice;
UInt64 frameNumber = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
frameNumber = usbDevice->GetBus()->GetFrameNumber();
Exit:
return frameNumber;
}
UInt8 AppleUSBAudioDevice::getManufacturerStringIndex () {
IOUSBDevice * usbDevice;
UInt8 stringIndex = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
stringIndex = usbDevice->GetManufacturerStringIndex();
Exit:
return stringIndex;
}
UInt8 AppleUSBAudioDevice::getProductStringIndex () {
IOUSBDevice * usbDevice;
UInt8 stringIndex = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
stringIndex = usbDevice->GetProductStringIndex();
Exit:
return stringIndex;
}
UInt8 AppleUSBAudioDevice::getSerialNumberStringIndex () {
IOUSBDevice * usbDevice;
UInt8 stringIndex = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
stringIndex = usbDevice->GetSerialNumberStringIndex();
Exit:
return stringIndex;
}
IOReturn AppleUSBAudioDevice::getStringDescriptor(UInt8 index, char *buf, int maxLen, UInt16 lang) {
IOUSBDevice * usbDevice;
IOReturn result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
result = usbDevice->GetStringDescriptor(index, buf, maxLen, lang);
Exit:
return result;
}
UInt16 AppleUSBAudioDevice::getVendorID () {
IOUSBDevice * usbDevice;
UInt16 vendorID = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
vendorID = usbDevice->GetVendorID();
Exit:
return vendorID;
}
UInt16 AppleUSBAudioDevice::getProductID () {
IOUSBDevice * usbDevice;
UInt16 productID = 0;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
FailIf (NULL == usbDevice, Exit);
productID = usbDevice->GetProductID();
Exit:
return productID;
}
OSNumber * AppleUSBAudioDevice::getLocationID () {
IOUSBDevice * usbDevice;
OSNumber * usbLocation = NULL;
FailIf (NULL == mControlInterface, Exit);
usbDevice = OSDynamicCast (IOUSBDevice, mControlInterface->GetDevice());
usbLocation = OSDynamicCast (OSNumber, usbDevice->getProperty (kUSBDevicePropertyLocationID));
Exit:
return usbLocation;
}
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;
}
IOReturn AppleUSBAudioDevice::registerEngineInfo (AppleUSBAudioEngine * usbAudioEngine) {
OSDictionary * engineInfo;
SInt32 oldEngineIndex;
IOReturn result = kIOReturnError;
if (NULL == mRegisteredEngines)
{
mRegisteredEngines = OSArray::withCapacity (2);
FailIf (NULL == mRegisteredEngines, Exit);
}
engineInfo = OSDictionary::withCapacity (1);
FailIf (NULL == engineInfo, Exit);
engineInfo->setObject (kEngine, usbAudioEngine);
if ( mRegisteredEnginesMutex )
{
IORecursiveLockLock (mRegisteredEnginesMutex);
}
oldEngineIndex = getEngineInfoIndex (usbAudioEngine);
if (-1 != oldEngineIndex)
{
mRegisteredEngines->replaceObject (oldEngineIndex, engineInfo);
}
else
{
mRegisteredEngines->setObject (engineInfo);
}
if ( mRegisteredEnginesMutex )
{
IORecursiveLockUnlock (mRegisteredEnginesMutex);
}
engineInfo->release ();
result = kIOReturnSuccess;
Exit:
return result;
}
SInt32 AppleUSBAudioDevice::getEngineInfoIndex (AppleUSBAudioEngine * inAudioEngine) {
OSDictionary * engineInfo;
AppleUSBAudioEngine * usbAudioEngine;
UInt16 engineIndex;
SInt32 returnIndex;
returnIndex = -1;
if ( mRegisteredEnginesMutex )
{
IORecursiveLockLock (mRegisteredEnginesMutex);
}
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; }
}
}
}
if ( mRegisteredEnginesMutex )
{
IORecursiveLockUnlock (mRegisteredEnginesMutex);
}
return returnIndex;
}
IOReturn AppleUSBAudioDevice::registerStreamInfo (UInt8 interfaceNum, UInt8 altSettingNum) {
OSDictionary * streamInfo;
SInt32 oldStreamIndex;
OSNumber * number;
IOReturn result = kIOReturnError;
if (NULL == mRegisteredStreams)
{
mRegisteredStreams = OSArray::withCapacity (4);
FailIf (NULL == mRegisteredStreams, Exit);
}
streamInfo = OSDictionary::withCapacity (2);
FailIf (NULL == streamInfo, Exit);
number = OSNumber::withNumber (interfaceNum, 8);
streamInfo->setObject (kInterface, number);
number->release ();
number = OSNumber::withNumber (altSettingNum, 8);
streamInfo->setObject (kAltSetting, number);
number->release ();
if ( mRegisteredStreamsMutex )
{
IORecursiveLockLock (mRegisteredStreamsMutex);
}
oldStreamIndex = getStreamInfoIndex (interfaceNum);
if (-1 != oldStreamIndex)
{
mRegisteredStreams->replaceObject (oldStreamIndex, streamInfo);
}
else
{
mRegisteredStreams->setObject (streamInfo);
}
if ( mRegisteredStreamsMutex )
{
IORecursiveLockUnlock (mRegisteredStreamsMutex);
}
streamInfo->release ();
result = kIOReturnSuccess;
Exit:
return result;
}
SInt32 AppleUSBAudioDevice::getStreamInfoIndex (UInt8 interfaceNum) {
OSDictionary * streamInfo;
OSNumber * streamInterfaceNumber;
UInt16 streamIndex;
SInt32 returnIndex;
returnIndex = -1;
if ( mRegisteredStreamsMutex )
{
IORecursiveLockLock (mRegisteredStreamsMutex);
}
if (mRegisteredStreams)
{
for (streamIndex = 0; streamIndex < mRegisteredStreams->getCount (); streamIndex++)
{
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamIndex));
if (streamInfo)
{
streamInterfaceNumber = OSDynamicCast (OSNumber, streamInfo->getObject (kInterface));
if ( ( NULL != streamInterfaceNumber ) && ( streamInterfaceNumber->unsigned8BitValue() == interfaceNum ) )
{
returnIndex = streamIndex;
break; }
}
}
}
if ( mRegisteredStreamsMutex )
{
IORecursiveLockUnlock (mRegisteredStreamsMutex);
}
return returnIndex;
}
IOReturn AppleUSBAudioDevice::doControlStuff (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altSettingNum) {
AppleUSBAudioEngine * usbAudioEngine;
IOAudioSelectorControl * inputSelector;
IOAudioSelectorControl * outputSelector = NULL; OSArray * arrayOfPathsFromOutputTerminal;
OSArray * aPath;
OSArray * playThroughPaths;
OSNumber * theUnitIDNum;
IOReturn result;
UInt32 numUnitsInPath, unitIndexInPath, pathIndex; UInt32 inputTerminalIndex; UInt32 outputTerminalIndex;
UInt32 numOutputTerminalArrays;
UInt32 numPathsFromOutputTerminal;
UInt32 pathsToOutputTerminalN;
UInt32 selection;
SInt32 engineIndex;
SInt32 streamIndex; UInt16 terminalType;
UInt8 numSelectorUnits;
UInt8 subType;
UInt8 numInputTerminals; UInt8 numOutputTerminals;
UInt8 selectorUnitID;
UInt8 featureUnitID;
UInt8 volFeatureUnitID; UInt8 muteFeatureUnitID; SInt16 deviceMax; UInt8 controlInterfaceNum;
UInt8 unitID;
UInt8 outputTerminalID;
UInt8 inputTerminalID; OSString * nameString; Boolean done;
UInt8 numControls; UInt8 channelNum; UInt8 defaultSelectorSetting; bool playthroughCapable;
UInt8 direction;
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);
FailIf ( kIOReturnSuccess != registerEngineInfo ( usbAudioEngine ), Exit ); FailIf ( kIOReturnSuccess != registerStreamInfo ( interfaceNum, altSettingNum ), Exit );
engineIndex = getEngineInfoIndex (usbAudioEngine); streamIndex = getStreamInfoIndex (interfaceNum); FailIf ( ( -1 == engineIndex ) || ( -1 == streamIndex ), Exit );
featureUnitID = 0;
volFeatureUnitID = 0; muteFeatureUnitID = 0; selectorUnitID = 0;
outputTerminalID = 0;
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumInputTerminals (&numInputTerminals, controlInterfaceNum, 0), Exit); FailIf (kIOReturnSuccess != mConfigDictionary->getNumOutputTerminals (&numOutputTerminals, controlInterfaceNum, 0), Exit);
FailIf (kIOReturnSuccess != mConfigDictionary->getIsocEndpointDirection (&direction, interfaceNum, altSettingNum), Exit);
if (direction == kIOAudioStreamDirectionOutput)
{
UInt32 numConnectedOutputTerminals = 0; UInt8 defaultOutputTerminalID = 0; bool hasInitializedOutputControls = false;
FailIf (kIOReturnSuccess != mConfigDictionary->getTerminalLink (&inputTerminalID, interfaceNum, altSettingNum), Exit);
if ( 0 == inputTerminalID )
{
for (inputTerminalIndex = 0; inputTerminalIndex < numInputTerminals; inputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedInputTerminalType (&terminalType, controlInterfaceNum, 0, inputTerminalIndex), Exit);
if (USB_STREAMING == terminalType)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedInputTerminalID (&inputTerminalID, controlInterfaceNum, 0, inputTerminalIndex), Exit);
break; }
}
}
defaultOutputTerminalID = getDefaultOutputTerminalID ( inputTerminalID ); numConnectedOutputTerminals = getNumConnectedOutputTerminals ( inputTerminalID );
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - numConnectedOutputTerminals = %d", numConnectedOutputTerminals);
for (outputTerminalIndex = 0; outputTerminalIndex < numOutputTerminals && FALSE == done; outputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalIndex), Exit);
if (terminalType != USB_STREAMING)
{
UInt8 inputUnitID, outputUnitID;
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);
outputUnitID = theUnitIDNum->unsigned8BitValue (); theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
inputUnitID = theUnitIDNum->unsigned8BitValue ();
if ( ( inputUnitID == inputTerminalID ) && ( outputUnitID == outputTerminalID ) ) {
if ( !hasInitializedOutputControls )
{
if ( numConnectedOutputTerminals > 1 ) {
outputSelector = IOAudioSelectorControl::createOutputSelector (defaultOutputTerminalID, kIOAudioControlChannelIDAll, 0, (streamIndex << 16) | ( engineIndex << 8) | 0 ); FailIf (NULL == outputSelector, Exit);
outputSelector->setValueChangeHandler (controlChangedHandler, this);
usbAudioEngine->addDefaultAudioControl (outputSelector);
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageOutput, interfaceNum, altSettingNum, kVolumeControl);
if (featureUnitID)
{
volFeatureUnitID = featureUnitID; debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating output gain controls");
addVolumeControls (usbAudioEngine, volFeatureUnitID, outputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageOutput); featureUnitID = 0;
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageOutput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating output mute controls");
muteFeatureUnitID = featureUnitID; addMuteControl (usbAudioEngine, muteFeatureUnitID, outputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageOutput); featureUnitID = 0;
if ( numConnectedOutputTerminals <= 1 )
{
done = TRUE;
}
}
if ( volFeatureUnitID != muteFeatureUnitID )
{
if ( volFeatureUnitID )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, volFeatureUnitID), Exit);
for (channelNum = 0; channelNum < numControls; channelNum++)
{
if ( mConfigDictionary->channelHasMuteControl ( controlInterfaceNum, 0, volFeatureUnitID, channelNum ) )
{
setCurMute (volFeatureUnitID, channelNum, 0);
}
}
}
if ( muteFeatureUnitID )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, muteFeatureUnitID), Exit);
for (channelNum = 0; channelNum < numControls; channelNum++)
{
if ( mConfigDictionary->channelHasVolumeControl ( controlInterfaceNum, 0, muteFeatureUnitID, channelNum ) )
{
if ( kIOReturnSuccess == getMaxVolume (muteFeatureUnitID, channelNum, &deviceMax) )
{
setCurVolume ( muteFeatureUnitID, channelNum, (deviceMax >= 0) ? 0 : deviceMax );
}
}
}
}
}
usbAudioEngine->updateChannelNames ( inputTerminalID, interfaceNum, altSettingNum );
hasInitializedOutputControls = true;
}
if ( NULL != outputSelector ) {
nameString = getNameForTerminal ( outputTerminalID, kIOAudioStreamDirectionOutput );
FailIf (NULL == nameString, Exit);
if ( !outputSelector->valueExists ( outputTerminalID ) )
{
outputSelector->addAvailableSelection (outputTerminalID, nameString);
}
nameString->release ();
}
break; }
} } } }
else
{ FailIf (kIOReturnSuccess != mConfigDictionary->getTerminalLink (&outputTerminalID, interfaceNum, altSettingNum), Exit);
if ( outputTerminalID == 0 )
{
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 ();
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ()); FailIf (NULL == theUnitIDNum, Exit);
inputTerminalID =theUnitIDNum->unsigned8BitValue ();
if (unitID == outputTerminalID)
{
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)
{
defaultSelectorSetting = getSelectorSetting ( unitID );
if ( 0 == defaultSelectorSetting )
{
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Unable to get the selector setting. Defaulting to 1" );
defaultSelectorSetting = 1;
}
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Default selector setting: %d", defaultSelectorSetting );
pathIndex = 0;
if ( 1 != defaultSelectorSetting )
{
pathIndex = getPathIndexForSelectorSetting ( arrayOfPathsFromOutputTerminal, pathsToOutputTerminalN, unitIndexInPath, defaultSelectorSetting );
aPath = OSDynamicCast ( OSArray, arrayOfPathsFromOutputTerminal->getObject ( pathIndex ) );
if ( NULL == aPath ) {
pathIndex = 0;
defaultSelectorSetting = 1;
aPath = OSDynamicCast ( OSArray, arrayOfPathsFromOutputTerminal->getObject ( pathIndex ) );
FailIf ( NULL == aPath, Exit );
}
theUnitIDNum = OSDynamicCast ( OSNumber, aPath->getLastObject () );
FailIf ( NULL == theUnitIDNum, Exit );
inputTerminalID =theUnitIDNum->unsigned8BitValue ();
}
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Selected aPath = %p, pathIndex = %d, inputTerminalID = %d", aPath, pathIndex, inputTerminalID );
if (kIOReturnSuccess == setSelectorSetting (unitID, defaultSelectorSetting)) {
selectorUnitID = unitID;
engineIndex = getEngineInfoIndex (usbAudioEngine);
streamIndex = getStreamInfoIndex (interfaceNum); if ( ( -1 != engineIndex ) && ( -1 != streamIndex ) ) {
selection = (0xFF000000 & (pathsToOutputTerminalN << 24)) | (0x00FF0000 & (pathIndex << 16)) | (0x0000FF00 & (selectorUnitID << 8)) | (0x000000FF & defaultSelectorSetting); inputSelector = IOAudioSelectorControl::createInputSelector (selection, kIOAudioControlChannelIDAll, 0, (streamIndex << 16) | ( engineIndex << 8 ) | selectorUnitID ); 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, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageInput);
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating input mute controls");
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageInput); featureUnitID = 0;
}
else
{
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - Creating input mute controls");
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, 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, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageInput); featureUnitID = 0;
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Creating input mute control (no selectors)" );
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, 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, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageInput); featureUnitID = 0;
}
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsageInput, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
debugIOLog ( "? AppleUSBAudioDevice::doControlStuff () - Creating input mute control (no selectors)" );
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsageInput); featureUnitID = 0;
}
}
usbAudioEngine->updateChannelNames ( inputTerminalID, interfaceNum, altSettingNum );
playThroughPaths = getPlaythroughPaths (inputTerminalID); if (playThroughPaths)
{
playthroughCapable = true;
debugIOLog("? AppleUSBAudioDevice::doControlStuff () - performing playthrough setup");
doPlaythroughSetup (usbAudioEngine, playThroughPaths, interfaceNum, altSettingNum, inputTerminalID); playThroughPaths->release ();
}
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, UInt8 inputTerminalID) { OSArray * aPath;
OSNumber * theUnitIDNum;
OSString * nameString;
IOAudioSelectorControl * playThroughSelector;
OSDictionary * engineInfo;
OSDictionary * streamInfo; UInt32 numPlayThroughPaths;
UInt32 pathIndex;
UInt32 defaultPathIndex = 0; UInt8 defaultPathTerminalType = 0; SInt32 engineInfoIndex;
SInt32 streamInfoIndex; UInt16 terminalType;
UInt8 featureUnitID;
UInt8 outputTerminalID; UInt8 controlInterfaceNum;
char stringBuffer[kStringBufferSize]; UInt8 stringIndex; IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
engineInfoIndex = getEngineInfoIndex (usbAudioEngine);
FailIf (-1 == engineInfoIndex, Exit);
streamInfoIndex = getStreamInfoIndex (interfaceNum);
FailIf (-1 == streamInfoIndex, Exit);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex));
FailIf (NULL == engineInfo, Exit);
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamInfoIndex));
FailIf (NULL == streamInfo, Exit);
streamInfo->setObject (kPassThruPathsArray, playThroughPaths);
numPlayThroughPaths = playThroughPaths->getCount ();
if (numPlayThroughPaths > 0) {
for (pathIndex = 0; pathIndex < numPlayThroughPaths; pathIndex++)
{
aPath = OSDynamicCast (OSArray, playThroughPaths->getObject (pathIndex));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (0));
FailIf (NULL == theUnitIDNum, Exit);
outputTerminalID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalID), Exit);
switch ( defaultPathTerminalType )
{
case 0:
defaultPathTerminalType = terminalType;
defaultPathIndex = pathIndex;
break;
case 0x0301: break;
case 0x0302: if ( 0x0301 == terminalType )
{
defaultPathTerminalType = terminalType;
defaultPathIndex = pathIndex;
}
break;
case 0x0603: if ( ( 0x0301 == terminalType ) || ( 0x0302 == terminalType ) )
{
defaultPathTerminalType = terminalType;
defaultPathIndex = pathIndex;
}
break;
}
}
if ( numPlayThroughPaths > 1 ) {
playThroughSelector = IOAudioSelectorControl::create (defaultPathIndex, kIOAudioControlChannelIDAll, 0, (inputTerminalID << 24) | (streamInfoIndex << 16) | ( engineInfoIndex << 8 ) | 0, kIOAudioSelectorControlSubTypeDestination, 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, kIOAudioControlUsagePassThru, interfaceNum, altSettingNum, kMuteControl);
if (featureUnitID)
{
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (0)); FailIf (NULL == theUnitIDNum, Exit);
outputTerminalID = theUnitIDNum->unsigned8BitValue (); FailIf (kIOReturnSuccess != mConfigDictionary->getOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalID), Exit);
stringIndex = 0;
if ( ( kIOReturnSuccess == mConfigDictionary->getStringIndex ( &stringIndex, controlInterfaceNum, 0, outputTerminalID ) ) && ( 0 != stringIndex ) &&
( kIOReturnSuccess == getStringDescriptor ( stringIndex, stringBuffer, kStringBufferSize ) ) )
{
nameString = OSString::withCString (stringBuffer);
}
else
{
nameString = OSString::withCString (TerminalTypeString (terminalType));
}
FailIf (NULL == nameString, Exit);
playThroughSelector->addAvailableSelection (pathIndex, nameString);
nameString->release ();
}
}
streamInfo->setObject (kPassThruSelectorControl, playThroughSelector); }
aPath = OSDynamicCast (OSArray, playThroughPaths->getObject (defaultPathIndex)); FailIf (NULL == aPath, Exit);
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsagePassThru, interfaceNum, altSettingNum, kVolumeControl); if (featureUnitID)
{
addVolumeControls (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru); }
featureUnitID = getBestFeatureUnitInPath (aPath, kIOAudioControlUsagePassThru, interfaceNum, altSettingNum, kMuteControl); if (featureUnitID)
{
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSettingNum, kIOAudioControlUsagePassThru); }
result = kIOReturnSuccess;
} else
{
result = kIOReturnSuccess;
}
Exit:
return result;
}
UInt32 AppleUSBAudioDevice::getPathIndexForSelectorSetting (OSArray * arrayOfPathsFromOutputTerminal, UInt32 pathsToOutputTerminalN, UInt8 selectorUnitIndex, UInt8 selectorSetting) {
OSArray * aPath;
OSNumber * theUnitIDNum;
OSString * nameString;
UInt32 selectorSourceIndex;
UInt32 pathIndex;
UInt8 numSelectorSources;
UInt8 selectorID;
UInt8 controlInterfaceNum;
pathIndex = 0;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
aPath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (0));
FailIf (NULL == aPath, Exit);
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getObject (selectorUnitIndex));
FailIf (NULL == theUnitIDNum, Exit);
selectorID = theUnitIDNum->unsigned8BitValue ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumSources (&numSelectorSources, controlInterfaceNum, 0, selectorID), Exit);
for (selectorSourceIndex = 0; selectorSourceIndex < numSelectorSources; selectorSourceIndex++)
{
nameString = getNameForPath (arrayOfPathsFromOutputTerminal, &pathIndex, selectorUnitIndex + 1);
if (NULL != nameString)
{
nameString->release ();
}
if ( ( selectorSourceIndex + 1 ) == selectorSetting )
{
pathIndex = pathIndex - 1;
break;
}
}
Exit:
return pathIndex;
}
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;
}
UInt8 AppleUSBAudioDevice::getDefaultOutputTerminalID (UInt8 inputTerminalID) {
OSArray * arrayOfPathsFromOutputTerminal;
OSArray * aPath;
OSNumber * theUnitIDNum;
UInt8 controlInterfaceNum;
UInt8 numOutputTerminals;
UInt16 terminalType;
UInt8 outputTerminalID;
UInt32 outputTerminalIndex;
UInt32 numOutputTerminalArrays;
UInt32 pathsToOutputTerminalN;
UInt8 defaultOutputTerminalID = 0;
UInt8 defaultOutputTerminalType = 0;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumOutputTerminals (&numOutputTerminals, controlInterfaceNum, 0), Exit);
for (outputTerminalIndex = 0; outputTerminalIndex < numOutputTerminals; outputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalIndex), Exit);
if (terminalType != USB_STREAMING)
{
UInt8 inputUnitID, outputUnitID;
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);
outputUnitID = theUnitIDNum->unsigned8BitValue ();
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
inputUnitID = theUnitIDNum->unsigned8BitValue ();
if ( ( inputUnitID == inputTerminalID ) && ( outputUnitID == outputTerminalID ) )
{
switch ( defaultOutputTerminalType )
{
case 0:
defaultOutputTerminalType = terminalType;
defaultOutputTerminalID = outputTerminalID;
break;
case 0x0301: break;
case 0x0302: if ( 0x0301 == terminalType )
{
defaultOutputTerminalType = terminalType;
defaultOutputTerminalID = outputTerminalID;
}
break;
case 0x0603: if ( ( 0x0301 == terminalType ) || ( 0x0302 == terminalType ) )
{
defaultOutputTerminalType = terminalType;
defaultOutputTerminalID = outputTerminalID;
}
break;
}
break;
}
} } }
Exit:
return defaultOutputTerminalID;
}
UInt32 AppleUSBAudioDevice::getNumConnectedOutputTerminals (UInt8 inputTerminalID) {
OSArray * arrayOfPathsFromOutputTerminal;
OSArray * aPath;
OSNumber * theUnitIDNum;
UInt8 controlInterfaceNum;
UInt8 numOutputTerminals;
UInt16 terminalType;
UInt8 outputTerminalID;
UInt32 outputTerminalIndex;
UInt32 numOutputTerminalArrays;
UInt32 pathsToOutputTerminalN;
UInt32 numConnectedOutputTerminals = 0;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
FailIf (kIOReturnSuccess != mConfigDictionary->getNumOutputTerminals (&numOutputTerminals, controlInterfaceNum, 0), Exit);
for (outputTerminalIndex = 0; outputTerminalIndex < numOutputTerminals; outputTerminalIndex++)
{
FailIf (kIOReturnSuccess != mConfigDictionary->getIndexedOutputTerminalType (&terminalType, controlInterfaceNum, 0, outputTerminalIndex), Exit);
if (terminalType != USB_STREAMING)
{
UInt8 inputUnitID, outputUnitID;
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);
outputUnitID = theUnitIDNum->unsigned8BitValue ();
theUnitIDNum = OSDynamicCast (OSNumber, aPath->getLastObject ());
FailIf (NULL == theUnitIDNum, Exit);
inputUnitID = theUnitIDNum->unsigned8BitValue ();
if ( ( inputUnitID == inputTerminalID ) && ( outputUnitID == outputTerminalID ) )
{
numConnectedOutputTerminals++;
break;
}
} } }
Exit:
return numConnectedOutputTerminals;
}
OSString * AppleUSBAudioDevice::getNameForTerminal (UInt8 terminalID, UInt8 direction) {
OSString * theString = NULL;
OSString * tempString;
char stringBuffer[kStringBufferSize]; UInt8 stringIndex = 0;
UInt8 controlInterfaceNum;
UInt16 terminalType;
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
if ( kIOAudioStreamDirectionOutput == direction )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getOutputTerminalType (&terminalType, controlInterfaceNum, 0, terminalID), Exit);
}
else
{
FailIf (kIOReturnSuccess != mConfigDictionary->getInputTerminalType (&terminalType, controlInterfaceNum, 0, terminalID), Exit);
}
if ( ( kIOReturnSuccess == mConfigDictionary->getStringIndex ( &stringIndex, controlInterfaceNum, 0, terminalID ) ) &&
( 0 != stringIndex ) &&
( kIOReturnSuccess == getStringDescriptor ( stringIndex, stringBuffer, kStringBufferSize ) ) )
{
debugIOLog ("? AppleUSBAudioDevice::getNameForTerminal () - terminalID = %d, stringIndex = %d, stringBuffer = %s", terminalID, stringIndex, stringBuffer);
tempString = OSString::withCString (stringBuffer);
}
else
{
tempString = OSString::withCString (TerminalTypeString (terminalType));
}
FailIf (NULL == tempString, Exit);
theString = OSString::withString (tempString);
tempString->release ();
Exit:
return theString;
}
OSString * AppleUSBAudioDevice::getNameForPath (OSArray * arrayOfPathsFromOutputTerminal, UInt32 * pathIndex, UInt8 startingPoint) {
OSString * theString;
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);
if ( USB_STREAMING != terminalType )
{
theString = getNameForTerminal ( unitID, kIOAudioStreamDirectionInput ); }
(*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 terminalID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage) { OSArray * inputGainControlsArray;
OSArray * passThruVolControlsArray;
OSArray * outputVolControlsArray;
OSDictionary * engineInfo;
OSDictionary * streamInfo; IOAudioLevelControl * theLevelControl;
IOFixed deviceMinDB;
IOFixed deviceMaxDB;
SInt32 engineInfoIndex;
SInt32 streamInfoIndex; 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, %d, %u)", usbAudioEngine, featureUnitID, terminalID, interfaceNum, altSettingNum, usage);
FailIf (NULL == mControlInterface, Exit);
engineInfoIndex = getEngineInfoIndex (usbAudioEngine);
FailIf (-1 == engineInfoIndex, Exit);
streamInfoIndex = getStreamInfoIndex (interfaceNum);
FailIf (-1 == streamInfoIndex, Exit);
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex));
FailIf (NULL == engineInfo, Exit);
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamInfoIndex));
FailIf (NULL == streamInfo, 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, (terminalID << 8) | 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)
{
streamInfo->setObject (kInputGainControls, inputGainControlsArray); inputGainControlsArray->release ();
}
if (NULL != passThruVolControlsArray)
{
streamInfo->setObject (kPassThruVolControls, passThruVolControlsArray); passThruVolControlsArray->release ();
}
if (NULL != outputVolControlsArray)
{
streamInfo->setObject (kOutputVolControls, outputVolControlsArray); outputVolControlsArray->release ();
}
Exit:
debugIOLog ("- AppleUSBAudioDevice::addVolumeControls (0x%x, %d, %d, %d, %d, %u)", usbAudioEngine, featureUnitID, terminalID, interfaceNum, altSettingNum, usage);
return;
}
void AppleUSBAudioDevice::addMuteControl (AppleUSBAudioEngine * usbAudioEngine, UInt8 featureUnitID, UInt8 terminalID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage) {
OSArray * inputMuteControlsArray;
OSArray * outputMuteControlsArray;
OSArray * passThruToggleControlsArray; OSDictionary * engineInfo;
OSDictionary * streamInfo; IOAudioToggleControl * theMuteControl;
SInt32 engineInfoIndex;
SInt32 streamInfoIndex; SInt16 deviceCur;
UInt8 channelNum;
UInt8 controlInterfaceNum;
UInt8 numControls;
IOReturn resultCode;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::addMuteControl ( %p, %d, %d, %d, %d, 0%x )", this, usbAudioEngine, featureUnitID, terminalID, interfaceNum, altSettingNum, usage );
FailIf ( NULL == mControlInterface, Exit );
engineInfoIndex = getEngineInfoIndex ( usbAudioEngine );
FailIf ( -1 == engineInfoIndex, Exit );
streamInfoIndex = getStreamInfoIndex ( interfaceNum );
FailIf ( -1 == streamInfoIndex, Exit );
engineInfo = OSDynamicCast ( OSDictionary, mRegisteredEngines->getObject ( engineInfoIndex ) );
FailIf ( NULL == engineInfo, Exit );
streamInfo = OSDynamicCast ( OSDictionary, mRegisteredStreams->getObject ( streamInfoIndex ) );
FailIf ( NULL == streamInfo, Exit );
inputMuteControlsArray = NULL;
outputMuteControlsArray = NULL; passThruToggleControlsArray = 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, (terminalID << 8) | 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:
if ( NULL == passThruToggleControlsArray )
{
passThruToggleControlsArray = OSArray::withObjects ( ( const OSObject ** ) &theMuteControl, 1 );
}
else
{
passThruToggleControlsArray->setObject ( theMuteControl );
}
break;
case kIOAudioControlUsageOutput:
if ( NULL == outputMuteControlsArray )
{
outputMuteControlsArray = OSArray::withObjects ( ( const OSObject ** ) &theMuteControl, 1 );
}
else
{
outputMuteControlsArray->setObject ( theMuteControl );
}
break;
}
theMuteControl->release ();
}
}
if ( NULL != inputMuteControlsArray )
{
streamInfo->setObject ( kInputMuteControls, inputMuteControlsArray ); inputMuteControlsArray->release ();
}
if ( NULL != passThruToggleControlsArray )
{
streamInfo->setObject ( kPassThruToggleControls, passThruToggleControlsArray ); passThruToggleControlsArray->release ();
}
if ( NULL != outputMuteControlsArray )
{
streamInfo->setObject ( kOutputMuteControls, outputMuteControlsArray ); outputMuteControlsArray->release ();
}
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::addMuteControl ( %p, %d, %d, %d, %d, 0x%x )", this, usbAudioEngine, featureUnitID, terminalID, 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 = IOBufferMemoryDescriptor::withBytes (&newValue, newValueLen, kIODirectionOut);
FailIf (NULL == theSettingDesc, Exit);
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) {
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
result = getFeatureUnitSetting (MUTE_CONTROL, unitID, channelNumber, USBAUDIO_0200::CUR, target);
}
else
{
result = getFeatureUnitSetting (MUTE_CONTROL, unitID, channelNumber, GET_CUR, target);
}
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::getCurVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
if ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() )
{
result = getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, USBAUDIO_0200::CUR, target);
}
else
{
result = getFeatureUnitSetting (VOLUME_CONTROL, unitID, channelNumber, GET_CUR, target);
}
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::getMaxVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
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);
}
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::getMinVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target) {
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
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);
}
Exit:
return result;
}
IOReturn AppleUSBAudioDevice::getVolumeResolution (UInt8 unitID, UInt8 channelNumber, UInt16 * target) {
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mControlInterface, Exit);
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);
}
Exit:
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:
result = doOutputSelectorChange (audioControl, oldValue, newValue); 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 () & 0xFF; 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);
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);
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;
debugIOLog ("+ AppleUSBAudioDevice[%p]::doToggleControlChange( %p, 0x%x, 0x%x )", this, audioControl, oldValue, newValue);
unitID = audioControl->getControlID () & 0xFF; channelNum = audioControl->getChannelID ();
debugIOLog ("? AppleUSBAudioDevice[%p]::doToggleControlChange( %p, 0x%x, 0x%x ) - unitID = %d, channelNum = %d", this, audioControl, oldValue, newValue, unitID, channelNum);
result = setCurMute (unitID, channelNum, HostToUSBWord (newValue));
debugIOLog ("- AppleUSBAudioDevice[%p]::doToggleControlChange( %p, 0x%x, 0x%x ) = 0x%x", this, audioControl, oldValue, newValue, kIOReturnSuccess);
return result;
}
IOReturn AppleUSBAudioDevice::doPassThruSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
AppleUSBAudioEngine * usbAudioEngine;
OSArray * playThroughPaths;
OSArray * passThruVolControlsArray;
OSArray * passThruToggleControlsArray; OSArray * thePath;
OSNumber * number;
OSDictionary * engineInfo;
OSDictionary * streamInfo; UInt32 i;
UInt32 numPassThruVolControls; UInt32 numPassThruToggleControls; UInt8 interfaceNum;
UInt8 altSetting;
UInt8 featureUnitID;
UInt8 inputTerminalID; UInt8 pathIndex;
SInt32 engineInfoIndex; SInt32 streamInfoIndex;
debugIOLog ("+ AppleUSBAudioDevice[%p]::doPassThruSelectorChange( %p, 0x%x, 0x%x )", this, audioControl, oldValue, newValue);
if ( oldValue != newValue ) {
pathIndex = (newValue & 0x000000FF);
debugIOLog ("? AppleUSBAudioDevice[%p]::doPassThruSelectorChange( %p, 0x%x, 0x%x ) - controlID = 0x%x", this, audioControl, oldValue, newValue, audioControl->getControlID ());
engineInfoIndex = ( audioControl->getControlID () >> 8 ) & 0xFF; streamInfoIndex = ( audioControl->getControlID () >> 16 ) & 0xFF;
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex)); FailIf (NULL == engineInfo, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
FailIf (NULL == usbAudioEngine, Exit);
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamInfoIndex)); FailIf (NULL == streamInfo, Exit);
number = OSDynamicCast (OSNumber, streamInfo->getObject (kInterface)); FailIf (NULL == number, Exit);
interfaceNum = number->unsigned8BitValue ();
number = OSDynamicCast (OSNumber, streamInfo->getObject (kAltSetting)); FailIf (NULL == number, Exit);
altSetting = number->unsigned8BitValue ();
passThruVolControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kPassThruVolControls)); passThruToggleControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kPassThruToggleControls));
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
if ( NULL != passThruVolControlsArray )
{
numPassThruVolControls = passThruVolControlsArray->getCount (); for (i = 0; i < numPassThruVolControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)passThruVolControlsArray->getObject (i));
}
passThruVolControlsArray->flushCollection ();
streamInfo->removeObject (kPassThruVolControls);
}
if ( NULL != passThruToggleControlsArray )
{
numPassThruToggleControls = passThruToggleControlsArray->getCount ();
for (i = 0; i < numPassThruToggleControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)passThruToggleControlsArray->getObject (i));
}
passThruToggleControlsArray->flushCollection ();
streamInfo->removeObject (kPassThruToggleControls);
}
playThroughPaths = OSDynamicCast (OSArray, streamInfo->getObject (kPassThruPathsArray)); FailIf (NULL == playThroughPaths, Exit);
thePath = OSDynamicCast (OSArray, playThroughPaths->getObject (pathIndex));
FailIf (NULL == thePath, Exit);
number = OSDynamicCast (OSNumber, thePath->getLastObject()); FailIf (NULL == number, Exit);
inputTerminalID = number->unsigned8BitValue ();
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsagePassThru, interfaceNum, altSetting, kVolumeControl);
if ( 0 != featureUnitID )
{
addVolumeControls (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSetting, kIOAudioControlUsagePassThru); }
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsagePassThru, interfaceNum, altSetting, kMuteControl);
if ( 0 != featureUnitID )
{
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSetting, kIOAudioControlUsagePassThru); }
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::doPassThruSelectorChange( %p, 0x%x, 0x%x ) = 0x%x", this, audioControl, oldValue, newValue, kIOReturnSuccess);
return kIOReturnSuccess;
}
IOReturn AppleUSBAudioDevice::doInputSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
AppleUSBAudioEngine * usbAudioEngine;
IOAudioSelectorControl * playThroughSelector; OSArray * playThroughPaths; OSArray * passThruVolControlsArray; OSArray * passThruToggleControlsArray; OSArray * inputGainControlsArray;
OSArray * inputMuteControlsArray; OSArray * arrayOfPathsFromOutputTerminal;
OSArray * thePath;
OSNumber * number;
OSDictionary * engineInfo;
OSDictionary * streamInfo; IOReturn result = kIOReturnError;
UInt32 i;
UInt32 numPassThruVolControls; UInt32 numPassThruToggleControls; UInt32 numGainControls;
UInt32 numMuteControls; UInt8 interfaceNum;
UInt8 altSetting;
UInt8 featureUnitID;
UInt8 selectorUnitID;
UInt8 selectorPosition;
UInt8 pathsToOutputTerminal;
UInt8 pathIndex;
UInt8 inputTerminalID; SInt32 engineInfoIndex; SInt32 streamInfoIndex; UInt32 unitIndex; Boolean foundMixerUnit = false; UInt8 controlInterfaceNum; UInt8 subType;
debugIOLog ("+ AppleUSBAudioDevice[%p]::doInputSelectorChange( %p, 0x%x, 0x%x )", this, audioControl, oldValue, newValue);
if ( oldValue != newValue ) {
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
pathsToOutputTerminal = (newValue & 0xFF000000) >> 24;
pathIndex = (newValue & 0x00FF0000) >> 16;
selectorUnitID = (newValue & 0x0000FF00) >> 8;
selectorPosition = newValue & 0x000000FF;
result = setSelectorSetting (selectorUnitID, selectorPosition);
FailIf (kIOReturnSuccess != result, Exit);
engineInfoIndex = ( audioControl->getControlID () >> 8 ) & 0xFF; streamInfoIndex = ( audioControl->getControlID () >> 16 ) & 0xFF;
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex)); FailIf (NULL == engineInfo, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
FailIf (NULL == usbAudioEngine, Exit);
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamInfoIndex)); FailIf (NULL == streamInfo, Exit);
number = OSDynamicCast (OSNumber, streamInfo->getObject (kInterface)); FailIf (NULL == number, Exit);
interfaceNum = number->unsigned8BitValue ();
number = OSDynamicCast (OSNumber, streamInfo->getObject (kAltSetting)); FailIf (NULL == number, Exit);
altSetting = number->unsigned8BitValue ();
inputGainControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kInputGainControls)); inputMuteControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kInputMuteControls)); passThruVolControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kPassThruVolControls)); passThruToggleControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kPassThruToggleControls)); playThroughSelector = OSDynamicCast (IOAudioSelectorControl, streamInfo->getObject (kPassThruSelectorControl));
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
if ( NULL != inputGainControlsArray )
{
numGainControls = inputGainControlsArray->getCount ();
for (i = 0; i < numGainControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)inputGainControlsArray->getObject (i));
}
inputGainControlsArray->flushCollection ();
streamInfo->removeObject (kInputGainControls);
}
if ( NULL != inputMuteControlsArray )
{
numMuteControls = inputMuteControlsArray->getCount ();
for (i = 0; i < numMuteControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)inputMuteControlsArray->getObject (i));
}
inputMuteControlsArray->flushCollection ();
streamInfo->removeObject (kInputMuteControls);
}
if ( NULL != passThruVolControlsArray )
{
numPassThruVolControls = passThruVolControlsArray->getCount ();
for (i = 0; i < numPassThruVolControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)passThruVolControlsArray->getObject (i));
}
passThruVolControlsArray->flushCollection ();
streamInfo->removeObject (kPassThruVolControls);
}
if ( NULL != passThruToggleControlsArray )
{
numPassThruToggleControls = passThruToggleControlsArray->getCount ();
for (i = 0; i < numPassThruToggleControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)passThruToggleControlsArray->getObject (i));
}
passThruToggleControlsArray->flushCollection ();
streamInfo->removeObject (kPassThruToggleControls);
}
if ( NULL != playThroughSelector )
{
usbAudioEngine->removeDefaultAudioControl (playThroughSelector);
streamInfo->removeObject (kPassThruSelectorControl);
}
arrayOfPathsFromOutputTerminal = OSDynamicCast (OSArray, mControlGraph->getObject (pathsToOutputTerminal));
FailIf (NULL == arrayOfPathsFromOutputTerminal, Exit);
thePath = OSDynamicCast (OSArray, arrayOfPathsFromOutputTerminal->getObject (pathIndex));
FailIf (NULL == thePath, Exit);
number = OSDynamicCast (OSNumber, thePath->getLastObject()); FailIf (NULL == number, Exit);
inputTerminalID = number->unsigned8BitValue ();
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsageInput, interfaceNum, altSetting, kVolumeControl);
if ( 0 != featureUnitID ) {
addVolumeControls (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSetting, kIOAudioControlUsageInput); addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSetting, kIOAudioControlUsageInput); }
else
{
featureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsageInput, interfaceNum, altSetting, kMuteControl);
if ( 0 != featureUnitID )
{
addMuteControl (usbAudioEngine, featureUnitID, inputTerminalID, interfaceNum, altSetting, kIOAudioControlUsageInput); }
}
foundMixerUnit = false;
for (unitIndex = thePath->getCount() - 2; unitIndex > 0; unitIndex--)
{
number = OSDynamicCast (OSNumber, thePath->getObject (unitIndex));
if ( ( NULL != number ) && ( kIOReturnSuccess == mConfigDictionary->getSubType (&subType, controlInterfaceNum, 0, number->unsigned8BitValue ()) ) )
{
if (MIXER_UNIT == subType)
{
foundMixerUnit = true;
break;
}
}
}
if ( !foundMixerUnit )
{
playThroughPaths = getPlaythroughPaths (inputTerminalID);
if (playThroughPaths)
{
debugIOLog("? AppleUSBAudioDevice::doInputSelectorChange () - performing playthrough setup");
doPlaythroughSetup (usbAudioEngine, playThroughPaths, interfaceNum, altSetting, inputTerminalID);
playThroughPaths->release ();
}
}
usbAudioEngine->updateChannelNames ( inputTerminalID, interfaceNum, altSetting ); usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
}
else
{
result = kIOReturnSuccess;
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::doInputSelectorChange( %p, 0x%x, 0x%x ) = 0x%x", this, audioControl, oldValue, newValue, result);
return result;
}
IOReturn AppleUSBAudioDevice::doOutputSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue) {
AppleUSBAudioEngine * usbAudioEngine;
OSArray * arrayOfPathsFromOutputTerminal;
UInt32 numOutputTerminalArrays;
UInt32 pathsToOutputTerminalN;
OSArray * outputVolControlsArray;
OSArray * outputMuteControlsArray;
OSArray * aPath;
OSNumber * theUnitIDNum;
OSArray * thePath = NULL;
OSNumber * number;
OSDictionary * engineInfo;
OSDictionary * streamInfo; UInt32 i;
UInt32 numOutputVolControls;
UInt32 numOutputMuteControls;
UInt8 interfaceNum;
UInt8 altSetting;
UInt8 volFeatureUnitID; UInt8 muteFeatureUnitID; UInt8 outputUnitID;
UInt8 selectedOutputTerminalID;
UInt8 inputTerminalID;
SInt32 engineInfoIndex; SInt32 streamInfoIndex; UInt8 controlInterfaceNum; UInt8 numControls; UInt8 channelNum; SInt16 deviceMax;
debugIOLog ("+ AppleUSBAudioDevice[%p]::doOutputSelectorChange( %p, 0x%x, 0x%x )", this, audioControl, oldValue, newValue);
if ( oldValue != newValue )
{
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
selectedOutputTerminalID = (newValue & 0x000000FF);
engineInfoIndex = ( audioControl->getControlID () >> 8 ) & 0xFF; streamInfoIndex = ( audioControl->getControlID () >> 16 ) & 0xFF;
engineInfo = OSDynamicCast (OSDictionary, mRegisteredEngines->getObject (engineInfoIndex)); FailIf (NULL == engineInfo, Exit);
usbAudioEngine = OSDynamicCast (AppleUSBAudioEngine, engineInfo->getObject (kEngine));
FailIf (NULL == usbAudioEngine, Exit);
streamInfo = OSDynamicCast (OSDictionary, mRegisteredStreams->getObject (streamInfoIndex)); FailIf (NULL == streamInfo, Exit);
number = OSDynamicCast (OSNumber, streamInfo->getObject (kInterface)); FailIf (NULL == number, Exit);
interfaceNum = number->unsigned8BitValue ();
number = OSDynamicCast (OSNumber, streamInfo->getObject (kAltSetting)); FailIf (NULL == number, Exit);
altSetting = number->unsigned8BitValue ();
outputVolControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kOutputVolControls)); outputMuteControlsArray = OSDynamicCast (OSArray, streamInfo->getObject (kOutputMuteControls));
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
if ( NULL != outputVolControlsArray )
{
numOutputVolControls = outputVolControlsArray->getCount ();
for (i = 0; i < numOutputVolControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)outputVolControlsArray->getObject (i));
}
outputVolControlsArray->flushCollection ();
streamInfo->removeObject (kOutputVolControls);
}
if ( NULL != outputMuteControlsArray )
{
numOutputMuteControls = outputMuteControlsArray->getCount ();
for (i = 0; i < numOutputMuteControls; i++)
{
usbAudioEngine->removeDefaultAudioControl ((IOAudioLevelControl *)outputMuteControlsArray->getObject (i));
}
outputMuteControlsArray->flushCollection ();
streamInfo->removeObject (kOutputMuteControls);
}
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);
outputUnitID = theUnitIDNum->unsigned8BitValue ();
if ( outputUnitID == selectedOutputTerminalID )
{
thePath = aPath;
break;
}
}
FailIf (NULL == thePath, Exit);
number = OSDynamicCast (OSNumber, thePath->getLastObject()); FailIf (NULL == number, Exit);
inputTerminalID = number->unsigned8BitValue ();
volFeatureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsageOutput, interfaceNum, altSetting, kVolumeControl);
if ( 0 != volFeatureUnitID )
{
addVolumeControls (usbAudioEngine, volFeatureUnitID, selectedOutputTerminalID, interfaceNum, altSetting, kIOAudioControlUsageOutput); }
muteFeatureUnitID = getBestFeatureUnitInPath (thePath, kIOAudioControlUsageOutput, interfaceNum, altSetting, kMuteControl);
if ( 0 != muteFeatureUnitID )
{
addMuteControl (usbAudioEngine, muteFeatureUnitID, selectedOutputTerminalID, interfaceNum, altSetting, kIOAudioControlUsageOutput); }
if ( volFeatureUnitID != muteFeatureUnitID )
{
if ( volFeatureUnitID )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, volFeatureUnitID), Exit);
for (channelNum = 0; channelNum < numControls; channelNum++)
{
if ( mConfigDictionary->channelHasMuteControl ( controlInterfaceNum, 0, volFeatureUnitID, channelNum ) )
{
setCurMute (volFeatureUnitID, channelNum, 0);
}
}
}
if ( muteFeatureUnitID )
{
FailIf (kIOReturnSuccess != mConfigDictionary->getNumControls (&numControls, controlInterfaceNum, 0, muteFeatureUnitID), Exit);
for (channelNum = 0; channelNum < numControls; channelNum++)
{
if ( mConfigDictionary->channelHasVolumeControl ( controlInterfaceNum, 0, muteFeatureUnitID, channelNum ) )
{
if ( kIOReturnSuccess == getMaxVolume (muteFeatureUnitID, channelNum, &deviceMax) )
{
setCurVolume ( muteFeatureUnitID, channelNum, (deviceMax >= 0) ? 0 : deviceMax );
}
}
}
}
}
usbAudioEngine->updateChannelNames ( inputTerminalID, interfaceNum, altSetting ); usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::doOutputSelectorChange( %p, 0x%x, 0x%x ) = 0x%x", this, audioControl, oldValue, newValue, kIOReturnSuccess);
return kIOReturnSuccess;
}
OSArray * AppleUSBAudioDevice::getPlaythroughPaths (UInt8 inputTerminalID) { 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 ();
if (unitID != inputTerminalID) continue; 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 startingUnitIndex; UInt8 endingUnitIndex; UInt8 controlInterfaceNum;
UInt8 unitID;
UInt8 subType;
UInt8 channelNum;
UInt8 numChannels;
UInt8 selectorUnitIndex; UInt8 mixerUnitIndex; UInt8 mixerUnitID; Boolean foundSelectorUnit; Boolean foundMixerUnit; Boolean foundFeatureUnit;
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 ();
foundFeatureUnit = FALSE;
switch (direction)
{
case kIOAudioControlUsagePassThru:
foundMixerUnit = false;
mixerUnitID = 0;
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 (MIXER_UNIT == subType)
{
foundMixerUnit = true;
mixerUnitIndex = unitIndex;
mixerUnitID = unitID;
break;
}
}
}
endingUnitIndex = foundMixerUnit ? mixerUnitIndex : 0;
for (unitIndex = numUnitsInPath - 2; unitIndex > endingUnitIndex && !foundFeatureUnit; 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)
&& ( ( 1 == pathsContaining (unitID) ) ||
( foundMixerUnit && ( 0 == pathsContainingFeatureUnitButNotMixerUnit (unitID, mixerUnitID) ) ) ) )
{
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;
foundFeatureUnit = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
foundFeatureUnit = TRUE;
}
break;
} } } } else
{
debugIOLog ( "! AppleUSBAudioDevice::getBestFeatureUnitInPath () - something is wrong here!!!" );
}
} break;
case kIOAudioControlUsageInput:
foundSelectorUnit = false;
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 (SELECTOR_UNIT == subType)
{
foundSelectorUnit = true;
selectorUnitIndex = unitIndex;
break;
}
}
}
foundFeatureUnit = false;
if ( foundSelectorUnit )
{
for (unitIndex = numUnitsInPath - 2; unitIndex > selectorUnitIndex; 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)
{
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;
foundFeatureUnit = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
foundFeatureUnit = TRUE;
}
break;
} } } } else
{
debugIOLog ( "! AppleUSBAudioDevice::getBestFeatureUnitInPath () - something is wrong here!!!" );
}
} }
if (!foundFeatureUnit)
{
startingUnitIndex = foundSelectorUnit ? ( selectorUnitIndex - 1) : ( numUnitsInPath - 2 );
for (unitIndex = startingUnitIndex; unitIndex > 0 && !foundFeatureUnit; 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)
{
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;
foundFeatureUnit = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
foundFeatureUnit = TRUE;
}
break;
} } } } else
{
debugIOLog ( "! AppleUSBAudioDevice::getBestFeatureUnitInPath () - something is wrong here!!!" );
}
} }
break;
case kIOAudioControlUsageOutput:
default:
debugIOLog ("? AppleUSBAudioDevice::getBestFeatureUnitInPath () - kIOAudioControlUsageOutput ");
for (unitIndex = 1; unitIndex < numUnitsInPath && !foundFeatureUnit; 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;
foundFeatureUnit = TRUE;
}
break;
case kMuteControl:
if (mConfigDictionary->channelHasMuteControl (controlInterfaceNum, 0, unitID, channelNum))
{
featureUnitID = unitID;
foundFeatureUnit = 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::pathsContainingFeatureUnitButNotMixerUnit (UInt8 featureUnitID, UInt8 mixerUnitID)
{
OSArray * thisPathGroup = NULL;
OSArray * thisPath = NULL;
OSNumber * unitNumber = NULL;
UInt8 unitID;
UInt8 controlInterfaceNum;
UInt8 numPaths = 0;
Boolean foundFeatureUnit;
Boolean foundMixerUnit;
if ( mControlGraph )
{
FailIf (NULL == mControlInterface, Exit);
controlInterfaceNum = mControlInterface->GetInterfaceNumber ();
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 )
{
foundFeatureUnit = false;
foundMixerUnit = false;
for ( UInt8 unitIndex = 0; unitIndex < thisPath->getCount (); unitIndex++ )
{
unitNumber = OSDynamicCast ( OSNumber, thisPath->getObject (unitIndex) );
if ( NULL != unitNumber )
{
unitID = unitNumber->unsigned8BitValue ();
if ( featureUnitID == unitID )
{
foundFeatureUnit = true;
}
else if ( mixerUnitID == unitID )
{
foundMixerUnit = true;
}
}
}
if ( foundFeatureUnit && !foundMixerUnit )
{
numPaths++;
}
}
}
}
}
}
Exit:
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() ) ? (UInt8)USBAUDIO_0200::CUR : GET_CUR;
devReq.wValue = ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() ) ? ( (UInt16)USBAUDIO_0200::SU_SELECTOR_CONTROL ) << 8 : 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 = IOBufferMemoryDescriptor::withBytes (&setting, 1, kIODirectionIn);
FailIf (NULL == settingDesc, Exit);
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBInterface);
devReq.bRequest = SET_CUR;
devReq.wValue = ( IP_VERSION_02_00 == mControlInterface->GetInterfaceProtocol() ) ? ( ( UInt16 )USBAUDIO_0200::SU_SELECTOR_CONTROL ) << 8 : 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, UInt8 * clockPathGroupIndex ) {
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 ( NULL == mControlInterface, 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 () )
{
if ( NULL != clockPathGroupIndex )
{
*clockPathGroupIndex = pathGroupIndex;
}
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;
}
OSArray * AppleUSBAudioDevice::getClockPathGroup ( UInt8 streamInterface, UInt8 altSetting, UInt8 * clockPathGroupIndex ) {
OSNumber * clockSourceIDNumber = NULL;
OSArray * pathGroupArray = NULL;
OSArray * pathArray = NULL;
UInt8 terminalID;
UInt8 clockSourceID;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::getClockPathGroup ( %d, %d )", this, streamInterface, altSetting );
FailIf ( NULL == mConfigDictionary, Exit );
FailIf ( NULL == mControlInterface, Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getTerminalLink ( &terminalID, streamInterface, altSetting ), Exit );
FailIf ( kIOReturnSuccess != mConfigDictionary->getClockSourceID ( &clockSourceID, mControlInterface->GetInterfaceNumber (), 0, terminalID ), Exit );
debugIOLog (" ? AppleUSBAudioDevice::getClockPathGroup () - 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 () )
{
if ( NULL != clockPathGroupIndex )
{
*clockPathGroupIndex = pathGroupIndex;
}
break;
}
else
{
pathGroupArray = NULL;
}
}
FailIf ( NULL == pathGroupArray, Exit );
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::getClockPathGroup ( %d, %d ) = %p", this, streamInterface, altSetting, pathGroupArray );
return pathGroupArray;
}
OSArray * AppleUSBAudioDevice::getClockPathGroup ( UInt8 pathGroupIndex )
{
OSArray * pathGroupArray = NULL;
debugIOLog ( "+ AppleUSBAudioDevice[%p]::getClockPathGroup ( %d )", this, pathGroupIndex );
FailIf ( pathGroupIndex >= mClockGraph->getCount (), Exit );
FailIf ( NULL == ( pathGroupArray = OSDynamicCast ( OSArray, mClockGraph->getObject ( pathGroupIndex ) ) ), Exit );
Exit:
debugIOLog ( "- AppleUSBAudioDevice[%p]::getClockPathGroup ( %d ) = %p", this, pathGroupIndex, pathGroupArray );
return pathGroupArray;
}
IOReturn AppleUSBAudioDevice::getClockSelectorIDAndPathIndex (UInt8 * selectorID, UInt8 * pathIndex, OSArray * clockPath) {
IOReturn result;
result = kIOReturnNotFound;
FailIf ( NULL == mControlInterface, Exit );
FailIf ( NULL == selectorID, Exit );
FailIf ( NULL == pathIndex, Exit );
*selectorID = 0;
*pathIndex = 0;
for ( UInt32 clockIndex = 0; clockIndex < clockPath->getCount (); clockIndex++ )
{
OSNumber * clockIDNumber;
UInt8 clockID;
UInt8 subType;
FailIf ( NULL == ( clockIDNumber = OSDynamicCast ( OSNumber, clockPath->getObject ( clockIndex ) ) ), Exit );
clockID = clockIDNumber->unsigned8BitValue ();
FailIf (kIOReturnSuccess != ( result = mConfigDictionary->getSubType ( &subType, mControlInterface->GetInterfaceNumber(), 0, clockID ) ), Exit );
if (USBAUDIO_0200::CLOCK_SELECTOR == subType)
{
OSArray * clockSourceIDs = NULL;
OSNumber * clockSourceIDNumber = NULL;
OSNumber * nextClockIDNumber = NULL;
UInt8 nextClockID;
FailIf ( kIOReturnSuccess != (result = mConfigDictionary->getClockSelectorSources ( &clockSourceIDs, mControlInterface->GetInterfaceNumber (), 0, clockID ) ), Exit );
FailIf ( NULL == ( nextClockIDNumber = OSDynamicCast ( OSNumber, clockPath->getObject ( clockIndex + 1 ) ) ), Exit );
nextClockID = nextClockIDNumber->unsigned8BitValue ();
for ( UInt32 index = 0; index < clockSourceIDs->getCount (); index++ )
{
FailIf ( NULL == ( clockSourceIDNumber = OSDynamicCast ( OSNumber, clockSourceIDs->getObject ( index ) ) ), Exit );
if ( clockSourceIDNumber->unsigned8BitValue() == nextClockID )
{
*selectorID = clockID;
*pathIndex = index + 1;
result = kIOReturnSuccess;
break;
}
}
}
}
Exit:
return result;
}
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->mIOAudioStreamArray )
{
for ( UInt32 index = 0; index < otherAudioEngine->mIOAudioStreamArray->getCount (); index++ )
{
AppleUSBAudioStream * appleUSBAudioStream = OSDynamicCast ( AppleUSBAudioStream, otherAudioEngine->mIOAudioStreamArray->getObject (index) );
if ( ( NULL != appleUSBAudioStream ) && ( NULL != appleUSBAudioStream->mActiveClockPath ) )
{
if ( clockPathCrossed ( thisClockPath, appleUSBAudioStream->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;
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
UInt32 clockIndex;
UInt8 clockID;
UInt8 subType;
UInt16 numerator;
UInt16 denominator;
UInt32 rateIndex;
OSNumber * rateNumber;
OSArray * rates;
OSNumber * sampleRateNumber;
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 );
for (clockIndex = path->getCount (); clockIndex > 0 ; clockIndex--)
{
FailIf (NULL == (arrayObject = path->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_MULTIPLIER == subType)
{
FailIf (kIOReturnSuccess != (result = getCurClockMultiplier (clockID, &numerator, &denominator)), Exit);
rates = OSArray::withCapacity ( sampleRates->getCount () );
FailIf ( NULL == rates, Exit );
for ( rateIndex = 0; rateIndex < sampleRates->getCount (); rateIndex ++ )
{
sampleRateNumber = OSDynamicCast ( OSNumber, sampleRates->getObject ( rateIndex ) );
FailIf ( NULL == sampleRateNumber, Exit );
rateNumber = OSNumber::withNumber ( sampleRateNumber->unsigned32BitValue () * numerator / denominator, 32 );
FailIf ( NULL == rateNumber, Exit );
rates->setObject ( rateNumber );
rates->release ();
}
if ( NULL != sampleRates )
{
sampleRates->release ();
}
sampleRates = rates;
}
}
FailIf ( kIOReturnSuccess != ( result = mConfigDictionary->addSampleRatesToStreamDictionary ( sampleRates, streamInterface, altSetting ) ), Exit );
Exit:
if ( NULL != sampleRates )
{
sampleRates->release ();
}
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 );
FailIf ( NULL == mControlInterface, Exit );
* sampleRates = NULL;
if ( mConfigDictionary->clockSourceHasFrequencyControl ( mControlInterface->GetInterfaceNumber (), 0, clockSource, true ) ||
mConfigDictionary->clockSourceHasFrequencyControl ( mControlInterface->GetInterfaceNumber (), 0, clockSource, false ) )
{
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 = (char*)"USB streaming"; break;
#if LOCALIZABLE
case INPUT_UNDEFINED: terminalTypeString = (char*)"StringInputUndefined"; break;
case INPUT_MICROPHONE: terminalTypeString = (char*)"StringMicrophone"; break;
case INPUT_DESKTOP_MICROPHONE: terminalTypeString = (char*)"StringDesktopMicrophone"; break;
case INPUT_PERSONAL_MICROPHONE: terminalTypeString = (char*)"StringPersonalMicrophone"; break;
case INPUT_OMNIDIRECTIONAL_MICROPHONE: terminalTypeString = (char*)"StringOmnidirectionalMicrophone"; break;
case INPUT_MICROPHONE_ARRAY: terminalTypeString = (char*)"StringMicrophoneArray"; break;
case INPUT_PROCESSING_MICROPHONE_ARRAY: terminalTypeString = (char*)"StringProcessingMicrophoneArray"; break;
case INPUT_MODEM_AUDIO: terminalTypeString = (char*)"StringModemAudio"; break;
case OUTPUT_UNDEFINED: terminalTypeString = (char*)"StringOutputUndefined"; break;
case OUTPUT_SPEAKER: terminalTypeString = (char*)"StringSpeaker"; break;
case OUTPUT_HEADPHONES: terminalTypeString = (char*)"StringHeadphones"; break;
case OUTPUT_HEAD_MOUNTED_DISPLAY_AUDIO: terminalTypeString = (char*)"StringHeadMountedDisplayAudio"; break;
case OUTPUT_DESKTOP_SPEAKER: terminalTypeString = (char*)"StringDesktopSpeaker"; break;
case OUTPUT_ROOM_SPEAKER: terminalTypeString = (char*)"StringRoomSpeaker"; break;
case OUTPUT_COMMUNICATION_SPEAKER: terminalTypeString = (char*)"StringCommunicationSpeaker"; break;
case OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER: terminalTypeString = (char*)"StringLowFrequencyEffectsSpeaker"; break;
case BIDIRECTIONAL_UNDEFINED: terminalTypeString = (char*)"StringBidirectionalUndefined"; break;
case BIDIRECTIONAL_HANDSET: terminalTypeString = (char*)"StringBidirectionalHandset"; break;
case BIDIRECTIONAL_HEADSET: terminalTypeString = (char*)"StringBidirectionalHeadset"; break;
case BIDIRECTIONAL_SPEAKERPHONE_NO_ECHO_REDX: terminalTypeString = (char*)"StringBidirectionalSpeakerphoneNoEchoRedx"; break;
case BIDIRECTIONAL_ECHO_SUPPRESSING_SPEAKERPHONE: terminalTypeString = (char*)"StringBidirectionalEchoSuppressingSpeakerphone"; break;
case BIDIRECTIONAL_ECHO_CANCELING_SPEAKERPHONE: terminalTypeString = (char*)"StringBidirectionalEchoCancelingSpeakerphone"; break;
case TELEPHONY_UNDEFINED: terminalTypeString = (char*)"StringTelephoneUndefined"; break;
case TELEPHONY_PHONE_LINE: terminalTypeString = (char*)"StringTelephoneLine"; break;
case TELEPHONY_TELEPHONE: terminalTypeString = (char*)"StringTelephone"; break;
case TELEPHONY_DOWN_LINE_PHONE: terminalTypeString = (char*)"StringDownLinePhone"; break;
case EXTERNAL_UNDEFINED: terminalTypeString = (char*)"StringExternalUndefined"; break;
case EXTERNAL_ANALOG_CONNECTOR: terminalTypeString = (char*)"StringExternalAnalogConnector"; break;
case EXTERNAL_DIGITAL_AUDIO_INTERFACE: terminalTypeString = (char*)"StringExternalDigitalAudioInterface"; break;
case EXTERNAL_LINE_CONNECTOR: terminalTypeString = (char*)"StringExternalLineConnector"; break;
case EXTERNAL_LEGACY_AUDIO_CONNECTOR: terminalTypeString = (char*)"StringExternalLegacyAudioConnector"; break;
case EXTERNAL_SPDIF_INTERFACE: terminalTypeString = (char*)"StringExternalSPDIFInterface"; break;
case EXTERNAL_1394_DA_STREAM: terminalTypeString = (char*)"StringExternal1394DAStream"; break;
case EXTERNAL_1394_DV_STREAM_SOUNDTRACK: terminalTypeString = (char*)"StringExternal1394DVStreamSoundtrack"; break;
case EMBEDDED_UNDEFINED: terminalTypeString = (char*)"StringEmbeddedUndefined"; break;
case EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE: terminalTypeString = (char*)"StringEmbeddedLevelCalibrationNoiseSource"; break;
case EMBEDDED_EQUALIZATION_NOISE: terminalTypeString = (char*)"StringEmbeddedEqualizationNoise"; break;
case EMBEDDED_CD_PLAYER: terminalTypeString = (char*)"StringEmbeddedCDPlayer"; break;
case EMBEDDED_DAT: terminalTypeString = (char*)"StringEmbeddedDAT"; break;
case EMBEDDED_DCC: terminalTypeString = (char*)"StringEmbeddedDCC"; break;
case EMBEDDED_MINIDISK: terminalTypeString = (char*)"StringEmbeddedMiniDisc"; break;
case EMBEDDED_ANALOG_TAPE: terminalTypeString = (char*)"StringEmbeddedAnalogTape"; break;
case EMBEDDED_PHONOGRAPH: terminalTypeString = (char*)"StringEmbeddedPhonograph"; break;
case EMBEDDED_VCR_AUDIO: terminalTypeString = (char*)"StringEmbeddedVCRAudio"; break;
case EMBEDDED_VIDEO_DISC_AUDIO: terminalTypeString = (char*)"StringEmbeddedVideoDiscAudio"; break;
case EMBEDDED_DVD_AUDIO: terminalTypeString = (char*)"StringEmbeddedDVDAudio"; break;
case EMBEDDED_TV_TUNER_AUDIO: terminalTypeString = (char*)"StringEmbeddedTVTunerAudio"; break;
case EMBEDDED_SATELLITE_RECEIVER_AUDIO: terminalTypeString = (char*)"StringEmbeddedSatelliteReceiverAudio"; break;
case EMBEDDED_CABLE_TUNER_AUDIO: terminalTypeString = (char*)"StringEmbeddedCableTunerAudio"; break;
case EMBEDDED_DSS_AUDIO: terminalTypeString = (char*)"StringEmbeddedDSSAudio"; break;
case EMBEDDED_RADIO_RECEIVER: terminalTypeString = (char*)"StringEmbeddedRadioReceiver"; break;
case EMBEDDED_RADIO_TRANSMITTER: terminalTypeString = (char*)"StringEmbeddedRadioTransmitter"; break;
case EMBEDDED_MULTITRACK_RECORDER: terminalTypeString = (char*)"StringEmbeddedMultitrackRecorder"; break;
case EMBEDDED_SYNTHESIZER: terminalTypeString = (char*)"StringEmbeddedSynthesizer"; break;
default: terminalTypeString = (char*)"StringUnknown"; break;
#else
case INPUT_UNDEFINED: terminalTypeString = (char*)"InputUndefined"; break;
case INPUT_MICROPHONE: terminalTypeString = (char*)"Microphone"; break;
case INPUT_DESKTOP_MICROPHONE: terminalTypeString = (char*)"Desktop Microphone"; break;
case INPUT_PERSONAL_MICROPHONE: terminalTypeString = (char*)"Personal Microphone"; break;
case INPUT_OMNIDIRECTIONAL_MICROPHONE: terminalTypeString = (char*)"Omnidirectional Microphone"; break;
case INPUT_MICROPHONE_ARRAY: terminalTypeString = (char*)"Microphone Array"; break;
case INPUT_PROCESSING_MICROPHONE_ARRAY: terminalTypeString = (char*)"Processing Microphone Array"; break;
case INPUT_MODEM_AUDIO: terminalTypeString = (char*)"Modem Audio"; break;
case OUTPUT_UNDEFINED: terminalTypeString = (char*)"Output Undefined"; break;
case OUTPUT_SPEAKER: terminalTypeString = (char*)"Speaker"; break;
case OUTPUT_HEADPHONES: terminalTypeString = (char*)"Headphones"; break;
case OUTPUT_HEAD_MOUNTED_DISPLAY_AUDIO: terminalTypeString = (char*)"Head Mounted Display Audio"; break;
case OUTPUT_DESKTOP_SPEAKER: terminalTypeString = (char*)"Desktop Speaker"; break;
case OUTPUT_ROOM_SPEAKER: terminalTypeString = (char*)"Room Speaker"; break;
case OUTPUT_COMMUNICATION_SPEAKER: terminalTypeString = (char*)"Communication Speaker"; break;
case OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER: terminalTypeString = (char*)"Low Frequency Effects Speaker"; break;
case BIDIRECTIONAL_UNDEFINED: terminalTypeString = (char*)"Bidirectional Undefined"; break;
case BIDIRECTIONAL_HANDSET: terminalTypeString = (char*)"Bidirectional Handset"; break;
case BIDIRECTIONAL_HEADSET: terminalTypeString = (char*)"Bidirectional Headset"; break;
case BIDIRECTIONAL_SPEAKERPHONE_NO_ECHO_REDX: terminalTypeString = (char*)"Bidirectional Speakerphone No Echo Redx"; break;
case BIDIRECTIONAL_ECHO_SUPPRESSING_SPEAKERPHONE: terminalTypeString = (char*)"Bidirectional Echo Suppressing Speakerphone"; break;
case BIDIRECTIONAL_ECHO_CANCELING_SPEAKERPHONE: terminalTypeString = (char*)"Bidirectional Echo Canceling Speakerphone"; break;
case TELEPHONY_UNDEFINED: terminalTypeString = (char*)"Telephone Undefined"; break;
case TELEPHONY_PHONE_LINE: terminalTypeString = (char*)"Telephone Line"; break;
case TELEPHONY_TELEPHONE: terminalTypeString = (char*)"Telephone"; break;
case TELEPHONY_DOWN_LINE_PHONE: terminalTypeString = (char*)"Down Line Phone"; break;
case EXTERNAL_UNDEFINED: terminalTypeString = (char*)"External Undefined"; break;
case EXTERNAL_ANALOG_CONNECTOR: terminalTypeString = (char*)"External Analog Connector"; break;
case EXTERNAL_DIGITAL_AUDIO_INTERFACE: terminalTypeString = (char*)"External Digital Audio Interface"; break;
case EXTERNAL_LINE_CONNECTOR: terminalTypeString = (char*)"External Line Connector"; break;
case EXTERNAL_LEGACY_AUDIO_CONNECTOR: terminalTypeString = (char*)"External Legacy Audio Connector"; break;
case EXTERNAL_SPDIF_INTERFACE: terminalTypeString = (char*)"External SPDIF Interface"; break;
case EXTERNAL_1394_DA_STREAM: terminalTypeString = (char*)"External 1394 DA Stream"; break;
case EXTERNAL_1394_DV_STREAM_SOUNDTRACK: terminalTypeString = (char*)"External 1394 DV Stream Soundtrack"; break;
case EMBEDDED_UNDEFINED: terminalTypeString = (char*)"Embedded Undefined"; break;
case EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE: terminalTypeString = (char*)"Embedded Level Calibration Noise Source"; break;
case EMBEDDED_EQUALIZATION_NOISE: terminalTypeString = (char*)"Embedded Equalization Noise"; break;
case EMBEDDED_CD_PLAYER: terminalTypeString = (char*)"Embedded CD Player"; break;
case EMBEDDED_DAT: terminalTypeString = (char*)"Embedded DAT"; break;
case EMBEDDED_DCC: terminalTypeString = (char*)"Embedded DCC"; break;
case EMBEDDED_MINIDISK: terminalTypeString = (char*)"Embedded Mini Disc"; break;
case EMBEDDED_ANALOG_TAPE: terminalTypeString = (char*)"Embedded Analog Tape"; break;
case EMBEDDED_PHONOGRAPH: terminalTypeString = (char*)"Embedded Phonograph"; break;
case EMBEDDED_VCR_AUDIO: terminalTypeString = (char*)"Embedded VCR Audio"; break;
case EMBEDDED_VIDEO_DISC_AUDIO: terminalTypeString = (char*)"Embedded Video Disc Audio"; break;
case EMBEDDED_DVD_AUDIO: terminalTypeString = (char*)"Embedded DVD Audio"; break;
case EMBEDDED_TV_TUNER_AUDIO: terminalTypeString = (char*)"Embedded TV Tuner Audio"; break;
case EMBEDDED_SATELLITE_RECEIVER_AUDIO: terminalTypeString = (char*)"Embedded Satellite Receiver Audio"; break;
case EMBEDDED_CABLE_TUNER_AUDIO: terminalTypeString = (char*)"Embedded Cable Tuner Audio"; break;
case EMBEDDED_DSS_AUDIO: terminalTypeString = (char*)"Embedded DSS Audio"; break;
case EMBEDDED_RADIO_RECEIVER: terminalTypeString = (char*)"Embedded Radio Receiver"; break;
case EMBEDDED_RADIO_TRANSMITTER: terminalTypeString = (char*)"Embedded Radio Transmitter"; break;
case EMBEDDED_MULTITRACK_RECORDER: terminalTypeString = (char*)"Embedded Multitrack Recorder"; break;
case EMBEDDED_SYNTHESIZER: terminalTypeString = (char*)"Embedded Synthesizer"; break;
default: terminalTypeString = (char*)"Unknown"; break;
#endif
}
return terminalTypeString;
}
char * AppleUSBAudioDevice::ClockTypeString (UInt8 clockType)
{
char * clockTypeString;
switch (clockType) {
#if LOCALIZABLE
case USBAUDIO_0200::CLOCK_TYPE_EXTERNAL: clockTypeString = (char*)"StringExternalClock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_FIXED: clockTypeString = (char*)"StringInternalFixedClock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_VARIABLE: clockTypeString = (char*)"StringInternalVariableClock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_PROGRAMMABLE: clockTypeString = (char*)"StringInternalProgrammableClock"; break;
default: clockTypeString = (char*)"StringUnknown"; break;
#else
case USBAUDIO_0200::CLOCK_TYPE_EXTERNAL: clockTypeString = (char*)"External Clock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_FIXED: clockTypeString = (char*)"Internal Fixed Clock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_VARIABLE: clockTypeString = (char*)"Internal Variable Clock"; break;
case USBAUDIO_0200::CLOCK_TYPE_INTERNAL_PROGRAMMABLE: clockTypeString = (char*)"Internal Programmable Clock"; break;
default: clockTypeString = (char*)"Unknown"; break;
#endif
}
return clockTypeString;
}
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;
}
if ( NULL != mInterruptPipe )
{
mInterruptPipe->Abort ();
mInterruptPipe->release ();
mInterruptPipe = NULL;
}
if ( mProcessStatusInterruptThread )
{
thread_call_cancel ( mProcessStatusInterruptThread );
thread_call_free ( mProcessStatusInterruptThread );
mProcessStatusInterruptThread = NULL;
}
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 ( 0 != mEngineArray )
{
for ( UInt32 engineIndex = 0; engineIndex < mEngineArray->getCount (); engineIndex++ )
{
AppleUSBAudioEngine * engine = OSDynamicCast ( AppleUSBAudioEngine, mEngineArray->getObject ( engineIndex ) );
if ( 0 != engine )
{
engine->runPolledTask ();
}
}
}
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;
AppleUSBAudioStream * thisStream = NULL;
AppleUSBAudioStream * otherStream = NULL;
const IOAudioStreamFormat * thisFormat;
const IOAudioStreamFormat * otherFormat;
const IOAudioSampleRate * thisSampleRate;
const IOAudioSampleRate * otherSampleRate;
const IOAudioStreamFormat * thisDefaultAudioStreamFormat;
const IOAudioStreamFormat * otherDefaultAudioStreamFormat;
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);
FailIf (NULL == mControlInterface, Exit);
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->mMainOutputStream ? thisAudioEngine->mMainOutputStream : thisAudioEngine->mMainInputStream;
otherStream = otherAudioEngine->mMainOutputStream ? otherAudioEngine->mMainOutputStream : otherAudioEngine->mMainInputStream;
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);
thisDefaultAudioStreamFormat = &thisStream->mDefaultAudioStreamFormat;
otherDefaultAudioStreamFormat = &otherStream->mDefaultAudioStreamFormat;
FailIf (NULL == thisDefaultAudioStreamFormat, Exit);
FailIf (NULL == otherDefaultAudioStreamFormat, Exit);
debugIOLog ("\n");
debugIOLog ("-------------------- BEFORE --------------------");
debugIOLog ("? AppleUSBAudioDevice[%p]::formatChangeController () - engine %p (interface %d, alternateSetting %d) info:", this, thisAudioEngine, thisStream->mInterfaceNumber, thisStream->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, otherStream->mInterfaceNumber, otherStream->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, thisStream->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, otherStream->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 ( thisDefaultAudioStreamFormat, false );
formatChangeReturnCode = thisAudioEngine->controlledFormatChange (thisStream, thisDefaultAudioStreamFormat, &(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 ( otherDefaultAudioStreamFormat, false );
formatChangeReturnCode = otherAudioEngine->controlledFormatChange (otherStream, otherDefaultAudioStreamFormat, &(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, otherStream->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->mMainOutputStream ? thisAudioEngine->mMainOutputStream : thisAudioEngine->mMainInputStream;
otherStream = otherAudioEngine->mMainOutputStream ? otherAudioEngine->mMainOutputStream : otherAudioEngine->mMainInputStream;
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, thisStream->mInterfaceNumber, thisStream->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, otherStream->mInterfaceNumber, otherStream->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 = IOBufferMemoryDescriptor::withBytes (target, length, kIODirectionOut);
FailIf (NULL == theSettingDesc, Exit);
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 == mControlInterface, 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 == mControlInterface, 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;
FailIf (NULL == mControlInterface, Exit);
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)
{
if (mConfigDictionary->clockSourceHasFrequencyControl (mControlInterface->GetInterfaceNumber (), 0, clockID, true))
{
FailIf (kIOReturnSuccess != (result = setCurClockSourceSamplingFrequency (clockID, sampleRate)), Exit);
}
else
{
result = kIOReturnSuccess;
}
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;
}
#pragma mark Single Audio Engine Capability
OSArray * AppleUSBAudioDevice::findStreamsWithCommonSampleRates (OSArray * availableStreamList) {
OSNumber * streamInterfaceNumber;
OSArray * compatibleStreamList = NULL;
OSArray * inCompatibleStreamList = NULL;
OSArray * result = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::findStreamsWithCommonSampleRates (%p)", this, availableStreamList);
FailIf ( NULL == availableStreamList, Exit );
compatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == compatibleStreamList, Exit );
inCompatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == inCompatibleStreamList, Exit );
while ( 0 != availableStreamList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, availableStreamList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
availableStreamList->removeObject (0);
if ( 0 == compatibleStreamList->getCount () )
{
if ( isSampleRateCommonWithAtLeastOneStreamsInList ( streamInterfaceNumber, availableStreamList ) )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
}
else
{
inCompatibleStreamList->setObject ( streamInterfaceNumber );
}
}
else
{
if ( isSampleRateCommonWithAllStreamsInList ( streamInterfaceNumber, compatibleStreamList ) )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
}
else
{
inCompatibleStreamList->setObject ( streamInterfaceNumber );
}
}
streamInterfaceNumber->release ();
}
FailIf ( 0 != availableStreamList->getCount (), Exit );
if ( 0 != compatibleStreamList->getCount () )
{
result = compatibleStreamList;
result->retain ();
}
else
{
if ( 0 != inCompatibleStreamList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inCompatibleStreamList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inCompatibleStreamList->removeObject (0);
compatibleStreamList->setObject ( streamInterfaceNumber );
result = compatibleStreamList;
result->retain ();
streamInterfaceNumber->release ();
}
}
#ifdef DEBUGLOGGING
if ( NULL != result )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::findStreamsWithCommonSampleRates (%p) - Found streams:", this, availableStreamList);
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < result->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, result->getObject ( streamInterfaceIndex ) );
FailMessage ( NULL == streamInterfaceNumber );
if ( NULL != streamInterfaceNumber )
{
debugIOLog ("--> #%u", streamInterfaceNumber->unsigned8BitValue () );
}
}
}
#endif
Exit:
if ( NULL != inCompatibleStreamList )
{
if ( 0 != inCompatibleStreamList->getCount () )
{
availableStreamList->merge ( inCompatibleStreamList );
}
inCompatibleStreamList->release ();
}
if ( NULL != compatibleStreamList )
{
if ( NULL == result && 0 != compatibleStreamList->getCount () )
{
availableStreamList->merge ( compatibleStreamList );
}
compatibleStreamList->release ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::findStreamsWithCommonSampleRates (%p) - result = %p", this, availableStreamList, result);
return result;
}
bool AppleUSBAudioDevice::isSampleRateCommonWithAtLeastOneStreamsInList (OSNumber * refStreamInterfaceNumber, OSArray * streamInterfaceNumberList) {
bool result = false;
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumberList->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, streamInterfaceNumberList->getObject ( streamInterfaceIndex ) );
FailIf ( NULL == streamInterfaceNumber, Exit );
if ( streamsHaveCommonSampleRates ( refStreamInterfaceNumber, streamInterfaceNumber ) )
{
result = true;
break;
}
}
Exit:
return result;
}
bool AppleUSBAudioDevice::isSampleRateCommonWithAllStreamsInList (OSNumber * refStreamInterfaceNumber, OSArray * streamInterfaceNumberList) {
bool result = true;
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumberList->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, streamInterfaceNumberList->getObject ( streamInterfaceIndex ) );
FailIf ( NULL == streamInterfaceNumber, Exit );
if ( !streamsHaveCommonSampleRates ( refStreamInterfaceNumber, streamInterfaceNumber ) )
{
result = false;
break;
}
}
Exit:
return result;
}
bool AppleUSBAudioDevice::streamsHaveCommonSampleRates (OSNumber * streamInterfaceNumberA, OSNumber * streamInterfaceNumberB) {
bool result = false;
OSArray * sampleRatesA = NULL;
OSArray * sampleRatesB = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::streamsHaveCommonSampleRates (%p, %p)", this, streamInterfaceNumberA, streamInterfaceNumberB);
FailIf ( NULL == streamInterfaceNumberA, Exit );
FailIf ( NULL == streamInterfaceNumberB, Exit );
debugIOLog ("? AppleUSBAudioDevice[%p]::streamsHaveCommonSampleRates (%d, %d)", this, streamInterfaceNumberA->unsigned8BitValue (), streamInterfaceNumberB->unsigned8BitValue ());
sampleRatesA = getSampleRatesFromStreamInterface ( streamInterfaceNumberA );
sampleRatesB = getSampleRatesFromStreamInterface ( streamInterfaceNumberB );
#ifdef DEBUGLOGGING
debugIOLog ("Sample rates for interface %d:", streamInterfaceNumberA->unsigned8BitValue ());
if ( NULL != sampleRatesA )
{
for ( UInt32 rateIndex = 0; rateIndex < sampleRatesA->getCount (); rateIndex++ )
{
OSNumber * rate = OSDynamicCast (OSNumber, sampleRatesA->getObject ( rateIndex ) );
FailMessage ( NULL == rate );
if ( NULL != rate )
{
debugIOLog ("--> %lu", rate->unsigned32BitValue () );
}
}
}
debugIOLog ("Sample rates for interface %d:", streamInterfaceNumberB->unsigned8BitValue ());
if ( NULL != sampleRatesB )
{
for ( UInt32 rateIndex = 0; rateIndex < sampleRatesB->getCount (); rateIndex++ )
{
OSNumber * rate = OSDynamicCast (OSNumber, sampleRatesB->getObject ( rateIndex ) );
FailMessage ( NULL == rate );
if ( NULL != rate )
{
debugIOLog ("--> %lu", rate->unsigned32BitValue () );
}
}
}
#endif
if ( ( NULL != sampleRatesA ) && ( NULL != sampleRatesB ) )
{
if ( compareSampleRates ( sampleRatesA, sampleRatesB ) && compareSampleRates ( sampleRatesB, sampleRatesA ) )
{
result = true;
}
}
Exit:
debugIOLog ("+ AppleUSBAudioDevice[%p]::streamsHaveCommonClocks (%p, %p) - result = %d", this, streamInterfaceNumberA, streamInterfaceNumberB, result);
return result;
}
OSArray * AppleUSBAudioDevice::getSampleRatesFromStreamInterface (OSNumber * streamInterfaceNumber) {
UInt8 interfaceNum;
UInt8 numAltSettings = 0;
OSArray * sampleRates = NULL;
FailIf ( NULL == streamInterfaceNumber, Exit );
interfaceNum = streamInterfaceNumber->unsigned8BitValue ();
if ( kIOReturnSuccess == mConfigDictionary->getNumAltSettings ( &numAltSettings, interfaceNum ) )
{
for ( UInt8 altSetting = 0; altSetting < numAltSettings; altSetting++ )
{
OSArray * rates = mConfigDictionary->getSampleRates ( interfaceNum, altSetting );
if ( NULL != rates )
{
if ( NULL == sampleRates )
{
sampleRates = OSArray::withCapacity ( rates->getCount () );
}
if ( NULL != sampleRates )
{
mergeSampleRates ( sampleRates, rates );
}
}
}
}
Exit:
return sampleRates;
}
void AppleUSBAudioDevice::mergeSampleRates (OSArray * thisArray, OSArray * otherArray)
{
for (UInt32 otherIndex = 0; otherIndex < otherArray->getCount (); otherIndex++)
{
OSNumber * otherRate = OSDynamicCast ( OSNumber, otherArray->getObject ( otherIndex ) );
if ( NULL != otherRate )
{
bool rateFound = false;
for ( UInt32 thisIndex = 0; thisIndex < thisArray->getCount (); thisIndex++ )
{
OSNumber * thisRate = OSDynamicCast ( OSNumber, thisArray->getObject ( thisIndex ) );
if ( NULL != thisRate )
{
if ( thisRate->unsigned32BitValue () == otherRate->unsigned32BitValue () )
{
rateFound = true;
break;
}
}
}
if ( !rateFound )
{
thisArray->setObject ( otherRate );
}
}
}
}
bool AppleUSBAudioDevice::compareSampleRates (OSArray * sampleRatesA, OSArray * sampleRatesB)
{
bool sampleRatesSupported = true;
for ( UInt32 indexA = 0; indexA < sampleRatesA->getCount (); indexA++ )
{
OSNumber * rateA = OSDynamicCast (OSNumber, sampleRatesA->getObject ( indexA ) );
if ( NULL != rateA )
{
bool rateFound = false;
for ( UInt32 indexB = 0; indexB < sampleRatesB->getCount (); indexB++ )
{
OSNumber * rateB = OSDynamicCast (OSNumber, sampleRatesB->getObject ( indexB ) );
if ( NULL != rateB )
{
if ( rateA->unsigned32BitValue () == rateB->unsigned32BitValue () )
{
rateFound = true;
break;
}
}
}
if ( !rateFound )
{
sampleRatesSupported = false;
break;
}
}
}
return sampleRatesSupported;
}
OSArray * AppleUSBAudioDevice::findStreamsWithCompatibleEndpoints (OSArray * availableStreamList) {
OSNumber * streamInterfaceNumber;
OSArray * inputAsynchronousList = NULL;
OSArray * inputAdaptiveList = NULL;
OSArray * inputSynchronousList = NULL;
OSArray * outputAsynchronousList = NULL;
OSArray * outputAdaptiveList = NULL;
OSArray * outputSynchronousList = NULL;
OSArray * inputUnknownList = NULL;
OSArray * outputUnknownList = NULL;
OSArray * compatibleStreamList = NULL;
OSArray * result = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::findStreamsWithCompatibleEndpoints (%p)", this, availableStreamList);
FailIf ( NULL == availableStreamList, Exit );
compatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == compatibleStreamList, Exit );
inputAsynchronousList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBIn, kAsynchSyncType );
inputAdaptiveList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBIn, kAdaptiveSyncType );
inputSynchronousList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBIn, kSynchronousSyncType );
outputAsynchronousList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBOut, kAsynchSyncType );
outputAdaptiveList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBOut, kAdaptiveSyncType );
outputSynchronousList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBOut, kSynchronousSyncType );
inputUnknownList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBIn, kUnknownSyncType );
outputUnknownList = findStreamsWithDirectionAndSyncType ( availableStreamList, kUSBOut, kUnknownSyncType );
FailIf ( 0 != availableStreamList->getCount (), Exit );
if ( NULL != inputAsynchronousList && 0 != inputAsynchronousList->getCount () )
{
compatibleStreamList->merge ( inputAsynchronousList );
inputAsynchronousList->release ();
inputAsynchronousList = 0;
if ( NULL != outputAsynchronousList && 0 != outputAsynchronousList->getCount () )
{
compatibleStreamList->merge ( outputAsynchronousList );
outputAsynchronousList->release ();
outputAsynchronousList = 0;
}
if ( NULL != outputAdaptiveList && 0 != outputAdaptiveList->getCount () )
{
compatibleStreamList->merge ( outputAdaptiveList );
outputAdaptiveList->release ();
outputAdaptiveList = 0;
}
if ( NULL != outputSynchronousList && 0 != outputSynchronousList->getCount () )
{
compatibleStreamList->merge ( outputSynchronousList );
outputSynchronousList->release ();
outputSynchronousList = 0;
}
}
else
{
if ( ( NULL != inputSynchronousList ) || ( NULL != inputAdaptiveList ) )
{
if ( NULL != inputSynchronousList && 0 != inputSynchronousList->getCount () )
{
compatibleStreamList->merge ( inputSynchronousList );
inputSynchronousList->release ();
inputSynchronousList = 0;
}
if ( NULL != inputAdaptiveList && 0 != inputAdaptiveList->getCount () )
{
compatibleStreamList->merge ( inputAdaptiveList );
inputAdaptiveList->release ();
inputAdaptiveList = 0;
}
if ( NULL != outputSynchronousList && 0 != outputSynchronousList->getCount () )
{
compatibleStreamList->merge ( outputSynchronousList );
outputSynchronousList->release ();
outputSynchronousList = 0;
}
if ( NULL != outputAdaptiveList && 0 != outputAdaptiveList->getCount () )
{
compatibleStreamList->merge ( outputAdaptiveList );
outputAdaptiveList->release ();
outputAdaptiveList = 0;
}
}
else
{
if ( ( NULL != outputSynchronousList ) || ( NULL != outputAdaptiveList ) )
{
if ( NULL != outputSynchronousList && 0 != outputSynchronousList->getCount () )
{
compatibleStreamList->merge ( outputSynchronousList );
outputSynchronousList->release ();
outputSynchronousList = 0;
}
if ( NULL != outputAdaptiveList && 0 != outputAdaptiveList->getCount () )
{
compatibleStreamList->merge ( outputAdaptiveList );
outputAdaptiveList->release ();
outputAdaptiveList = 0;
}
}
else
{
if ( NULL != outputAsynchronousList && 0 != outputAsynchronousList->getCount () )
{
compatibleStreamList->merge ( outputAsynchronousList );
outputAsynchronousList->release ();
outputAsynchronousList = 0;
}
}
}
}
if ( 0 != compatibleStreamList->getCount () )
{
result = compatibleStreamList;
result->retain ();
}
else
{
streamInterfaceNumber = NULL;
if ( NULL != inputAsynchronousList && 0 != inputAsynchronousList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inputAsynchronousList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inputAsynchronousList->removeObject (0);
}
else if ( NULL != inputAdaptiveList && 0 != inputAdaptiveList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inputAdaptiveList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inputAdaptiveList->removeObject (0);
}
else if ( NULL != inputSynchronousList && 0 != inputSynchronousList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inputSynchronousList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inputSynchronousList->removeObject (0);
}
else if ( NULL != outputAsynchronousList && 0 != outputAsynchronousList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, outputAsynchronousList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
outputAsynchronousList->removeObject (0);
}
else if ( NULL != outputAdaptiveList && 0 != outputAdaptiveList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, outputAdaptiveList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
outputAdaptiveList->removeObject (0);
}
else if ( NULL != outputSynchronousList && 0 != outputSynchronousList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, outputSynchronousList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
outputSynchronousList->removeObject (0);
}
else if ( NULL != inputUnknownList && 0 != inputUnknownList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inputUnknownList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inputUnknownList->removeObject (0);
}
else if ( NULL != outputUnknownList && 0 != outputUnknownList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, outputUnknownList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
outputUnknownList->removeObject (0);
}
if ( NULL != streamInterfaceNumber )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
result = compatibleStreamList;
result->retain ();
streamInterfaceNumber->release ();
}
}
#ifdef DEBUGLOGGING
if ( NULL != result )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::findStreamsWithCompatibleEndpoints (%p) - Found streams:", this, availableStreamList);
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < result->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, result->getObject ( streamInterfaceIndex ) );
FailMessage ( NULL == streamInterfaceNumber );
if ( NULL != streamInterfaceNumber )
{
debugIOLog ("--> #%u", streamInterfaceNumber->unsigned8BitValue () );
}
}
}
#endif
Exit:
if ( NULL != inputAsynchronousList )
{
if ( 0 != inputAsynchronousList->getCount () )
{
availableStreamList->merge ( inputAsynchronousList );
}
inputAsynchronousList->release ();
}
if ( NULL != inputAdaptiveList )
{
if ( 0 != inputAdaptiveList->getCount () )
{
availableStreamList->merge ( inputAdaptiveList );
}
inputAdaptiveList->release ();
}
if ( NULL != inputSynchronousList )
{
if ( 0 != inputSynchronousList->getCount () )
{
availableStreamList->merge ( inputSynchronousList );
}
inputSynchronousList->release ();
}
if ( NULL != outputAsynchronousList )
{
if ( 0 != outputAsynchronousList->getCount () )
{
availableStreamList->merge ( outputAsynchronousList );
}
outputAsynchronousList->release ();
}
if ( NULL != outputAdaptiveList )
{
if ( 0 != outputAdaptiveList->getCount () )
{
availableStreamList->merge ( outputAdaptiveList );
}
outputAdaptiveList->release ();
}
if ( NULL != outputSynchronousList )
{
if ( 0 != outputSynchronousList->getCount () )
{
availableStreamList->merge ( outputSynchronousList );
}
outputSynchronousList->release ();
}
if ( NULL != inputUnknownList )
{
if ( 0 != inputUnknownList->getCount () )
{
availableStreamList->merge ( inputUnknownList );
}
inputUnknownList->release ();
}
if ( NULL != outputUnknownList )
{
if ( 0 != outputUnknownList->getCount () )
{
availableStreamList->merge ( outputUnknownList );
}
outputUnknownList->release ();
}
if ( NULL != compatibleStreamList )
{
if ( NULL == result && 0 != compatibleStreamList->getCount () )
{
availableStreamList->merge ( compatibleStreamList );
}
compatibleStreamList->release ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::findStreamsWithCompatibleEndpoints (%p) - result = %p", this, availableStreamList, result);
return result;
}
OSArray * AppleUSBAudioDevice::findStreamsWithDirectionAndSyncType (OSArray * availableStreamList, UInt8 direction, UInt8 syncType ) {
OSNumber * streamInterfaceNumber;
OSArray * compatibleStreamList = NULL;
OSArray * inCompatibleStreamList = NULL;
OSArray * result = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::findStreamsWithDirectionAndSyncType (%p, %d, %d)", this, availableStreamList, direction, syncType);
FailIf ( NULL == availableStreamList, Exit );
compatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == compatibleStreamList, Exit );
inCompatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == inCompatibleStreamList, Exit );
while ( 0 != availableStreamList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, availableStreamList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
availableStreamList->removeObject (0);
if ( streamEndpointsHaveSpecifiedDirectionAndSyncType ( streamInterfaceNumber, direction, syncType ) )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
}
else
{
inCompatibleStreamList->setObject ( streamInterfaceNumber );
}
streamInterfaceNumber->release ();
}
FailIf ( 0 != availableStreamList->getCount (), Exit );
if ( 0 != compatibleStreamList->getCount () )
{
result = compatibleStreamList;
result->retain ();
}
#ifdef DEBUGLOGGING
if ( NULL != result )
{
debugIOLog ("- AppleUSBAudioDevice[%p]::findStreamsWithDirectionAndSyncType (%p, %d, %d) - Found streams:", this, availableStreamList, direction, syncType);
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < result->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, result->getObject ( streamInterfaceIndex ) );
FailMessage ( NULL == streamInterfaceNumber );
if ( NULL != streamInterfaceNumber )
{
debugIOLog ("--> #%u", streamInterfaceNumber->unsigned8BitValue () );
}
}
}
#endif
Exit:
if ( NULL != inCompatibleStreamList )
{
if ( 0 != inCompatibleStreamList->getCount () )
{
availableStreamList->merge ( inCompatibleStreamList );
}
inCompatibleStreamList->release ();
}
if ( NULL != compatibleStreamList )
{
if ( NULL == result && 0 != compatibleStreamList->getCount () )
{
availableStreamList->merge ( compatibleStreamList );
}
compatibleStreamList->release ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::findStreamsWithDirectionAndSyncType (%p, %d, %d) - result = %p", this, availableStreamList, direction, syncType, result);
return result;
}
bool AppleUSBAudioDevice::streamEndpointsHaveSpecifiedDirectionAndSyncType ( OSNumber * streamInterfaceNumber, UInt8 endpointDirection, UInt8 endpointSyncType ) {
UInt8 interfaceNum;
UInt8 numAltSettings = 0;
bool hasSpecifiedDirection = true;
bool hasSpecifiedSyncType = true;
bool result = false;
debugIOLog ("+ AppleUSBAudioDevice[%p]::streamEndpointsHaveSpecifiedDirectionAndSyncType (%p, %d, %d)", this, streamInterfaceNumber, endpointDirection, endpointSyncType);
FailIf ( NULL == streamInterfaceNumber, Exit );
interfaceNum = streamInterfaceNumber->unsigned8BitValue ();
debugIOLog ("? AppleUSBAudioDevice[%p]::streamEndpointsHaveSpecifiedDirectionAndSyncType (%d, %d, %d)", this, interfaceNum, endpointDirection, endpointSyncType);
if ( kIOReturnSuccess == mConfigDictionary->getNumAltSettings ( &numAltSettings, interfaceNum ) )
{
bool startAtZero = mConfigDictionary->alternateSettingZeroCanStream ( interfaceNum );
if ( kUnknownSyncType == endpointSyncType )
{
UInt32 compareSyncType = kUnknownSyncType;
hasSpecifiedSyncType = false;
for ( UInt8 altSetting = (startAtZero ? 0 : 1); altSetting < numAltSettings; altSetting++ )
{
UInt8 direction = 0;
UInt8 address = 0;
UInt8 syncType = 0;
if ( ( kIOReturnSuccess == mConfigDictionary->getIsocEndpointDirection (&direction, interfaceNum, altSetting) ) &&
( kIOReturnSuccess == mConfigDictionary->getIsocEndpointAddress (&address, interfaceNum, altSetting, direction) ) &&
( kIOReturnSuccess == mConfigDictionary->getIsocEndpointSyncType (&syncType, interfaceNum, altSetting, address) ) )
{
if ( endpointDirection != direction )
{
hasSpecifiedDirection = false;
break;
}
if ( kUnknownSyncType == compareSyncType )
{
compareSyncType = syncType;
}
else
{
if ( compareSyncType != syncType )
{
hasSpecifiedSyncType = true;
}
}
}
}
}
else
{
for ( UInt8 altSetting = (startAtZero ? 0 : 1); altSetting < numAltSettings; altSetting++ )
{
UInt8 direction = 0;
UInt8 address = 0;
UInt8 syncType = 0;
if ( ( kIOReturnSuccess == mConfigDictionary->getIsocEndpointDirection (&direction, interfaceNum, altSetting) ) &&
( kIOReturnSuccess == mConfigDictionary->getIsocEndpointAddress (&address, interfaceNum, altSetting, direction) ) &&
( kIOReturnSuccess == mConfigDictionary->getIsocEndpointSyncType (&syncType, interfaceNum, altSetting, address) ) )
{
if ( endpointDirection != direction )
{
hasSpecifiedDirection = false;
break;
}
switch ( endpointSyncType )
{
case kNoneSyncType:
case kSynchronousSyncType:
if ( ( kNoneSyncType != syncType ) && ( kSynchronousSyncType != syncType ) )
{
hasSpecifiedSyncType = false;
}
break;
default:
if ( endpointSyncType != syncType )
{
hasSpecifiedSyncType = false;
}
break;
}
}
if ( !hasSpecifiedSyncType) break;
}
}
}
if ( hasSpecifiedDirection && hasSpecifiedSyncType )
{
result = true;
}
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::streamEndpointsHaveSpecifiedDirectionAndSyncType (%p, %d, %d) - result = %d", this, streamInterfaceNumber, endpointDirection, endpointSyncType, result);
return result;
}
OSArray * AppleUSBAudioDevice::findStreamsWithCommonClocks (OSArray * availableStreamList) {
OSNumber * streamInterfaceNumber;
OSArray * compatibleStreamList = NULL;
OSArray * inCompatibleStreamList = NULL;
OSArray * result = NULL;
debugIOLog ("+ AppleUSBAudioDevice[%p]::findStreamsWithCommonClocks (%p)", this, availableStreamList);
FailIf ( NULL == availableStreamList, Exit );
compatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == compatibleStreamList, Exit );
inCompatibleStreamList = OSArray::withCapacity ( 1 );
FailIf ( 0 == inCompatibleStreamList, Exit );
while ( 0 != availableStreamList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, availableStreamList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
availableStreamList->removeObject (0);
if ( 0 == compatibleStreamList->getCount () )
{
if ( isClockCommonWithAtLeastOneStreamsInList ( streamInterfaceNumber, availableStreamList ) )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
}
else
{
inCompatibleStreamList->setObject ( streamInterfaceNumber );
}
}
else
{
if ( isClockCommonWithAllStreamsInList ( streamInterfaceNumber, compatibleStreamList ) )
{
compatibleStreamList->setObject ( streamInterfaceNumber );
}
else
{
inCompatibleStreamList->setObject ( streamInterfaceNumber );
}
}
streamInterfaceNumber->release ();
}
FailIf ( 0 != availableStreamList->getCount (), Exit );
if ( 0 != compatibleStreamList->getCount () )
{
result = compatibleStreamList;
result->retain ();
}
else
{
if ( 0 != inCompatibleStreamList->getCount () )
{
FailIf ( NULL == ( streamInterfaceNumber = OSDynamicCast ( OSNumber, inCompatibleStreamList->getObject (0) ) ), Exit );
streamInterfaceNumber->retain ();
inCompatibleStreamList->removeObject (0);
compatibleStreamList->setObject ( streamInterfaceNumber );
result = compatibleStreamList;
result->retain ();
streamInterfaceNumber->release ();
}
}
#ifdef DEBUGLOGGING
if ( NULL != result )
{
debugIOLog ("? AppleUSBAudioDevice[%p]::findStreamsWithCommonClocks (%p) - Found streams:", this, availableStreamList);
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < result->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, result->getObject ( streamInterfaceIndex ) );
FailMessage ( NULL == streamInterfaceNumber );
if ( NULL != streamInterfaceNumber )
{
debugIOLog ("--> #%u", streamInterfaceNumber->unsigned8BitValue () );
}
}
}
#endif
Exit:
if ( NULL != inCompatibleStreamList )
{
if ( 0 != inCompatibleStreamList->getCount () )
{
availableStreamList->merge ( inCompatibleStreamList );
}
inCompatibleStreamList->release ();
}
if ( NULL != compatibleStreamList )
{
if ( NULL == result && 0 != compatibleStreamList->getCount () )
{
availableStreamList->merge ( compatibleStreamList );
}
compatibleStreamList->release ();
}
debugIOLog ("- AppleUSBAudioDevice[%p]::findStreamsWithCommonClocks (%p) - result = %p", this, availableStreamList, result);
return result;
}
bool AppleUSBAudioDevice::isClockCommonWithAtLeastOneStreamsInList (OSNumber * refStreamInterfaceNumber, OSArray * streamInterfaceNumberList) {
bool result = false;
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumberList->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, streamInterfaceNumberList->getObject ( streamInterfaceIndex ) );
FailIf ( NULL == streamInterfaceNumber, Exit );
if ( streamsHaveCommonClocks ( refStreamInterfaceNumber, streamInterfaceNumber ) )
{
result = true;
break;
}
}
Exit:
return result;
}
bool AppleUSBAudioDevice::isClockCommonWithAllStreamsInList (OSNumber * refStreamInterfaceNumber, OSArray * streamInterfaceNumberList) {
bool result = true;
for ( UInt32 streamInterfaceIndex = 0; streamInterfaceIndex < streamInterfaceNumberList->getCount (); streamInterfaceIndex++ )
{
OSNumber * streamInterfaceNumber = OSDynamicCast (OSNumber, streamInterfaceNumberList->getObject ( streamInterfaceIndex ) );
FailIf ( NULL == streamInterfaceNumber, Exit );
if ( !streamsHaveCommonClocks ( refStreamInterfaceNumber, streamInterfaceNumber ) )
{
result = false;
break;
}
}
Exit:
return result;
}
bool AppleUSBAudioDevice::streamsHaveCommonClocks (OSNumber * streamInterfaceNumberA, OSNumber * streamInterfaceNumberB) {
OSArray * clockPathGroup;
OSArray * clockPath;
UInt8 pathIndex;
UInt8 rateIndex;
UInt32 numClockPathSupported = 0;
UInt32 numClockPathCrossed = 0;
UInt8 interfaceNum;
UInt8 numAltSettings = 0;
bool result = false;
debugIOLog ("+ AppleUSBAudioDevice[%p]::streamsHaveCommonClocks (%p, %p)", this, streamInterfaceNumberA, streamInterfaceNumberB);
FailIf ( NULL == streamInterfaceNumberA, Exit );
FailIf ( NULL == streamInterfaceNumberB, Exit );
debugIOLog ("? AppleUSBAudioDevice[%p]::streamsHaveCommonClocks (%d, %d)", this, streamInterfaceNumberA->unsigned8BitValue (), streamInterfaceNumberB->unsigned8BitValue ());
interfaceNum = streamInterfaceNumberB->unsigned8BitValue ();
if ( kIOReturnSuccess == mConfigDictionary->getNumAltSettings ( &numAltSettings, interfaceNum ) )
{
bool startAtZero = mConfigDictionary->alternateSettingZeroCanStream ( interfaceNum );
for ( UInt8 altSetting = (startAtZero ? 0 : 1); altSetting < numAltSettings; altSetting++ )
{
OSArray * rates = mConfigDictionary->getSampleRates ( interfaceNum, altSetting );
if (NULL != rates)
{
clockPathGroup = getClockPathGroup ( interfaceNum, altSetting );
FailIf ( NULL == clockPathGroup, Exit );
for ( rateIndex = 0; rateIndex < rates->getCount (); rateIndex++ )
{
OSNumber * rate = OSDynamicCast ( OSNumber, rates->getObject ( rateIndex ) );
if (NULL != rate)
{
for ( pathIndex = 0; pathIndex < clockPathGroup->getCount (); pathIndex++ )
{
FailIf ( NULL == ( clockPath = OSDynamicCast ( OSArray, clockPathGroup->getObject ( pathIndex ) ) ), Exit );
if ( supportSampleRateInClockPath ( clockPath, rate->unsigned32BitValue () ) )
{
numClockPathSupported ++;
if ( isClockPathCrossed ( streamInterfaceNumberA, clockPath, rate->unsigned32BitValue () ) )
{
numClockPathCrossed ++;
}
else
{
break;
}
}
}
}
if ( numClockPathSupported != numClockPathCrossed )
{
break;
}
}
}
if ( numClockPathSupported != numClockPathCrossed )
{
break;
}
}
}
result = ( 0 != numClockPathSupported ) && ( 0 != numClockPathCrossed ) && ( numClockPathSupported == numClockPathCrossed );
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::streamsHaveCommonClocks (%p, %p) - result = %d", this, streamInterfaceNumberA, streamInterfaceNumberB, result);
return result;
}
bool AppleUSBAudioDevice::isClockPathCrossed (OSNumber * streamInterfaceNumber, OSArray * otherClockPath, UInt32 sampleRate)
{
UInt8 interfaceNum;
UInt8 numAltSettings = 0;
OSArray * clockPathGroup;
OSArray * thisClockPath;
UInt8 pathIndex;
bool startAtZero;
UInt32 numClockPathSupported = 0;
UInt32 numClockPathCrossed = 0;
bool result = false;
debugIOLog ("+ AppleUSBAudioDevice[%p]::isClockPathCrossed (%p, %p, %lu)", this, streamInterfaceNumber, otherClockPath, sampleRate);
interfaceNum = streamInterfaceNumber->unsigned8BitValue ();
if ( kIOReturnSuccess == mConfigDictionary->getNumAltSettings ( &numAltSettings, interfaceNum ) )
{
startAtZero = mConfigDictionary->alternateSettingZeroCanStream ( interfaceNum );
for ( UInt8 altSetting = (startAtZero ? 0 : 1); altSetting < numAltSettings; altSetting++ )
{
clockPathGroup = getClockPathGroup ( interfaceNum, altSetting );
if ( NULL != clockPathGroup )
{
for ( pathIndex = 0; pathIndex < clockPathGroup->getCount (); pathIndex++ )
{
FailIf ( NULL == ( thisClockPath = OSDynamicCast ( OSArray, clockPathGroup->getObject ( pathIndex ) ) ), Exit );
if ( supportSampleRateInClockPath ( thisClockPath, sampleRate ) )
{
numClockPathSupported ++;
if ( clockPathCrossed ( thisClockPath, otherClockPath ) )
{
numClockPathCrossed ++;
}
else
{
break;
}
}
}
if ( numClockPathSupported != numClockPathCrossed )
{
break;
}
}
}
}
result = ( 0 != numClockPathSupported ) && ( 0 != numClockPathCrossed ) && ( numClockPathSupported == numClockPathCrossed );
Exit:
debugIOLog ("- AppleUSBAudioDevice[%p]::isClockPathCrossed (%p, %p, %lu) - result = %d", this, streamInterfaceNumber, otherClockPath, sampleRate, result);
return result;
}
Generated by GNU enscript 1.6.4.