USBAudioObject.cpp [plain text]
/*
    An object whose purpose is to abstract a USB audio class device descriptor.

    The basic idea is that a USB device is described by a chunk of memory on the device.
    This chunk of memory is formatted with length bytes so that you can skip over any
    data that you don't care about, and is aranged into a basic list, starting with the
    device descriptor, then one or more configuration descriptors, one or more stream
    descriptors, and one or more HID descriptors.  It is possible for the configutation
    and stream descriptors to come in any order and not necessarily all config descriptors,
    then all stream descriptors.

    Because Mac OS X's implementation of USB services doesn't allow you to get the device
    descriptor, this object only parses configuration and interface descriptors.  Code
    calling this object's init function must pass it configuration descriptor pointer,
    which is gotten from the USB services API via GetFullConfigurationDescriptor ().

    To use this code you do all of your interactions through the USBAudioConfigObject.
    You do not directly call any of the other objects.  First allocate a USBAudioConfigObject
    and call its init function which will do the parsing of config descriptor and create
    the other objects as necessary.  Once the config object has been init'ed you should
    call GetNumStreamInterfaces, GetNumAltStreamInterfaces, and GetFirstStreamInterfaceNum
    so that you know how many interfaces there are and can query each interface for its
    properties.  Once you have found an interface that has the properties that you want
    you can proceed with the normal USB calls to select and configure that interface.

    The implementation of USBAudioConfigObject is to create two OSArrays, one for the
    control interfaces and one for the stream interfaces.  As the configuration descriptor
    is parsed new control or stream objects are created and inserted in the appropriate
    array after being filled in with the information from the parsed descriptor.
*/

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

#include "USBAudioObject.h"
#include "AppleUSBAudioCommon.h"

/* ------------------------------------------------------
    USBAudioConfigObject
------------------------------------------------------ */
OSDefineMetaClassAndStructors (USBAudioConfigObject, OSObject);

/*
 	Public methods
*/
USBAudioConfigObject * USBAudioConfigObject::create (const IOUSBConfigurationDescriptor * newConfigurationDescriptor) {
    USBAudioConfigObject *			configObject;

    configObject = new USBAudioConfigObject;

    FailIf (NULL == configObject, Exit);

    if (FALSE == configObject->init (newConfigurationDescriptor)) {
        configObject->release();
        configObject = 0;
    }

Exit:
    return configObject;
}

#if DEBUGLOG
void USBAudioConfigObject::DumpConfigMemoryToIOLog (void) {
#if 0
	UInt8 *	descriptorPtr;
	UInt8	descriptorIndex;
	UInt8	length;

	descriptorPtr = (UInt8*)theConfigurationDescriptorPtr;
	while (*descriptorPtr != 0) {
		length = *descriptorPtr;
		for (descriptorIndex = 0; descriptorIndex < length; descriptorIndex++) {
			debug2IOLog ("%2x ", *descriptorPtr++);
		}
		debugIOLog ("\n");
	}
#endif
}
#endif

bool USBAudioConfigObject::init (const IOUSBConfigurationDescriptor * newConfigurationDescriptor) {
    Boolean				result;

    result = FALSE;
    FailIf (FALSE == OSObject::init (), Exit);
    FailIf (NULL == newConfigurationDescriptor, Exit);

    debug2IOLog ("allocating %d bytes for config descriptor\n", USBToHostWord (newConfigurationDescriptor->wTotalLength));
    theConfigurationDescriptorPtr = (IOUSBConfigurationDescriptor *)IOMalloc (USBToHostWord (newConfigurationDescriptor->wTotalLength) + 1);
    FailIf (NULL == theConfigurationDescriptorPtr, Exit);

    memcpy (theConfigurationDescriptorPtr, newConfigurationDescriptor, USBToHostWord (newConfigurationDescriptor->wTotalLength));
    ((UInt8 *)theConfigurationDescriptorPtr)[USBToHostWord (newConfigurationDescriptor->wTotalLength)] = 0;
#if DEBUGLOG
	DumpConfigMemoryToIOLog ();
#endif

    theControls = OSArray::withCapacity (1);
    FailIf (NULL == theControls, Exit);
    theStreams = OSArray::withCapacity (1);
    FailIf (NULL == theStreams, Exit);

    ParseConfigurationDescriptor ();
    result = TRUE;

Exit:
    return result;
}

void USBAudioConfigObject::free (void) {
    theControls->release ();
    theStreams->release ();
    IOFree (theConfigurationDescriptorPtr, USBToHostWord (theConfigurationDescriptorPtr->wTotalLength) + 1);
    OSObject::free ();
}

Boolean USBAudioConfigObject::ChannelHasMuteControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID, UInt8 channelNum) {
    USBAudioControlObject *				thisControl;
    Boolean								theControl;

    theControl = FALSE;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		theControl = thisControl->ChannelHasMuteControl (featureUnitID, channelNum);

    return theControl;
}

Boolean USBAudioConfigObject::ChannelHasVolumeControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID, UInt8 channelNum) {
    USBAudioControlObject *				thisControl;
    Boolean								theControl;

    theControl = FALSE;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		theControl = thisControl->ChannelHasVolumeControl (featureUnitID, channelNum);

    return theControl;
}

UInt8 USBAudioConfigObject::FindNextAltInterfaceWithNumChannels (UInt8 interfaceNum, UInt8 startingAltInterface, UInt8 numChannelsRequested) {
    UInt16								numAltInterfaces;
	UInt8								altInterface;
	UInt8								altInterfaceIndx;

	altInterface = 255;
	if (startingAltInterface == 0)
		startingAltInterface = 1;
	numAltInterfaces = GetNumAltStreamInterfaces (interfaceNum);
	for (altInterfaceIndx = startingAltInterface; altInterfaceIndx < numAltInterfaces && altInterface == 255; altInterfaceIndx++) {
		if (numChannelsRequested == GetNumChannels (interfaceNum, altInterfaceIndx)) {
			altInterface = altInterfaceIndx;
		}
	}

	return altInterface;
}

UInt8 USBAudioConfigObject::FindNextAltInterfaceWithSampleSize (UInt8 interfaceNum, UInt8 startingAltInterface, UInt8 sampleSizeRequested) {
    UInt16								numAltInterfaces;
	UInt8								altInterface;
	UInt8								altInterfaceIndx;

	altInterface = 255;
	if (startingAltInterface == 0)
		startingAltInterface = 1;
	numAltInterfaces = GetNumAltStreamInterfaces (interfaceNum);
	for (altInterfaceIndx = startingAltInterface; altInterfaceIndx < numAltInterfaces && altInterface == 255; altInterfaceIndx++) {
		if (sampleSizeRequested == GetSampleSize (interfaceNum, altInterfaceIndx)) {
			altInterface = altInterfaceIndx;
		}
	}

	return altInterface;
}

UInt8 USBAudioConfigObject::FindNextAltInterfaceWithSampleRate (UInt8 interfaceNum, UInt8 startingAltInterface, UInt32 sampleRateRequested) {
	UInt16								numAltInterfaces;
	UInt8								altInterface;
	UInt8								altInterfaceIndx;

	altInterface = 255;
	if (startingAltInterface == 0)
		startingAltInterface = 1;
	numAltInterfaces = GetNumAltStreamInterfaces (interfaceNum);
	for (altInterfaceIndx = startingAltInterface; altInterfaceIndx < numAltInterfaces && altInterface == 255; altInterfaceIndx++) {
		if (TRUE == VerifySampleRateIsSupported (interfaceNum, altInterfaceIndx, sampleRateRequested)) {
			altInterface = altInterfaceIndx;
		}
	}

	return altInterface;
}

UInt8 USBAudioConfigObject::FindAltInterfaceWithSettings (UInt8 interfaceNum, UInt8 numChannels, UInt8 sampleSize, UInt32 sampleRate) {
	UInt8			potentialAltInterface;
	UInt8			theAltInterface;
	Boolean			found;

	potentialAltInterface = 1;
	theAltInterface = 255;
	found = FALSE;
	while (!found && potentialAltInterface != 255) {
		potentialAltInterface = FindNextAltInterfaceWithNumChannels (interfaceNum, potentialAltInterface, numChannels);
		FailIf (255 == potentialAltInterface, Exit);
		if (potentialAltInterface == FindNextAltInterfaceWithSampleSize (interfaceNum, potentialAltInterface, sampleSize)) {
			FailIf (255 == potentialAltInterface, Exit);
			if (0 != sampleRate) {
				// they want a specific sample rate on this interface
				if (potentialAltInterface == FindNextAltInterfaceWithSampleRate (interfaceNum, potentialAltInterface, sampleRate)) {
					found = TRUE;
					theAltInterface = potentialAltInterface;
				} else {
					potentialAltInterface++;
				}
			} else {
				// they don't care about the sample rate
				found = TRUE;
				theAltInterface = potentialAltInterface;
			}
		} else {
			potentialAltInterface++;
		}
	}

Exit:
	return theAltInterface;
}

UInt8 USBAudioConfigObject::GetFeatureUnitIDConnectedToOutputTerminal (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 outputTerminalID) {
    USBAudioControlObject *				thisControl;
    UInt8								featureUnitID;

    featureUnitID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		featureUnitID = thisControl->GetFeatureUnitIDConnectedToOutputTerminal (outputTerminalID);

    return featureUnitID;
}

UInt8 USBAudioConfigObject::GetFirstStreamInterfaceNum (void) {
    USBAudioStreamObject * 				thisStream;
	UInt8								interfaceNum;

	interfaceNum = 0;
    thisStream = OSDynamicCast (USBAudioStreamObject, theStreams->getObject (0));
	if (thisStream)
		interfaceNum = thisStream->GetInterfaceNum ();

    return interfaceNum;
}

UInt8 USBAudioConfigObject::GetFirstControlInterfaceNum (void) {
    USBAudioControlObject * 			thisControl;
	UInt8								interfaceNum;

	interfaceNum = 0;
    thisControl = OSDynamicCast (USBAudioControlObject, theControls->getObject (0));
	if (thisControl)
		interfaceNum = thisControl->GetInterfaceNum ();

    return interfaceNum;
}

UInt16 USBAudioConfigObject::GetFormat (UInt8 interfaceNum, UInt8 altInterfaceNum) {
	USBAudioStreamObject * 				thisStream;
	UInt16								formatTag;
	
	formatTag = TYPE_I_UNDEFINED;
	thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	if (thisStream)
		formatTag = thisStream->GetFormatTag ();
	
	return formatTag;
}

UInt32 USBAudioConfigObject::GetHighestSampleRate (UInt8 interfaceNum, UInt8 altInterfaceNum) {
	UInt32 *				sampleRates;
	UInt32					highSampleRate;
	UInt32					i;
	UInt8					numSampleRates;
	UInt8					highest;

	highSampleRate = 0;
	numSampleRates = GetNumSampleRates (interfaceNum, altInterfaceNum);
	sampleRates = GetSampleRates (interfaceNum, altInterfaceNum);
	FailIf (NULL == sampleRates, Exit);

	highest = 0;
	for (i = 1; i < numSampleRates; i++) {
		if (sampleRates[i] > sampleRates[highest])
			highest = i;
	}

	highSampleRate = sampleRates[highest];

Exit:
	return highSampleRate;
}

UInt8 USBAudioConfigObject::GetIsocAssociatedEndpointAddress (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address) {
	USBAudioStreamObject * 				thisStream;
	UInt8								assocEndpointAddress;
	
	assocEndpointAddress = 0;
	thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	if (thisStream)
		assocEndpointAddress = thisStream->GetIsocAssociatedEndpointAddress (address);
	
	return assocEndpointAddress;
}

UInt8 USBAudioConfigObject::GetIsocAssociatedEndpointRefreshInt (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address) {
	USBAudioStreamObject * 				thisStream;
	UInt8								assocEndpointRefresh;
	
	assocEndpointRefresh = 0;
	thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	if (thisStream)
		assocEndpointRefresh = thisStream->GetIsocAssociatedEndpointRefreshInt (address);
	
	return assocEndpointRefresh;
}

UInt8 USBAudioConfigObject::GetIsocEndpointAddress (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 direction) {
	USBAudioStreamObject * 				thisStream;
	UInt8								endpointAddress;
	
	endpointAddress = 0;
	thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	if (thisStream)
		endpointAddress = thisStream->GetIsocEndpointAddress (direction);
	
	return endpointAddress;
}

// Use GetTerminalLink to get the unit number of the input or output terminal that the endpoint is associated with.
// Once you have that terminal, you can figure out if it's an input or output terminal, and once you know that you
// know which direction the endpoint is supposed to be.
UInt8 USBAudioConfigObject::GetIsocEndpointDirection (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    USBAudioControlObject * 			thisControl;
    UInt8								endpointDirection;
	UInt8								terminalLink;
	UInt8								numOutputs;
	UInt8								numInputs;
	UInt8								index;
	UInt8								terminalID;
	UInt8								direction;

	endpointDirection = 0xFF;
	direction = 0xFF;
	index = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	debug4IOLog ("GetIsocEndpointDirection (%d, %d), thisStream = %p\n", interfaceNum, altInterfaceNum, thisStream);
    thisControl = GetControlObject (0, 0);
	debug4IOLog ("GetIsocEndpointDirection (%d, %d), thisControl = %p\n", interfaceNum, altInterfaceNum, thisControl);
	if (thisStream && thisControl) {
		terminalLink = thisStream->GetTerminalLink ();		// returns the unitID of the terminal the endpoint goes with
		debug4IOLog ("GetIsocEndpointDirection (%d, %d), terminalLink = %d\n", interfaceNum, altInterfaceNum, terminalLink);
		if (0 != terminalLink) {
			numOutputs = thisControl->GetNumOutputTerminals ();
			debug4IOLog ("GetIsocEndpointDirection (%d, %d), numOutputs = %d\n", interfaceNum, altInterfaceNum, numOutputs);
			while (0xFF == direction && index < numOutputs) {
				terminalID = thisControl->GetIndexedOutputTerminalID (index);
				debug4IOLog ("GetIsocEndpointDirection (%d, %d), terminalID = %d\n", interfaceNum, altInterfaceNum, terminalID);
				if (terminalID == terminalLink) {
					direction = kUSBIn;
					debug4IOLog ("GetIsocEndpointDirection (%d, %d), found an output terminal (#%d)\n", interfaceNum, altInterfaceNum, terminalID);
				} else {
					index++;
				}
			}
			numInputs = thisControl->GetNumInputTerminals ();
			debug4IOLog ("GetIsocEndpointDirection (%d, %d), numInputs = %d\n", interfaceNum, altInterfaceNum, numInputs);
			index = 0;
			while (0xFF == direction && index < numInputs) {
				terminalID = thisControl->GetIndexedInputTerminalID (index);
				debug4IOLog ("GetIsocEndpointDirection, terminalID = %d\n", interfaceNum, altInterfaceNum, terminalID);
				if (terminalID == terminalLink) {
					direction = kUSBOut;
					debug4IOLog ("GetIsocEndpointDirection (%d, %d), found an input terminal (#%d)\n", interfaceNum, altInterfaceNum, terminalID);
				} else {
					index++;
				}
			}
		}
		if (0xFF != direction)
			endpointDirection = thisStream->GetIsocEndpointDirection (index);
	}

    return endpointDirection;
}

UInt8 USBAudioConfigObject::GetIsocEndpointSyncType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address) {
	USBAudioStreamObject * 				thisStream;
	UInt8								endpointSyncType;
	
	endpointSyncType = 0;
	thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
	if (thisStream)
		endpointSyncType = thisStream->GetIsocEndpointSyncType (address);
	
	return endpointSyncType;
}

UInt8 USBAudioConfigObject::GetIndexedFeatureUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitIndex) {
    USBAudioControlObject *				thisControl;
    UInt8								featureUnitID;

    featureUnitID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		featureUnitID = thisControl->GetIndexedFeatureUnitID (featureUnitIndex);

    return featureUnitID;
}

UInt8 USBAudioConfigObject::GetIndexedMixerUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 mixerUnitIndex) {
    USBAudioControlObject *				thisControl;
    UInt8								mixerUnitID;

    mixerUnitID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		mixerUnitID = thisControl->GetIndexedMixerUnitID (mixerUnitIndex);

    return mixerUnitID;
}

UInt8 USBAudioConfigObject::GetIndexedSelectorUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 selectorUnitIndex) {
    USBAudioControlObject *				thisControl;
    UInt8								selectorUnitID;

    selectorUnitID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		selectorUnitID = thisControl->GetIndexedSelectorUnitID (selectorUnitIndex);

    return selectorUnitID;
}

UInt16 USBAudioConfigObject::GetIndexedInputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalType;

	terminalType = INPUT_UNDEFINED;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalType = thisControl->GetIndexedInputTerminalType (index);

    return terminalType;
}

UInt8 USBAudioConfigObject::GetIndexedInputTerminalID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalID;

	terminalID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalID = thisControl->GetIndexedInputTerminalID (index);

    return terminalID;
}

UInt8 USBAudioConfigObject::GetIndexedOutputTerminalID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalID;

	terminalID = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalID = thisControl->GetIndexedOutputTerminalID (index);

    return terminalID;
}

UInt16 USBAudioConfigObject::GetIndexedOutputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalType;

	terminalType = OUTPUT_UNDEFINED;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalType = thisControl->GetIndexedOutputTerminalType (index);

    return terminalType;
}

UInt16 USBAudioConfigObject::GetInputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 terminalNum) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalType;

    terminalType = INPUT_UNDEFINED;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalType = thisControl->GetInputTerminalType (terminalNum);

    return terminalType;
}

UInt8 USBAudioConfigObject::GetInterfaceClass (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								interfaceClass;

    interfaceClass = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        interfaceClass = thisStream->GetInterfaceClass ();

    return interfaceClass;
}

UInt8 USBAudioConfigObject::GetInterfaceSubClass (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								interfaceSubClass;

    interfaceSubClass = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        interfaceSubClass = thisStream->GetInterfaceSubClass ();

    return interfaceSubClass;
}

UInt32 USBAudioConfigObject::GetLowestSampleRate (UInt8 interfaceNum, UInt8 altInterfaceNum) {
	UInt32 *				sampleRates;
	UInt32					lowSampleRate;
	UInt32					i;
	UInt8					numSampleRates;
	UInt8					lowest;

	lowSampleRate = 0xFFFFFFFF;
	numSampleRates = GetNumSampleRates (interfaceNum, altInterfaceNum);
	sampleRates = GetSampleRates (interfaceNum, altInterfaceNum);
	FailIf (NULL == sampleRates, Exit);

	lowest = 0;
	for (i = 1; i < numSampleRates; i++) {
		if (sampleRates[i] < sampleRates[lowest])
			lowest = i;
	}

	lowSampleRate = sampleRates[lowest];

Exit:
	return lowSampleRate;
}

UInt8 USBAudioConfigObject::GetNumAltStreamInterfaces (UInt8 interfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt16								numAltInterfaces;
    UInt16								indx;

    numAltInterfaces = 0;
    debug2IOLog ("USBAudioConfigObject::GetNumAltInterfaces %d = theStreams->getCount ()\n", theStreams->getCount ());
    for (indx = 0; indx < theStreams->getCount (); indx++) {
        thisStream = OSDynamicCast (USBAudioStreamObject, theStreams->getObject (indx));
		if (thisStream && thisStream->GetInterfaceNum () == interfaceNum) {
			numAltInterfaces++;
		}
    }

    return numAltInterfaces;
}

UInt8 USBAudioConfigObject::GetNumChannels (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								numChannels;

    numChannels = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        numChannels = thisStream->GetNumChannels ();

    return numChannels;
}

UInt8 USBAudioConfigObject::GetNumSampleRates (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								numSampleRates;

    numSampleRates = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        numSampleRates = thisStream->GetNumSampleRates ();

    return numSampleRates;
}

UInt8 USBAudioConfigObject::GetNumInputTerminals (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioControlObject * 			thisControl;
	UInt8								numInputTerminals;

	numInputTerminals = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		numInputTerminals = thisControl->GetNumInputTerminals ();

	return numInputTerminals;
}

UInt8 USBAudioConfigObject::GetNumOutputTerminals (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioControlObject * 			thisControl;
	UInt8								numOutputTerminals;

	numOutputTerminals = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		numOutputTerminals = thisControl->GetNumOutputTerminals ();

	return numOutputTerminals;
}

UInt8 USBAudioConfigObject::GetNumSelectorSources (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 unitID) {
    USBAudioControlObject * 			thisControl;
	UInt8								numSelectorSources;

	numSelectorSources = 0;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		numSelectorSources = thisControl->GetNumSelectorSources (unitID);

	return numSelectorSources;
}

UInt8 USBAudioConfigObject::GetNumStreamInterfaces (void) {
    USBAudioStreamObject * 				thisStream;
    UInt16								numInterfaces;
    UInt16								interfaceNum;
    UInt16								indx;

    numInterfaces = 0;
    interfaceNum = 0;
    debug2IOLog ("USBAudioConfigObject::GetNumInterfaces %d = theStreams->getCount ()\n", theStreams->getCount ());
    for (indx = 0; indx < theStreams->getCount (); indx++) {
        thisStream = OSDynamicCast (USBAudioStreamObject, theStreams->getObject (indx));
		if (thisStream && thisStream->GetInterfaceNum () != interfaceNum) {
			interfaceNum = thisStream->GetInterfaceNum ();
			numInterfaces++;
		}
    }

    return numInterfaces;
}

UInt32 * USBAudioConfigObject::GetSampleRates (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt32 *							sampleRates;

    sampleRates = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        sampleRates = thisStream->GetSampleRates ();

    return sampleRates;
}

UInt8 USBAudioConfigObject::GetSampleSize (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								sampleSize;

    sampleSize = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        sampleSize = thisStream->GetSampleSize ();

    return sampleSize;
}

UInt8 * USBAudioConfigObject::GetSelectorSources (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 unitID) {
    USBAudioControlObject *				thisControl;
    UInt8 *								sources;

    sources = NULL;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
        sources = thisControl->GetSelectorSources (unitID);

    return sources;
}

UInt8 USBAudioConfigObject::GetSubframeSize (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								subframeSize;

    subframeSize = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        subframeSize = thisStream->GetSubframeSize ();

    return subframeSize;
}

UInt8 USBAudioConfigObject::GetTerminalLink (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								terminalLink;

    terminalLink = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        terminalLink = thisStream->GetTerminalLink ();

    return terminalLink;
}

UInt16 USBAudioConfigObject::GetOutputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 terminalNum) {
    USBAudioControlObject *				thisControl;
    UInt16								terminalType;

    terminalType = OUTPUT_UNDEFINED;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		terminalType = thisControl->GetOutputTerminalType (terminalNum);

    return terminalType;
}

Boolean USBAudioConfigObject::IsocEndpointDoesMaxPacketsOnly (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
	Boolean								maxPacketsOnly;

	maxPacketsOnly = FALSE;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        maxPacketsOnly = thisStream->IsocEndpointDoesMaxPacketsOnly ();

    return maxPacketsOnly;
}

UInt8 USBAudioConfigObject::IsocEndpointGetLockDelay (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
	UInt8								lockDelay;

	lockDelay = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        lockDelay = thisStream->IsocEndpointGetLockDelay ();

    return lockDelay;
}

UInt8 USBAudioConfigObject::IsocEndpointGetLockDelayUnits (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
	UInt8								lockDelayUnits;

	lockDelayUnits = 0;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        lockDelayUnits = thisStream->IsocEndpointGetLockDelayUnits ();

    return lockDelayUnits;
}

Boolean USBAudioConfigObject::IsocEndpointHasPitchControl (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
	Boolean								hasPitchCntrl;

	hasPitchCntrl = FALSE;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        hasPitchCntrl = thisStream->IsocEndpointHasPitchControl ();

    return hasPitchCntrl;
}

Boolean USBAudioConfigObject::IsocEndpointHasSampleFreqControl (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
	Boolean								hasSampleFreqCntrl;

	hasSampleFreqCntrl = FALSE;
    thisStream = GetStreamObject (interfaceNum, altInterfaceNum);
    if (thisStream)
        hasSampleFreqCntrl = thisStream->IsocEndpointHasSampleFreqControl ();

    return hasSampleFreqCntrl;
}

Boolean USBAudioConfigObject::MasterHasMuteControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID) {
    USBAudioControlObject *				thisControl;
    Boolean								theControl;

    theControl = FALSE;
    thisControl = GetControlObject (interfaceNum, altInterfaceNum);
    if (thisControl)
		theControl = thisControl->MasterHasMuteControl (featureUnitID);

    return theControl;
}

Boolean USBAudioConfigObject::VerifySampleRateIsSupported (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt32 verifyRate) {
	IOReturn							result;
	UInt32 *							sampleRates;
	UInt8								rateIndx;
	UInt8								numSampleRates;

	result = FALSE;
	numSampleRates = GetNumSampleRates (interfaceNum, altInterfaceNum);
	sampleRates = GetSampleRates (interfaceNum, altInterfaceNum);
	if (numSampleRates) {
		// There are a discrete number of sample rates supported, so check each one to see if they support the one we want.
		for (rateIndx = 0; rateIndx < numSampleRates && result == FALSE; rateIndx++) {
			if (sampleRates[rateIndx] == verifyRate) {
				result = TRUE;
			}
		}
	} else if (sampleRates) {
		// There is a range of sample rates supported, so check to see if the one we want is within that range.
		if (sampleRates[0] <= verifyRate && sampleRates[1] >= verifyRate) {
			result = TRUE;
		}
	} else {
		debugIOLog ("!!!!There aren't any sample rates!!!!\n");
	}

	return result;
}

/*
    Private methods
*/
USBAudioStreamObject * USBAudioConfigObject::GetStreamObject (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioStreamObject * 				thisStream;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisStream = NULL;
    while (!found && indx < theStreams->getCount ()) {
        thisStream = OSDynamicCast (USBAudioStreamObject, theStreams->getObject (indx));
        if (thisStream && interfaceNum == thisStream->GetInterfaceNum () && altInterfaceNum == thisStream->GetAltInterfaceNum ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisStream = NULL;

    return thisStream;
}

USBAudioControlObject * USBAudioConfigObject::GetControlObject (UInt8 interfaceNum, UInt8 altInterfaceNum) {
    USBAudioControlObject * 			thisControl;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisControl = NULL;
    while (!found && indx < theControls->getCount ()) {
        thisControl = OSDynamicCast (USBAudioControlObject, theControls->getObject (indx));
        if (thisControl && interfaceNum == thisControl->GetInterfaceNum () && altInterfaceNum == thisControl->GetAltInterfaceNum ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisControl = NULL;

    return thisControl;
}

void USBAudioConfigObject::ParseConfigurationDescriptor (void) {
    USBInterfaceDescriptorPtr			theInterfacePtr;
    USBAudioControlObject *				theControlObject;
    USBAudioStreamObject *				theStreamObject;
    UInt8								interfaceClass;
    UInt8								interfaceSubClass;

    FailIf (NULL == theConfigurationDescriptorPtr, Exit);
    FailIf (0 == theConfigurationDescriptorPtr->bLength, Exit);
    FailIf (CONFIGURATION != theConfigurationDescriptorPtr->bDescriptorType, Exit);

    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theConfigurationDescriptorPtr + theConfigurationDescriptorPtr->bLength);
    while (0 != theInterfacePtr->bLength) {
        switch (theInterfacePtr->bDescriptorType) {
            case INTERFACE:
                debugIOLog ("in INTERFACE in ParseConfigurationDescriptor\n");
                theInterfacePtr = ParseInterfaceDescriptor (theInterfacePtr, &interfaceClass, &interfaceSubClass);
                debug3IOLog ("interfaceClass = %d, interfaceSubClass = %d\n", interfaceClass, interfaceSubClass);
                break;
            case CS_INTERFACE:
                debugIOLog ("in CS_INTERFACE in ParseConfigurationDescriptor\n");
				if (CONTROL == interfaceSubClass) {
					debugIOLog ("found a CONTROL CS_INTERFACE \n");
					theControlObject = OSDynamicCast (USBAudioControlObject, theControls->getLastObject ());
					theInterfacePtr = theControlObject->ParseACInterfaceDescriptor (theInterfacePtr, ((ACInterfaceDescriptorPtr)theInterfacePtr)->bInterfaceNumber);
					theControls->replaceObject (theControls->getCount () - 1, theControlObject);
				} else if (STREAM == interfaceSubClass) {
					debugIOLog ("found a STREAM CS_INTERFACE \n");
					theStreamObject = OSDynamicCast (USBAudioStreamObject, theStreams->getLastObject ());
					theInterfacePtr = theStreamObject->ParseASInterfaceDescriptor (theInterfacePtr, ((ACInterfaceDescriptorPtr)theInterfacePtr)->bInterfaceNumber);
					theStreams->replaceObject (theStreams->getCount () - 1, theStreamObject);
				}
                break;
            default:
                debugIOLog ("in default in ParseConfigurationDescriptor\n");
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
        }
    }

Exit:
    return;
}

USBInterfaceDescriptorPtr USBAudioConfigObject::ParseInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 * interfaceClass, UInt8 * interfaceSubClass) {
    USBAudioControlObject *				theControlObject;
    USBAudioStreamObject *				theStreamObject;

    debugIOLog ("in ParseInterfaceDescriptor\n");

    FailIf (NULL == theInterfacePtr, Exit);
    FailIf (0 == theInterfacePtr->bLength, Exit);
    FailIf (INTERFACE != theInterfacePtr->bDescriptorType, Exit);

    if (NULL != interfaceClass)
        *interfaceClass = theInterfacePtr->bInterfaceClass;
    if (NULL != interfaceSubClass)
        *interfaceSubClass = theInterfacePtr->bInterfaceSubClass;

    if (CONTROL == theInterfacePtr->bInterfaceSubClass) {
        debugIOLog ("found a CONTROL interface\n");
        theControlObject = USBAudioControlObject::create ();
        theControlObject->SetInterfaceNumber (theInterfacePtr->bDescriptorSubtype);
        theControlObject->SetAlternateSetting (theInterfacePtr->bAlternateSetting);
        theControlObject->SetNumEndpoints (theInterfacePtr->bNumEndpoints);
        theControlObject->SetInterfaceClass (theInterfacePtr->bInterfaceClass);
        theControlObject->SetInterfaceSubClass (theInterfacePtr->bInterfaceSubClass);
        theControlObject->SetInterfaceProtocol (theInterfacePtr->bInterfaceProtocol);
        theControls->setObject (theControlObject);
        theControlObject->release ();
    } else if (STREAM == theInterfacePtr->bInterfaceSubClass) {
        debugIOLog ("found a STREAM interface\n");
        theStreamObject = USBAudioStreamObject::create ();
        theStreamObject->SetInterfaceNumber (theInterfacePtr->bDescriptorSubtype);
        theStreamObject->SetAlternateSetting (theInterfacePtr->bAlternateSetting);
        theStreamObject->SetNumEndpoints (theInterfacePtr->bNumEndpoints);
        theStreamObject->SetInterfaceClass (theInterfacePtr->bInterfaceClass);
        theStreamObject->SetInterfaceSubClass (theInterfacePtr->bInterfaceSubClass);
        theStreamObject->SetInterfaceProtocol (theInterfacePtr->bInterfaceProtocol);
        theStreams->setObject (theStreamObject);
        theStreamObject->release ();
    }

    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);

Exit:
    return theInterfacePtr;
}

/* ------------------------------------------------------
    USBAudioControlObject
------------------------------------------------------ */
/*
	Public methods
*/
OSDefineMetaClassAndStructors (USBAudioControlObject, OSObject);

USBAudioControlObject * USBAudioControlObject::create (void) {
    USBAudioControlObject *			controlObject;

    controlObject = new USBAudioControlObject;

    FailIf (NULL == controlObject, Exit);
    if (FALSE == controlObject->init ()) {
        controlObject->release ();
        controlObject = 0;
    }

Exit:
    return controlObject;
}

void USBAudioControlObject::free (void) {
	theInputTerminals->release ();
	theOutputTerminals->release ();
	theFeatureUnits->release ();
	theMixerUnits->release ();
	theSelectorUnits->release ();
    OSObject::free ();
}

// Channel #1 is left channel, #2 is right channel
Boolean USBAudioControlObject::ChannelHasMuteControl (UInt8 featureUnitID, UInt8 channelNum) {
	USBFeatureUnitObject *				thisFeatureUnit;
	Boolean								result;

	result = FALSE;
	thisFeatureUnit = GetFeatureUnitObject (featureUnitID);
	if (thisFeatureUnit)
		result = thisFeatureUnit->ChannelHasMuteControl (channelNum);

	return result;
}

Boolean USBAudioControlObject::ChannelHasVolumeControl (UInt8 featureUnitID, UInt8 channelNum) {
	USBFeatureUnitObject *				thisFeatureUnit;
	Boolean								result;

	result = FALSE;
	thisFeatureUnit = GetFeatureUnitObject (featureUnitID);
	if (thisFeatureUnit)
		result = thisFeatureUnit->ChannelHasVolumeControl (channelNum);

	return result;
}

USBACDescriptorObject * USBAudioControlObject::GetACDescriptorObject (UInt8 unitID) {
    USBACDescriptorObject * 			thisACDescriptorObject;
    UInt8								indx;
    Boolean								done;

    indx = 0;
    done = FALSE;
	thisACDescriptorObject = GetInputTerminalObject (unitID);
	if (!thisACDescriptorObject)
		thisACDescriptorObject = GetOutputTerminalObject (unitID);
	if (!thisACDescriptorObject)
		thisACDescriptorObject = GetMixerObject (unitID);

    return thisACDescriptorObject;
}

UInt8 USBAudioControlObject::GetFeatureSourceID (UInt8 featureUnitID) {
	USBFeatureUnitObject *		theFeatureUnit;
	UInt8						sourceID;

	sourceID = 0;
	theFeatureUnit = GetFeatureUnitObject (featureUnitID);
	if (theFeatureUnit)
		sourceID = theFeatureUnit->GetSourceID ();

	return sourceID;
}

UInt8 USBAudioControlObject::GetIndexedFeatureUnitID (UInt8 featureUnitIndex) {
	USBFeatureUnitObject *				theFeatureUnit;
	UInt8								unitID;

	unitID = 0;
	theFeatureUnit = GetIndexedFeatureUnitObject (featureUnitIndex);
	if (theFeatureUnit)
		unitID = theFeatureUnit->GetUnitID ();

	return unitID;
}

UInt8 USBAudioControlObject::GetIndexedMixerUnitID (UInt8 mixerUnitIndex) {
	USBMixerUnitObject *				theMixerUnit;
	UInt8								unitID;

	unitID = 0;
	theMixerUnit = GetIndexedMixerUnitObject (mixerUnitIndex);
	if (theMixerUnit)
		unitID = theMixerUnit->GetUnitID ();

	return unitID;
}

UInt8 USBAudioControlObject::GetIndexedSelectorUnitID (UInt8 selectorUnitIndex) {
	USBSelectorUnitObject *				theSelectorUnit;
	UInt8								unitID;

	unitID = 0;
	theSelectorUnit = GetIndexedSelectorUnitObject (selectorUnitIndex);
	if (theSelectorUnit)
		unitID = theSelectorUnit->GetUnitID ();

	return unitID;
}

UInt8 USBAudioControlObject::GetFeatureUnitIDConnectedToOutputTerminal (UInt8 outputTerminalID) {
    USBOutputTerminalObject *			thisOutputTerminal;
	USBFeatureUnitObject *				thisFeatureUnit;
	UInt8								outputTerminalSourceID;
	UInt8								featureUnitID;

	outputTerminalSourceID = 0;
	featureUnitID = 0;
	thisOutputTerminal = GetOutputTerminalObject (outputTerminalID);
    if (thisOutputTerminal)
		outputTerminalSourceID = thisOutputTerminal->GetSourceID ();

	if (0 != outputTerminalSourceID) {
		thisFeatureUnit = GetFeatureUnitObject (outputTerminalSourceID);
		if (thisFeatureUnit)
			featureUnitID = outputTerminalSourceID;
		else {
			// have to keep looking upstream of whatever this object is
		}
	}

	return featureUnitID;
}

UInt16 USBAudioControlObject::GetIndexedInputTerminalType (UInt8 index) {
    USBInputTerminalObject *			thisInputTerminal;
    UInt16								terminalType;

    terminalType = INPUT_UNDEFINED;
    thisInputTerminal = OSDynamicCast (USBInputTerminalObject, theInputTerminals->getObject (index));
    if (thisInputTerminal)
		terminalType = thisInputTerminal->GetTerminalType ();

	return terminalType;
}

UInt8 USBAudioControlObject::GetIndexedInputTerminalID (UInt8 index) {
    USBInputTerminalObject *			thisInputTerminal;
    UInt8								terminalID;

    terminalID = 0;
    thisInputTerminal = OSDynamicCast (USBInputTerminalObject, theInputTerminals->getObject (index));
    if (thisInputTerminal)
		terminalID = thisInputTerminal->GetUnitID ();

	return terminalID;
}

UInt8 USBAudioControlObject::GetIndexedOutputTerminalID (UInt8 index) {
    USBOutputTerminalObject *			thisOutputTerminal;
    UInt8								terminalID;

    terminalID = 0;
    thisOutputTerminal = OSDynamicCast (USBOutputTerminalObject, theOutputTerminals->getObject (index));
    if (thisOutputTerminal)
		terminalID = thisOutputTerminal->GetUnitID ();

	return terminalID;
}

UInt16 USBAudioControlObject::GetIndexedOutputTerminalType (UInt8 index) {
    USBOutputTerminalObject *			thisOutputTerminal;
    UInt16								terminalType;

    terminalType = OUTPUT_UNDEFINED;
    thisOutputTerminal = OSDynamicCast (USBOutputTerminalObject, theOutputTerminals->getObject (index));
    if (thisOutputTerminal)
		terminalType = thisOutputTerminal->GetTerminalType ();

	return terminalType;
}

USBFeatureUnitObject * USBAudioControlObject::GetIndexedFeatureUnitObject (UInt8 index) {
    return OSDynamicCast (USBFeatureUnitObject, theFeatureUnits->getObject (index));
}

USBMixerUnitObject * USBAudioControlObject::GetIndexedMixerUnitObject (UInt8 index) {
    return OSDynamicCast (USBMixerUnitObject, theMixerUnits->getObject (index));
}

USBSelectorUnitObject * USBAudioControlObject::GetIndexedSelectorUnitObject (UInt8 index) {
    return OSDynamicCast (USBSelectorUnitObject, theSelectorUnits->getObject (index));
}

USBFeatureUnitObject * USBAudioControlObject::GetFeatureUnitObject (UInt8 unitID) {
    USBFeatureUnitObject *	 			thisFeatureUnit;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisFeatureUnit = NULL;
    while (!found && indx < theFeatureUnits->getCount ()) {
        thisFeatureUnit = OSDynamicCast (USBFeatureUnitObject, theFeatureUnits->getObject (indx));
        if (thisFeatureUnit && unitID == thisFeatureUnit->GetUnitID ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisFeatureUnit = NULL;

    return thisFeatureUnit;
}

USBInputTerminalObject * USBAudioControlObject::GetInputTerminalObject (UInt8 unitID) {
    USBInputTerminalObject * 			thisInputTerminal;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisInputTerminal = NULL;
    while (!found && indx < theInputTerminals->getCount ()) {
        thisInputTerminal = OSDynamicCast (USBInputTerminalObject, theInputTerminals->getObject (indx));
        if (thisInputTerminal && unitID == thisInputTerminal->GetUnitID ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisInputTerminal = NULL;

    return thisInputTerminal;
}

UInt16 USBAudioControlObject::GetInputTerminalType (UInt8 unitID) {
    USBInputTerminalObject *			thisInputTerminal;
    UInt16								terminalType;

    terminalType = INPUT_UNDEFINED;
    thisInputTerminal = GetInputTerminalObject (unitID);
    if (thisInputTerminal)
		terminalType = thisInputTerminal->GetTerminalType ();

    return terminalType;
}

UInt8 USBAudioControlObject::GetNumInputTerminals (void) {
	return theInputTerminals->getCount ();
}

UInt8 USBAudioControlObject::GetNumOutputTerminals (void) {
	return theOutputTerminals->getCount ();
}

UInt8 USBAudioControlObject::GetNumSelectorSources (UInt8 unitID) {
    USBSelectorUnitObject *				thisSelectorUnit;
    UInt8								numSelectorSources;

    numSelectorSources = 0;
    thisSelectorUnit = GetSelectorUnitObject (unitID);
    if (thisSelectorUnit)
		numSelectorSources = thisSelectorUnit->GetNumInPins ();

    return numSelectorSources;
}

USBMixerUnitObject * USBAudioControlObject::GetMixerObject (UInt8 unitID) {
    USBMixerUnitObject *		 		thisMixerObject;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisMixerObject = NULL;
    while (!found && indx < theMixerUnits->getCount ()) {
        thisMixerObject = OSDynamicCast (USBMixerUnitObject, theMixerUnits->getObject (indx));
        if (thisMixerObject && unitID == thisMixerObject->GetUnitID ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisMixerObject = NULL;

    return thisMixerObject;
}

USBOutputTerminalObject * USBAudioControlObject::GetOutputTerminalObject (UInt8 unitID) {
    USBOutputTerminalObject * 			thisOutputTerminal;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisOutputTerminal = NULL;
    while (!found && indx < theOutputTerminals->getCount ()) {
        thisOutputTerminal = OSDynamicCast (USBOutputTerminalObject, theOutputTerminals->getObject (indx));
        if (thisOutputTerminal && unitID == thisOutputTerminal->GetUnitID ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisOutputTerminal = NULL;

    return thisOutputTerminal;
}

USBSelectorUnitObject * USBAudioControlObject::GetSelectorUnitObject (UInt8 unitID) {
    USBSelectorUnitObject *		 		thisSelectorObject;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisSelectorObject = NULL;
    while (!found && indx < theSelectorUnits->getCount ()) {
        thisSelectorObject = OSDynamicCast (USBSelectorUnitObject, theSelectorUnits->getObject (indx));
        if (thisSelectorObject && unitID == thisSelectorObject->GetUnitID ()) {
            found = TRUE;
        }
        indx++;
    }

	if (found != TRUE)
		thisSelectorObject = NULL;

    return thisSelectorObject;
}

UInt16 USBAudioControlObject::GetOutputTerminalType (UInt8 unitID) {
    USBOutputTerminalObject *			thisOutputTerminal;
    UInt16								terminalType;

    terminalType = OUTPUT_UNDEFINED;
    thisOutputTerminal = GetOutputTerminalObject (unitID);
    if (thisOutputTerminal)
		terminalType = thisOutputTerminal->GetTerminalType ();

    return terminalType;
}

UInt8 * USBAudioControlObject::GetSelectorSources (UInt8 unitID) {
    USBSelectorUnitObject *				thisSelectorUnit;
    UInt8 *								selectorSources;

    selectorSources = NULL;
    thisSelectorUnit = GetSelectorUnitObject (unitID);
    if (thisSelectorUnit)
		selectorSources = thisSelectorUnit->GetSelectorSources ();

    return selectorSources;
}

Boolean USBAudioControlObject::MasterHasMuteControl (UInt8 featureUnitID) {
	USBFeatureUnitObject *				thisFeatureUnit;
	Boolean								result;

	result = FALSE;
	thisFeatureUnit = GetFeatureUnitObject (featureUnitID);
	if (thisFeatureUnit)
		result = thisFeatureUnit->MasterHasMuteControl ();

	return result;
}

USBInterfaceDescriptorPtr USBAudioControlObject::ParseACInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 const currentInterface) {
	USBInputTerminalObject *	inputTerminal;
	USBOutputTerminalObject *	outputTerminal;
	USBFeatureUnitObject *		featureUnit;
	USBMixerUnitObject *		mixerUnit;
	USBSelectorUnitObject *		selectorUnit;

    FailIf (NULL == theInterfacePtr, Exit);
    FailIf (0 == theInterfacePtr->bLength, Exit);
    FailIf (CS_INTERFACE != theInterfacePtr->bDescriptorType, Exit);

    theInputTerminals = OSArray::withCapacity (1);
    FailIf (NULL == theInputTerminals, Exit);
    theOutputTerminals = OSArray::withCapacity (1);
    FailIf (NULL == theOutputTerminals, Exit);
    theFeatureUnits = OSArray::withCapacity (1);
    FailIf (NULL == theFeatureUnits, Exit);
    theMixerUnits = OSArray::withCapacity (1);
    FailIf (NULL == theMixerUnits, Exit);
    theSelectorUnits = OSArray::withCapacity (1);
    FailIf (NULL == theSelectorUnits, Exit);

    while (theInterfacePtr->bLength && CS_INTERFACE == theInterfacePtr->bDescriptorType) {
        switch (theInterfacePtr->bDescriptorSubtype) {
            case HEADER:
                debugIOLog ("in HEADER in ParseACInterfaceDescriptor\n");
                adcVersion = USBToHostWord (((ACInterfaceHeaderDescriptorPtr)theInterfacePtr)->bcdADC);
                numStreamInterfaces = ((ACInterfaceHeaderDescriptorPtr)theInterfacePtr)->bInCollection;
                firstASInterface = ((ACInterfaceHeaderDescriptorPtr)theInterfacePtr)->baInterfaceNr[1];
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                break;
            case INPUT_TERMINAL:
                debugIOLog ("in INPUT_TERMINAL in ParseACInterfaceDescriptor\n");
				inputTerminal = new USBInputTerminalObject;
				FailIf (NULL == inputTerminal, Exit);
                inputTerminal->SetUnitID (((ACInputTerminalDescriptorPtr)theInterfacePtr)->bTerminalID);
                inputTerminal->SetTerminalType (USBToHostWord (((ACInputTerminalDescriptorPtr)theInterfacePtr)->wTerminalType));
                inputTerminal->SetAssocTerminal (((ACInputTerminalDescriptorPtr)theInterfacePtr)->bAssocTerminal);
                inputTerminal->SetNumChannels (((ACInputTerminalDescriptorPtr)theInterfacePtr)->bNrChannels);
                inputTerminal->SetChannelConfig (USBToHostWord (((ACInputTerminalDescriptorPtr)theInterfacePtr)->wChannelConfig));
				theInputTerminals->setObject (inputTerminal);
				inputTerminal->release ();
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                break;
            case OUTPUT_TERMINAL:
                debugIOLog ("in OUTPUT_TERMINAL in ParseACInterfaceDescriptor\n");
				outputTerminal = new USBOutputTerminalObject;
				FailIf (NULL == outputTerminal, Exit);
                outputTerminal->SetUnitID (((ACOutputTerminalDescriptorPtr)theInterfacePtr)->bTerminalID);
                outputTerminal->SetTerminalType (USBToHostWord (((ACOutputTerminalDescriptorPtr)theInterfacePtr)->wTerminalType));
                outputTerminal->SetAssocTerminal (((ACOutputTerminalDescriptorPtr)theInterfacePtr)->bAssocTerminal);
                outputTerminal->SetSourceID (((ACOutputTerminalDescriptorPtr)theInterfacePtr)->bSourceID);
				theOutputTerminals->setObject (outputTerminal);
				outputTerminal->release ();
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                break;
            case FEATURE_UNIT:
				{
				UInt8						numControls;

                debugIOLog ("in FEATURE_UNIT in ParseACInterfaceDescriptor\n");
				featureUnit = new USBFeatureUnitObject;
				FailIf (NULL == featureUnit, Exit);
                featureUnit->SetUnitID (((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bUnitID);
                featureUnit->SetSourceID (((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bSourceID);
                featureUnit->SetControlSize (((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bControlSize);
                // subtract 7 because that's how many fields are guaranteed to be in the struct
				numControls = (((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bLength - 7) / ((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bControlSize;
				featureUnit->InitControlsArray (&((ACFeatureUnitDescriptorPtr)theInterfacePtr)->bmaControls[0], numControls);
				theFeatureUnits->setObject (featureUnit);
				featureUnit->release ();
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                break;
				}
            case MIXER_UNIT:
				{
				UInt32						controlSize;
				UInt16 *					channelConfig;
				UInt8						nrChannels;

                debugIOLog ("in MIXER_UNIT in ParseACInterfaceDescriptor\n");
				mixerUnit = new USBMixerUnitObject;
				FailIf (NULL == mixerUnit, Exit);
				debug2IOLog ("descriptor length = %d\n", theInterfacePtr->bLength);
				mixerUnit->SetUnitID (((ACMixerUnitDescriptorPtr)theInterfacePtr)->bUnitID);
				debug2IOLog ("unit ID = %d\n", ((ACMixerUnitDescriptorPtr)theInterfacePtr)->bUnitID);
				debug2IOLog ("numInPins = %d\n", ((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins);
				mixerUnit->InitSourceIDs (&((ACMixerUnitDescriptorPtr)theInterfacePtr)->baSourceID[0], ((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins);
				nrChannels = ((ACMixerUnitDescriptorPtr)theInterfacePtr)->baSourceID[((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins];
				debug2IOLog ("nrChannels = %d\n", nrChannels);
				mixerUnit->SetNumChannels (nrChannels);
				channelConfig = (UInt16 *)&((ACMixerUnitDescriptorPtr)theInterfacePtr)->baSourceID[((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins + 1];
				*channelConfig = USBToHostWord (*channelConfig);
				debug2IOLog ("channelConfig = %d\n", *channelConfig);
				mixerUnit->SetChannelConfig (*channelConfig);
				controlSize = ((ACMixerUnitDescriptorPtr)theInterfacePtr)->bLength - 10 - ((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins;
				debug2IOLog ("controlSize = %d\n", controlSize);
				mixerUnit->InitControlsArray (&((ACMixerUnitDescriptorPtr)theInterfacePtr)->baSourceID[((ACMixerUnitDescriptorPtr)theInterfacePtr)->bNrInPins + 3], controlSize);
				theMixerUnits->setObject (mixerUnit);
				mixerUnit->release ();
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
				break;
				}
            case SELECTOR_UNIT:
                debugIOLog ("in SELECTOR_UNIT in ParseACInterfaceDescriptor\n");
				selectorUnit = new USBSelectorUnitObject;
				FailIf (NULL == selectorUnit, Exit);
				selectorUnit->SetUnitID (((ACSelectorUnitDescriptorPtr)theInterfacePtr)->bUnitID);
				selectorUnit->InitSourceIDs (&((ACSelectorUnitDescriptorPtr)theInterfacePtr)->baSourceID[0], ((ACSelectorUnitDescriptorPtr)theInterfacePtr)->bNrInPins);
				debug2IOLog ("numInPins on selector = %d\n", ((ACSelectorUnitDescriptorPtr)theInterfacePtr)->bNrInPins);
				theSelectorUnits->setObject (selectorUnit);
				selectorUnit->release ();
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
				break;
            case PROCESSING_UNIT:
                debugIOLog ("in PROCESSING_UNIT in ParseACInterfaceDescriptor\n");
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
				break;
            case EXTENSION_UNIT:
                debugIOLog ("in EXTENSION_UNIT in ParseACInterfaceDescriptor\n");
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
				break;
            default:
                debugIOLog ("in default in ParseACInterfaceDescriptor\n");
                theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
        }
    }

Exit:
    return theInterfacePtr;
}

/* ------------------------------------------------------
    USBAudioStreamObject
------------------------------------------------------ */
/*
	Public methods
*/
OSDefineMetaClassAndStructors (USBAudioStreamObject, OSObject);

USBAudioStreamObject * USBAudioStreamObject::create (void) {
    USBAudioStreamObject *			streamObject;

    streamObject = new USBAudioStreamObject;

    FailIf (NULL == streamObject, Exit);
    if (FALSE == streamObject->init ()) {
        streamObject->release ();
        streamObject = 0;
    }

Exit:
    return streamObject;
}

void USBAudioStreamObject::free (void) {
    IOFree (sampleFreqs, numSampleFreqs * sizeof (UInt32));
	if (NULL != theEndpointObjects) {
		theEndpointObjects->release ();
		theEndpointObjects = NULL;
	}
    OSObject::free ();
}

USBEndpointObject * USBAudioStreamObject::GetIndexedEndpointObject (UInt8 index) {
    USBEndpointObject *		 			thisEndpoint;

	if (theEndpointObjects)
		thisEndpoint = OSDynamicCast (USBEndpointObject, theEndpointObjects->getObject (index));
	else
		thisEndpoint = NULL;

	return thisEndpoint;
}

UInt8 USBAudioStreamObject::GetIsocAssociatedEndpointAddress (UInt8 address) {
    USBEndpointObject *		 			thisEndpoint;
    UInt8								assocEndpointAddress;

	assocEndpointAddress = 0;
	thisEndpoint = GetEndpointByAddress (address);
	if (thisEndpoint) {
		assocEndpointAddress = thisEndpoint->GetSynchAddress ();
	}

    return assocEndpointAddress;
}

UInt8 USBAudioStreamObject::GetIsocAssociatedEndpointRefreshInt (UInt8 address) {
    USBEndpointObject *		 			thisEndpoint;
    UInt8								assocEndpointRefresh;

	assocEndpointRefresh = 0;
	thisEndpoint = GetEndpointByAddress (address);
	if (thisEndpoint) {
		assocEndpointRefresh = thisEndpoint->GetRefreshInt ();
	}

    return assocEndpointRefresh;
}

UInt8 USBAudioStreamObject::GetIsocEndpointAddress (UInt8 direction) {
    USBEndpointObject *		 					thisEndpointObject;
	UInt8										address;
    UInt8										indx;

    indx = 0;
	address = 0;
	debug2IOLog ("GetIsocEndpointAddress, looking for direction %d\n", direction);
	if (theEndpointObjects) {
		while (!address && indx < theEndpointObjects->getCount ()) {
			thisEndpointObject = OSDynamicCast (USBEndpointObject, theEndpointObjects->getObject (indx));
			debug2IOLog ("GetIsocEndpointAddress, this endpoint's direction %d\n", thisEndpointObject->GetDirection ());
			if (thisEndpointObject && direction == thisEndpointObject->GetDirection ()) {
				address = thisEndpointObject->GetAddress ();
				debug2IOLog ("GetIsocEndpointAddress, found endpoint address %d\n", address);
			}
		indx++;
		}
	}

	return address;
}

UInt8 USBAudioStreamObject::GetIsocEndpointDirection (UInt8 index) {
    USBEndpointObject *		 					thisEndpointObject;
	UInt8										direction;

	direction = 0xFF;
	thisEndpointObject = NULL;
	if (theEndpointObjects) {
		thisEndpointObject = OSDynamicCast (USBEndpointObject, theEndpointObjects->getObject (index));
	}

	if (NULL != thisEndpointObject)
        direction = thisEndpointObject->GetDirection ();

	return direction;
}

UInt8 USBAudioStreamObject::GetIsocEndpointSyncType (UInt8 address) {
    USBEndpointObject *		 					thisEndpointObject;
	UInt8										syncType;

	syncType = 0;
	thisEndpointObject = GetEndpointByAddress (address);

	if (NULL != thisEndpointObject)
        syncType = thisEndpointObject->GetSyncType ();

	return syncType;
}

USBInterfaceDescriptorPtr USBAudioStreamObject::ParseASInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 const currentInterface) {
    UInt32								indx;
    Boolean								done;
    USBEndpointObject *							theEndpoint;

    FailIf (NULL == theInterfacePtr, Exit);
    FailIf (0 == theInterfacePtr->bLength, Exit);
    FailIf (CS_INTERFACE != theInterfacePtr->bDescriptorType, Exit);

    theEndpointObjects = OSArray::withCapacity (1);
    FailIf (NULL == theEndpointObjects, Exit);

    done = FALSE;
    while (theInterfacePtr->bLength && !done) {
        if (CS_INTERFACE == theInterfacePtr->bDescriptorType) {
            switch (theInterfacePtr->bDescriptorSubtype) {
                case AS_GENERAL:
                    debugIOLog ("in AS_GENERAL in ParseASInterfaceDescriptor\n");
                    terminalLink = ((ASInterfaceDescriptorPtr)theInterfacePtr)->bTerminalLink;
                    delay = ((ASInterfaceDescriptorPtr)theInterfacePtr)->bDelay;
                    formatTag = (((ASInterfaceDescriptorPtr)theInterfacePtr)->wFormatTag[1] << 8) | ((ASInterfaceDescriptorPtr)theInterfacePtr)->wFormatTag[0];
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                    break;
                case FORMAT_TYPE:
                    debugIOLog ("in FORMAT_TYPE in ParseASInterfaceDescriptor\n");
					switch (((ASFormatTypeIDescriptorPtr)theInterfacePtr)->bFormatType) {
						case FORMAT_TYPE_I:
						case FORMAT_TYPE_III:
							debugIOLog ("in FORMAT_TYPE_I/FORMAT_TYPE_III in FORMAT_TYPE\n");
							numChannels = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->bNrChannels;
							subframeSize = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->bSubframeSize;
							bitResolution = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->bBitResolution;
							numSampleFreqs = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->bSamFreqType;
							if (0 != numSampleFreqs) {
								debugIOLog ("device has a descrete number of sample rates\n");
								sampleFreqs = (UInt32 *)IOMalloc (numSampleFreqs * sizeof (UInt32));
								for (indx = 0; indx < numSampleFreqs; indx++) {
									((UInt8 *)sampleFreqs)[indx * 4] = 0;
									((UInt8 *)sampleFreqs)[indx * 4 + 1] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 2];
									((UInt8 *)sampleFreqs)[indx * 4 + 2] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 1];
									((UInt8 *)sampleFreqs)[indx * 4 + 3] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3];
								}
							} else {
								debugIOLog ("device has a variable number of sample rates\n");
								sampleFreqs = (UInt32 *)IOMalloc (2 * sizeof (UInt32));
								for (indx = 0; indx < 2; indx++) {
									((UInt8 *)sampleFreqs)[indx * 4] = 0;
									((UInt8 *)sampleFreqs)[indx * 4 + 1] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 2];
									((UInt8 *)sampleFreqs)[indx * 4 + 2] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 1];
									((UInt8 *)sampleFreqs)[indx * 4 + 3] = ((ASFormatTypeIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3];
								}
							}
							break;
						case FORMAT_TYPE_II:
							debugIOLog ("in FORMAT_TYPE_II in FORMAT_TYPE\n");
							maxBitRate = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->wMaxBitRate;
							samplesPerFrame = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->wSamplesPerFrame;
							numSampleFreqs = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->bSamFreqType;
							if (0 != numSampleFreqs) {
								debugIOLog ("device has a descrete number of sample rates\n");
								sampleFreqs = (UInt32 *)IOMalloc (numSampleFreqs * sizeof (UInt32));
								for (indx = 0; indx < numSampleFreqs; indx++) {
									((UInt8 *)sampleFreqs)[indx * 4] = 0;
									((UInt8 *)sampleFreqs)[indx * 4 + 1] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 2];
									((UInt8 *)sampleFreqs)[indx * 4 + 2] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 1];
									((UInt8 *)sampleFreqs)[indx * 4 + 3] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3];
								}
							} else {
								debugIOLog ("device has a variable number of sample rates\n");
								sampleFreqs = (UInt32 *)IOMalloc (2 * sizeof (UInt32));
								for (indx = 0; indx < 2; indx++) {
									((UInt8 *)sampleFreqs)[indx * 4] = 0;
									((UInt8 *)sampleFreqs)[indx * 4 + 1] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 2];
									((UInt8 *)sampleFreqs)[indx * 4 + 2] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3 + 1];
									((UInt8 *)sampleFreqs)[indx * 4 + 3] = ((ASFormatTypeIIDescriptorPtr)theInterfacePtr)->sampleFreq[indx * 3];
								}
							}
							break;
						default:
							debugIOLog ("!!!!unknown format type in FORMAT_TYPE!!!!\n");
					}
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                    break;
                default:
                    debugIOLog ("in default in ParseASInterfaceDescriptor\n");
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
            }
        } else {
            switch (theInterfacePtr->bDescriptorType) {
                case INTERFACE:
                    // need to make a new interface object for this new interface or new alternate interface
                    debugIOLog ("in INTERFACE in ParseASInterfaceDescriptor\n");
                    done = TRUE;
                    break;
                case ENDPOINT:
                    debugIOLog ("in ENDPOINT in ParseASInterfaceDescriptor\n");
                    theEndpoint = USBEndpointObject::create ();
					theEndpoint->SetAddress (((USBEndpointDescriptorPtr)theInterfacePtr)->bEndpointAddress);
                    theEndpoint->SetAttributes (((USBEndpointDescriptorPtr)theInterfacePtr)->bmAttributes);
                    theEndpoint->SetMaxPacketSize (USBToHostWord (((USBEndpointDescriptorPtr)theInterfacePtr)->wMaxPacketSize));
					theEndpoint->SetRefreshInt (((USBEndpointDescriptorPtr)theInterfacePtr)->bRefresh);
					theEndpoint->SetSynchAddress (((USBEndpointDescriptorPtr)theInterfacePtr)->bSynchAddress);
                    theEndpointObjects->setObject (theEndpoint);
					theEndpoint->release ();
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                    break;
                case CS_ENDPOINT:
                    debugIOLog ("in CS_ENDPOINT in ParseASInterfaceDescriptor\n");
                    if (EP_GENERAL == ((ASEndpointDescriptorPtr)theInterfacePtr)->bDescriptorSubtype) {
                        debugIOLog ("in EP_GENERAL in CS_ENDPOINT\n");
                        theIsocEndpointObject = new USBCSASIsocADEndpointObject (((ASEndpointDescriptorPtr)theInterfacePtr)->bmAttributes & (1 << sampleFreqControlBit),
                                                                            ((ASEndpointDescriptorPtr)theInterfacePtr)->bmAttributes & (1 << pitchControlBit),
                                                                            ((ASEndpointDescriptorPtr)theInterfacePtr)->bmAttributes & (1 << maxPacketsOnlyBit),
                                                                            ((ASEndpointDescriptorPtr)theInterfacePtr)->bLockDelayUnits,
                                                                            (((ASEndpointDescriptorPtr)theInterfacePtr)->wLockDelay[1] << 8) | ((ASEndpointDescriptorPtr)theInterfacePtr)->wLockDelay[0]);
                    }
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
                    break;
                default:
                    debugIOLog ("in default in else in ParseASInterfaceDescriptor\n");
                    theInterfacePtr = (USBInterfaceDescriptorPtr)((UInt8 *)theInterfacePtr + theInterfacePtr->bLength);
            }
        }
    }

Exit:
    return theInterfacePtr;
}

/*
 	 Private methods
*/

USBEndpointObject * USBAudioStreamObject::GetEndpointByAddress (UInt8 address) {
    USBEndpointObject *		 			thisEndpoint;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisEndpoint = NULL;
	if (theEndpointObjects) {
		while (!found && indx < theEndpointObjects->getCount ()) {
			thisEndpoint = GetIndexedEndpointObject (indx);
			if (thisEndpoint && (thisEndpoint->GetAddress () == address)) {
				found = TRUE;
			}
			indx++;
		}
	}

	if (found != TRUE)
		thisEndpoint = NULL;

    return thisEndpoint;
}

USBEndpointObject * USBAudioStreamObject::GetEndpointObjectByAddress (UInt8 address) {
    USBEndpointObject *		 			thisEndpointObject;
    UInt8								indx;
    Boolean								found;

    indx = 0;
    found = FALSE;
	thisEndpointObject = NULL;
	if (theEndpointObjects) {
		while (!found && indx < theEndpointObjects->getCount ()) {
			thisEndpointObject = OSDynamicCast (USBEndpointObject, theEndpointObjects->getObject (indx));
			if (thisEndpointObject && address == thisEndpointObject->GetAddress ()) {
				found = TRUE;
			}
			indx++;
		}
	}

    if (found != TRUE)
		thisEndpointObject = NULL;

    return thisEndpointObject;
}

//UInt8 GetEndpointAttributes (void) {if (theEndpointObject) return theEndpointObject->GetAttributes (); else return 0;}
//UInt8 GetEndpointDirection (void) {if (theEndpointObject) return theEndpointObject->GetDirection (); else return 0;}

/* ------------------------------------------------------
    USBEndpointObject
------------------------------------------------------ */
OSDefineMetaClassAndStructors (USBEndpointObject, OSObject);

USBEndpointObject * USBEndpointObject::create (void) {
    USBEndpointObject *			endpointObject;

    endpointObject = new USBEndpointObject;

    FailIf (NULL == endpointObject, Exit);
    if (FALSE == endpointObject->init ()) {
        endpointObject->release ();
        endpointObject = 0;
    }

Exit:
    return endpointObject;
}

void USBEndpointObject::free (void) {
    OSObject::free ();
}

/* ------------------------------------------------------
    USBASIsocEndpointObject
------------------------------------------------------ */
USBCSASIsocADEndpointObject::USBCSASIsocADEndpointObject (Boolean theSampleFreqControl, Boolean thePitchControl, Boolean theMaxPacketsOnly, UInt8 theLockDelayUnits, UInt16 theLockDelay)
    :	sampleFreqControl				(theSampleFreqControl),
        pitchControl					(thePitchControl),
        maxPacketsOnly					(theMaxPacketsOnly),
        lockDelayUnits					(theLockDelayUnits),
        lockDelay						(theLockDelay)
{
}

/* ------------------------------------------------------
    USBInputTerminalObject
------------------------------------------------------ */
//OSDefineMetaClassAndStructors (USBInputTerminalObject, OSObject);

void USBInputTerminalObject::free (void) {
    USBACDescriptorObject::free ();
}

/* ------------------------------------------------------
    USBOutputTerminalObject
------------------------------------------------------ */
//OSDefineMetaClassAndStructors (USBOutputTerminalObject, OSObject);

void USBOutputTerminalObject::free (void) {
    USBACDescriptorObject::free ();
}

/* ------------------------------------------------------
    USBMixerUnitObject
------------------------------------------------------ */
void USBMixerUnitObject::free (void) {
    USBACDescriptorObject::free ();
}

void USBMixerUnitObject::InitControlsArray (UInt8 * bmCntrls, UInt8 bmControlSize) {
	UInt8					i;

	controlSize = bmControlSize;
	bmControls = ((UInt8 *)IOMalloc (bmControlSize));
	FailIf (NULL == bmControls, Exit);
	memcpy (bmControls, bmCntrls, bmControlSize);
	for (i = 0; i < bmControlSize; i++) {
		debug3IOLog ("bmCntrls[%d] = 0x%X\n", i, bmCntrls[i]);
		debug3IOLog ("bmControls[%d] = 0x%X\n", i, bmControls[i]);
	}
Exit:
	return;
}

void USBMixerUnitObject::InitSourceIDs (UInt8 * baSrcIDs, UInt8 nrInPins) {
	numInPins = nrInPins;
	baSourceIDs = (UInt8 *)IOMalloc (nrInPins);
	FailIf (NULL == baSourceIDs, Exit);
	memcpy (baSourceIDs, baSrcIDs, nrInPins);

#if DEBUGLOG
	{
		UInt8			i;
		for (i = 0; i < nrInPins; i++) {
			debug3IOLog ("baSourceIDs[%d] = %d\n", i, baSourceIDs[i]);
		}
	}
#endif

Exit:
	return;
}

/* ------------------------------------------------------
    USBSelectorUnitObject
------------------------------------------------------ */
void USBSelectorUnitObject::free (void) {
    USBACDescriptorObject::free ();
}

void USBSelectorUnitObject::InitSourceIDs (UInt8 * baSrcIDs, UInt8 nrInPins) {
	numInPins = nrInPins;
	baSourceIDs = (UInt8 *)IOMalloc (nrInPins);
	FailIf (NULL == baSourceIDs, Exit);
	memcpy (baSourceIDs, baSrcIDs, nrInPins);

Exit:
	return;
}

/* ------------------------------------------------------
    USBFeatureUnitObject
------------------------------------------------------ */
//OSDefineMetaClassAndStructors (USBFeatureUnitObject, OSObject);

void USBFeatureUnitObject::free (void) {
    IOFree (bmaControls, numControls * controlSize);
    USBACDescriptorObject::free ();
}

Boolean USBFeatureUnitObject::MasterHasMuteControl (void) {
	return ChannelHasMuteControl (0);		// Master channel is always bmaControls[0]
}

// Channel #1 is left channel, #2 is right channel
Boolean USBFeatureUnitObject::ChannelHasMuteControl (UInt8 channelNum) {
	Boolean						result;

	result = FALSE;
	if (numControls >= channelNum + 1) {
		if (1 == controlSize) {
			result = ((UInt8 *)bmaControls)[channelNum] & (1 << kMuteBit);
		} else {
			result = ((UInt16 *)bmaControls)[channelNum] & (1 << kMuteBit);
		}
	}

	return result;
}

Boolean USBFeatureUnitObject::ChannelHasVolumeControl (UInt8 channelNum) {
	Boolean						result;

	result = FALSE;
	if (numControls >= channelNum + 1) {
		if (1 == controlSize) {
			result = ((UInt8 *)bmaControls)[channelNum] & (1 << kVolumeBit);
		} else {
			result = ((UInt16 *)bmaControls)[channelNum] & (1 << kVolumeBit);
		}
	}

	return result;
}

void USBFeatureUnitObject::InitControlsArray (UInt8 * bmaControlsArrary, UInt8 numCntrls) {
	UInt32						bmaControlIndex;

	numControls = numCntrls;
	bmaControls = (UInt8 *)IOMalloc (numControls * controlSize);
	FailIf (NULL == bmaControls, Exit);
	memcpy (bmaControls, bmaControlsArrary, numControls * controlSize);
	if (2 == controlSize) {
		for (bmaControlIndex = 0; bmaControlIndex < numControls; bmaControlIndex++) {
			((UInt16 *)bmaControls)[bmaControlIndex] = USBToHostWord (((UInt16 *)bmaControls)[bmaControlIndex]);
		}
	}

Exit:
	return;
}

/* ------------------------------------------------------
    USBACDescriptorObject
------------------------------------------------------ */
OSDefineMetaClassAndStructors (USBACDescriptorObject, OSObject);

void USBACDescriptorObject::free (void) {
    OSObject::free ();
}


Generated by GNU enscript 1.6.4.