#include <libkern/c++/OSArray.h>
#include <IOKit/usb/IOUSBInterface.h>

#include "AppleUSBAudioCommon.h"

#ifndef __USBAudioObject__
#define __USBAudioObject__

enum {
	kMuteBit					= 0,
	kVolumeBit					= 1,
	kBassBit					= 2,
	kMidBit						= 3,
	kTrebleBit					= 4,
	kEQBit						= 5,
	kAGBit						= 6,
	kDelayBit					= 7,
	kBassBoostBit				= 8,
	kLoudnessBit				= 9
};

#define CLASS_PROPERTY_NAME					"class"
#define SUBCLASS_PROPERTY_NAME				"subClass"
#define PROTOCOL_PROPERTY_NAME				"protocol"
#define VENDOR_PROPERTY_NAME				"vendor"
#define PRODUCT_PROPERTY_NAME				"product"
#define VERSION_PROPERTY_NAME				"version"


enum {
    sampleFreqControlBit					= 0,
    pitchControlBit							= 1,
    maxPacketsOnlyBit						= 7
};

enum {
	kAsynchSyncType							= 0x01,
	kAdaptiveSyncType						= 0x02,
	kSynchronousSyncType					= 0x03
};

enum {
    DEVICE									= 0x01,
    CONFIGURATION							= 0x02,
    STRING									= 0x03,
    INTERFACE								= 0x04,
    ENDPOINT								= 0x05
};

enum {
	GET_STATUS								= 0x00,
	CLEAR_FREATURE							= 0x01,
	SET_FEATURE								= 0x03,
	SET_ADDRESS								= 0x05,
	GET_DESCRIPTOR							= 0x06,
	SET_DESCRIPTOR							= 0x07,
	GET_CONFIGURATION						= 0x08,
	SET_CONFIGURATION						= 0x09,
	GET_INTERFACE							= 0x0A,
	SET_INTERFACE							= 0x0B,
	SYNCH_FRAME								= 0x0C
};

enum {
    // For descriptor type
    CS_UNDEFINED							= 0x20,
    CS_DEVICE								= 0x21,
    CS_CONFIGURATION						= 0x22,
    CS_STRING								= 0x23,
    CS_INTERFACE							= 0x24,
    CS_ENDPOINT								= 0x25
};

enum {
	// Audio Interface Class Code
    AUDIO									= 0x01
};

enum {
	// Audio Interface Subclass Codes
	SUBCLASS_UNDEFINED						= 0x00,
    AUDIOCONTROL							= 0x01,
    AUDIOSTREAMING							= 0x02,
	MIDISTREAMING							= 0x03,
	VENDOR_SPECIFIC							= 0xff
};

enum {
    // Audio Control (AC) interface descriptor subtypes
    AC_DESCRIPTOR_UNDEFINED					= 0x00,
    HEADER									= 0x01,
    INPUT_TERMINAL							= 0x02,
    OUTPUT_TERMINAL							= 0x03,
    MIXER_UNIT								= 0x04,
    SELECTOR_UNIT							= 0x05,
    FEATURE_UNIT							= 0x06,
    PROCESSING_UNIT							= 0x07,
    EXTENSION_UNIT							= 0x08
};

enum {
    USB_STREAMING							= 0x0101
};

enum {
    // Audio Stream (AS) interface descriptor subtypes
    AS_DESCRIPTOR_UNDEFINED					= 0x00,
    AS_GENERAL								= 0x01,
    FORMAT_TYPE								= 0x02,
    FORMAT_SPECIFIC							= 0x03
};

enum {
    FORMAT_TYPE_UNDEFINED					= 0x00,
    FORMAT_TYPE_I							= 0x01,
    FORMAT_TYPE_II							= 0x02,
    FORMAT_TYPE_III							= 0x03
};

enum {
    // Audio data format type I codes
    TYPE_I_UNDEFINED						= 0x0000,
    PCM										= 0x0001,
    PCM8									= 0x0002,
    IEEE_FLOAT								= 0x0003,
    ALAW									= 0x0004,
    MULAW									= 0x0005
};

enum {
	// Audio data format type II codes
	TYPE_II_UNDEFINED						= 0x1000,
	MPEG									= 0x1001,
	AC3										= 0x1002
};

enum {
	// Audio data format type III codes
	TYPE_III_UNDEFINED						= 0x2000,
	IEC1937_AC3								= 0x2001,
	IEC1937_MPEG1_Layer1					= 0x2002,
	IEC1937_MPEG1_Layer2or3					= 0x2003,
	IEC1937_MPEG2_NOEXT						= 0x2003,
	IEC1937_MPEG2_EXT						= 0x2004,
	IEC1937_MPEG2_Layer1_LS					= 0x2005,
	IEC1937_MPEG2_Layer2or3_LS				= 0x2006
};

enum {
	// MPEG control selectors
	MPEG_CONTROL_UNDEFINED					= 0x00,
	MP_DUAL_CHANNEL_CONTROL					= 0x01,
	MP_SECOND_STEREO_CONTROL				= 0x02,
	MP_MULTILINGUAL_CONTROL					= 0x03,
	MP_DYN_RANGE_CONTROL					= 0x04,
	MP_SCALING_CONTROL						= 0x05,
	MP_HILO_SCALING_CONTROL					= 0x06
};

enum {
	// AC-3 control selectors
	AC_CONTROL_UNDEFINED					= 0x00,
	AC_MODE_CONTROL							= 0x01,
	AC_DYN_RANGE_CONTROL					= 0x02,
	AC_SCALING_CONTROL						= 0x03,
	AC_HILO_SCALING_CONTROL					= 0x04
};

enum {
    // Audio Class-specific endpoint descriptor subtypes
    DESCRIPTOR_UNDEFINED					= 0x00,
    EP_GENERAL								= 0x01
};

enum {
    REQUEST_CODE_UNDEFINED					= 0x00,
    SET_CUR									= 0x01,
    GET_CUR									= 0x81,
    SET_MIN									= 0x02,
    GET_MIN									= 0x82,
    SET_MAX									= 0x03,
    GET_MAX									= 0x83,
    SET_RES									= 0x04,
    GET_RES									= 0x84,
    SET_MEM									= 0x05,
    GET_MEM									= 0x85,
    GET_STAT								= 0xff
};

enum {
    FU_CONTROL_UNDEFINED					= 0x00,
    MUTE_CONTROL							= 0x01,
    VOLUME_CONTROL							= 0x02,
    BASS_CONTROL							= 0x03,
    MID_CONTROL								= 0x04,
    TREBLE_CONTROL							= 0x05,
    GRAPHIC_EQUALIZER_CONTROL				= 0x06,
    AUTOMATIC_GAIN_CONTROL					= 0x07,
    DELAY_CONTROL							= 0x08,
    BASS_BOOST_CONTROL						= 0x09,
    LOUDNESS_CONTROL						= 0x0a
};

enum {
	EP_CONTROL_UNDEFINED					= 0x00,
	SAMPLING_FREQ_CONTROL					= 0x01,
	PITCH_CONTROL							= 0x02
};

#if 0
// Input terminal types
enum {
    INPUT_UNDEFINED							= 0x0200,
    INPUT_MICROPHONE						= 0x0201,
    INPUT_DESKTOP_MICROPHONE				= 0x0202,
    INPUT_PERSONAL_MICROPHONE				= 0x0203,
    INPUT_OMNIDIRECTIONAL_MICROPHONE		= 0x0204,
    INPUT_MICROPHONE_ARRAY					= 0x0205,
    INPUT_PROCESSING_MICROPHONE_ARRAY		= 0x0206
};

// Output terminal types
enum {
    OUTPUT_UNDEFINED						= 0x0300,
    OUTPUT_SPEAKER							= 0x0301,
    OUTPUT_HEADPHONES						= 0x0302,
    OUTPUT_HEAD_MOUNTED_DISPLAY_AUDIO		= 0x0303,
    OUTPUT_DESKTOP_SPEAKER					= 0x0304,
    OUTPUT_ROOM_SPEAKER						= 0x0305,
    OUTPUT_COMMUNICATION_SPEAKER			= 0x0306,
    OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER	= 0x0307
};

// Bi-directional terminal types
enum {
    BIDIRECTIONAL_UNDEFINED					= 0x0400,
    BIDIRECTIONAL_HANDSET					= 0x0401,
    BIDIRECTIONAL_HEADSET					= 0x0402,
    BIDIRECTIONAL_SPEAKERPHONE_NO_ECHO_REDX	= 0x0403,
    BIDIRECTIONAL_ECHO_SUPPRESSING_SPEAKERPHONE	= 0x0404,
    BIDIRECTIONAL_ECHO_CANCELING_SPEAKERPHONE	= 0x0405
};

// Telephony terminal types
enum {
    TELEPHONY_UNDEFINED						= 0x0500,
    TELEPHONY_PHONE_LINE					= 0x0501,
    TELEPHONY_TELEPHONE						= 0x0502,
    TELEPHONY_DOWN_LINE_PHONE				= 0x0503
};

// External terminal types
enum {
    EXTERNAL_UNDEFINED						= 0x0600,
    EXTERNAL_ANALOG_CONNECTOR				= 0x0601,
    EXTERNAL_DIGITAL_AUDIO_INTERFACE		= 0x0602,
    EXTERNAL_LINE_CONNECTOR					= 0x0603,
    EXTERNAL_LEGACY_AUDIO_CONNECTOR			= 0x0604,
    EXTERNAL_SPDIF_INTERFACE				= 0x0605,
    EXTERNAL_1394_DA_STREAM					= 0x0606,
    EXTERNAL_1394_DV_STREAM_SOUNDTRACK		= 0x0607
};

// Embedded terminal types
enum {
    EMBEDDED_UNDEFINED						= 0x0700,
    EMBEDDED_LEVEL_CALIBRATION_NOISE_SOURCE	= 0x0701,
    EMBEDDED_EQUALIZATION_NOISE				= 0x0702,
    EMBEDDED_CD_PLAYER						= 0x0703,
    EMBEDDED_DAT							= 0x0704,
    EMBEDDED_DCC							= 0x0705,
    EMBEDDED_MINIDISK						= 0x0706,
    EMBEDDED_ANALOG_TAPE					= 0x0707,
    EMBEDDED_PHONOGRAPH						= 0x0708,
    EMBEDDED_VCR_AUDIO						= 0x0709,
    EMBEDDED_VIDEO_DISC_AUDIO				= 0x070A,
    EMBEDDED_DVD_AUDIO						= 0x070B,
    EMBEDDED_TV_TUNER_AUDIO					= 0x070C,
    EMBEDDED_SATELLITE_RECEIVER_AUDIO		= 0x070D,
    EMBEDDED_CABLE_TUNER_AUDIO				= 0x070E,
    EMBEDDED_DSS_AUDIO						= 0x070F,
    EMBEDDED_RADIO_RECEIVER					= 0x0710,
    EMBEDDED_RADIO_TRANSMITTER				= 0x0711,
    EMBEDDED_MULTITRACK_RECORDER			= 0x0712,
    EMBEDDED_SYNTHESIZER					= 0x0713
};
#endif

#define USB_AUDIO_IS_FUNCTION(subtype)	((subtype >= MIXER_UNIT) && (subtype <= EXTENSION_UNIT))
#define USB_AUDIO_IS_TERMINAL(subtype)	((subtype == INPUT_TERMINAL) || (subtype == OUTPUT_TERMINAL))

typedef struct USBDeviceDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt16									bcdUSB;
    UInt8									bDeviceClass;
    UInt8									bDeviceSubClass;
    UInt8									bDeviceProtocol;
    UInt8									bMaxPacketSize0;
    UInt16									idVendor;
    UInt16									idProduct;
    UInt16									bcdDevice;
    UInt8									iManufacturer;
    UInt8									iProduct;
    UInt8									iSerialNumber;
    UInt8									bNumConfigurations;
} USBDeviceDescriptor, *USBDeviceDescriptorPtr;

typedef struct USBConfigurationDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt16									wTotalLength;
    UInt8									bNumInterfaces;
    UInt8									bConfigurationValue;
    UInt8									iConfiguration;
    UInt8									bmAttributes;
    UInt8									MaxPower;	// expressed in 2mA units
} USBConfigurationDescriptor, *USBConfigurationDescriptorPtr;

typedef struct USBInterfaceDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bAlternateSetting;
    UInt8									bNumEndpoints;
    UInt8									bInterfaceClass;
    UInt8									bInterfaceSubClass;
    UInt8									bInterfaceProtocol;
    UInt8									iInterface;
} USBInterfaceDescriptor, *USBInterfaceDescriptorPtr;

typedef struct USBEndpointDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bEndpointAddress;
    UInt8									bmAttributes;
    UInt16									wMaxPacketSize;
    UInt8									bInterval;
    UInt8									bRefresh;
    UInt8									bSynchAddress;
} USBEndpointDescriptor, *USBEndpointDescriptorPtr;

typedef struct ACFunctionDescriptorHeader {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bFunctionID;
} ACFunctionDescriptorHeader;

typedef struct ACInterfaceHeaderDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bcdADC;
    UInt16									wTotalLength;
    UInt8									bInCollection;
    UInt8									baInterfaceNr[1];			// There are bInCollection of these
} ACInterfaceHeaderDescriptor, *ACInterfaceHeaderDescriptorPtr;

typedef struct ACInterfaceDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bInterfaceNumber;
    UInt8									bAlternateSetting;
    UInt8									bNumEndpoints;
    UInt8									bInterfaceClass;
    UInt8									bInterfaceSubClass;
    UInt8									bInterfaceProtocol;
    UInt8									iInterface;
} ACInterfaceDescriptor, *ACInterfaceDescriptorPtr;

typedef struct ACInputTerminalDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bTerminalID;
    UInt16									wTerminalType;
    UInt8									bAssocTerminal;
    UInt8									bNrChannels;
    UInt16									wChannelConfig;
    UInt8									iChannelNames;
    UInt8									iTerminal;
} ACInputTerminalDescriptor, *ACInputTerminalDescriptorPtr;

typedef struct ACOutputTerminalDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bTerminalID;
    UInt16									wTerminalType;
    UInt8									bAssocTerminal;
    UInt8									bSourceID;
    UInt8									iTerminal;
} ACOutputTerminalDescriptor, *ACOutputTerminalDescriptorPtr;

typedef struct ACFeatureUnitDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bUnitID;
    UInt8									bSourceID;
    UInt8									bControlSize;
    UInt8									bmaControls[2];
    // bmaControls size is actually bControlSize, so it might be one or two bytes
} ACFeatureUnitDescriptor, *ACFeatureUnitDescriptorPtr;

typedef struct ACMixerUnitDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bUnitID;
	UInt8									bNrInPins;
	UInt8									baSourceID[1];	// there are bNrInPins of these
	// Can't have a static structure to define these locations:
	// UInt8								bNrChannels
	// UInt16								wChannelConfig
	// UInt8								iChannelNames
	// UInt8								bmControls[]	// you don't know the size of this, calculate it using bLength and bNrInPins
	// UInt8								iMixer
} ACMixerUnitDescriptor, *ACMixerUnitDescriptorPtr;

typedef struct ACSelectorUnitDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bUnitID;
	UInt8									bNrInPins;
	UInt8									baSourceID[1];	// there are bNrInPins of these
	// Can't have a static structure to define this location:
	// UInt8								iSelector
} ACSelectorUnitDescriptor, *ACSelectorUnitDescriptorPtr;

typedef struct ACProcessingUnitDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bUnitID;
	UInt16									wProcessType;
	UInt8									bNrInPins;
	UInt8									baSourceID[1];	// there are bNrInPins of these
	// Can't have a static structure to define these locations:
	// UInt8								bNrChannels
	// UInt16								wChannelConfig
	// UInt8								iChannelNames
	// UInt8								bControlSize
	// UInt8								bmControls[]
	// UInt8								iProcessing
	// UInt8								processSpecific[]	// no set size, calculate
} ACProcessingUnitDescriptor, *ACProcessingUnitDescriptorPtr;

/*	From USB Device Class Definition for Audio Data Formats 2.4.1:
	The Type III Format Type is identical to the Type I PCM Format Type, set up for two-channel 16-bit PCM data.
	It therefore uses two audio subframes per audio frame.  The subframe size is two bytes and the bit resolution
	is 16 bits.  The Type III Format Type descriptor is identical to the Type I Format Type descriptor but with
	the bNrChannels field set to two, the bSubframeSize field set to two and the bBitResolution field set to 16.
	All the techniques used to correctly transport Type I PCM formatted streams over USB equally apply to Type III
	formatted streams.

	The non-PCM encoded audio bitstreams that are transferred within the basic 16-bit data area of the IEC1937
	subframes (time-slots 12 [LSB] to 27 [MSB]) are placed unaltered in the two available 16-bit audio subframes
	per audio frame of the Type III formatted USB stream.  The additional information in the IEC1937 subframes
	(channel status, user bit, etc.) is discarded.  Refer to the IEC1937 standard for a detailed description of the
	exact contents of the subframes.
*/
typedef struct ASFormatTypeIDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bFormatType;
    UInt8									bNrChannels;
    UInt8									bSubframeSize;
    UInt8									bBitResolution;
    UInt8									bSamFreqType;
    UInt8									sampleFreq[3];	// sample rates are 24 bit values -- arg!
    //... fill in for sample freqs - probably a union for either a min/max or an array
} ASFormatTypeIDescriptor, *ASFormatTypeIDescriptorPtr;

typedef struct ASFormatTypeIIDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bFormatType;
	UInt16									wMaxBitRate;
	UInt16									wSamplesPerFrame;
    UInt8									bSamFreqType;
    UInt8									sampleFreq[3];	// sample rates are 24 bit values -- arg!
    //... fill in for sample freqs - probably a union for either a min/max or an array
} ASFormatTypeIIDescriptor, *ASFormatTypeIIDescriptorPtr;

typedef struct ASInterfaceDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bTerminalLink;
    UInt8									bDelay;
    UInt8									wFormatTag[2];	// because it's not PPC aligned when declared as UInt16
} ASInterfaceDescriptor, *ASInterfaceDescriptorPtr;

typedef struct ASFormatSpecificDescriptorHeader {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									wFormatTag[2];	// because it's not PPC aligned when declared as UInt16
} ASFormatSpecificDescriptorHeader, *ASFormatSpecificDescriptorHeaderPtr;

typedef struct ASMPEGFormatSpecificDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									wFormatTag[2];	// because it's not PPC aligned when declared as UInt16
	UInt8									bmMPEGCapabilities[2];	// because it's not PPC aligned when declared as UInt16
	UInt8									bmMPEGFeatures;
} ASMPEGFormatSpecificDescriptor, *ASMPEGFormatSpecificDescriptorPtr;

typedef struct ASAC3FormatSpecificDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									wFormatTag[2];	// because it's not PPC aligned when declared as UInt16
	UInt8									bmBSID[4];		// because it's not PPC aligned when declared as UInt32
	UInt8									bmAC3Features;
} ASAC3FormatSpecificDescriptor, *ASAC3FormatSpecificDescriptorPtr;

typedef struct ASEndpointDescriptor {
    UInt8									bLength;
    UInt8									bDescriptorType;
    UInt8									bDescriptorSubtype;
    UInt8									bmAttributes;
    UInt8									bLockDelayUnits;
    UInt8									wLockDelay[2];	// because it's not PPC aligned when declared as UInt16
} ASEndpointDescriptor, *ASEndpointDescriptorPtr;


/* -------------------------------------------------------------------
	Classes
------------------------------------------------------------------- */


class USBACDescriptorObject : public OSObject {
    OSDeclareDefaultStructors (USBACDescriptorObject);

private:
	UInt8							unitID;
	UInt8							sourceID;

public:
    virtual void					free (void);

	virtual UInt8					GetSourceID (void) {return sourceID;}
	virtual UInt8					GetUnitID (void) {return unitID;}

	virtual void					SetSourceID (UInt8 srcID) {sourceID = srcID;}
	virtual void					SetUnitID (UInt8 termID) {unitID = termID;}

};

class USBInputTerminalObject : public USBACDescriptorObject {
private:
	UInt16							terminalType;
	UInt16							channelConfig;
	UInt8							assocTerminal;
	UInt8							numChannels;

public:
    virtual void					free (void);

	UInt8							GetAssocTerminal (void) {return assocTerminal;}
	UInt16							GetChannelConfig (void) {return channelConfig;}
	UInt8							GetNumChannels (void) {return numChannels;}
	UInt16							GetTerminalType (void) {return terminalType;}

	void							SetAssocTerminal (UInt8 assocTerm) {assocTerminal = assocTerm;}
	void							SetChannelConfig (UInt16 chanConfig) {channelConfig = chanConfig;}
	void							SetNumChannels (UInt8 numChan) {numChannels = numChan;}
	void							SetTerminalType (UInt16 termType) {terminalType = termType;}
};

class USBOutputTerminalObject : public USBACDescriptorObject {
private:
	UInt16							terminalType;
	UInt8							assocTerminal;

public:
    virtual void					free (void);

	UInt8							GetAssocTerminal (void) {return assocTerminal;}
	UInt16							GetTerminalType (void) {return terminalType;}

	void							SetAssocTerminal (UInt8 assocTerm) {assocTerminal = assocTerm;}
	void							SetTerminalType (UInt16 termType) {terminalType = termType;}
};

class USBMixerUnitObject : public USBACDescriptorObject {
private:
	UInt8 *							baSourceIDs;		// there are numInPins of these
	UInt8 *							bmControls;			// you don't know the size of this, calculate it using bLength and numInPins
	UInt16							channelConfig;
	UInt8							controlSize;		// This is the calculated size of bmControls
	UInt8							numInPins;
	UInt8							numChannels;

public:
    virtual void					free (void);

	UInt16							GetChannelConfig (void) {return channelConfig;}
	UInt8							GetNumInPins (void) {return numInPins;}
	UInt8							GetNumChannels (void) {return numChannels;}

	void							InitControlsArray (UInt8 * channelConfig, UInt8 bmControlSize);
	void							InitSourceIDs (UInt8 * baSrcIDs, UInt8 nrInPins);
	void							SetChannelConfig (UInt16 chanConfig) {channelConfig = chanConfig;}
	void							SetNumChannels (UInt8 numChan) {numChannels = numChan;}
};

class USBSelectorUnitObject : public USBACDescriptorObject {
private:
	UInt8 *							baSourceIDs;		// there are numInPins of these
	UInt8							numInPins;

public:
	virtual void					free (void);

	UInt8							GetNumInPins (void) {return numInPins;}
	UInt8 *							GetSelectorSources (void) {return baSourceIDs;}

	void							InitSourceIDs (UInt8 * baSrcIDs, UInt8 nrInPins);
};

class USBFeatureUnitObject : public USBACDescriptorObject {
private:
	UInt8 *							bmaControls;
	UInt8							controlSize;
	UInt8							numControls;

public:
    virtual void					free (void);

	Boolean							ChannelHasMuteControl (UInt8 channelNum);
	Boolean							ChannelHasVolumeControl (UInt8 channelNum);
	UInt8 *							GetControlsBMA (void) {return bmaControls;}
	UInt8							GetControlSize (void) {return controlSize;}
	UInt8							GetNumControls (void) {return numControls;}
	Boolean							MasterHasMuteControl (void);

	void							InitControlsArray (UInt8 * bmaControlsArrary, UInt8 numCntrls);
	void							SetControlSize (UInt8 cntrlSize) {controlSize = cntrlSize;}
};

class USBAudioControlObject : public OSObject {
	friend class USBAudioConfigObject;

    OSDeclareDefaultStructors (USBAudioControlObject);

private:
    OSArray *						theInputTerminals;
    OSArray *						theOutputTerminals;
	OSArray *						theFeatureUnits;
	OSArray *						theMixerUnits;
	OSArray *						theSelectorUnits;
    UInt16							adcVersion;			// in BCD
    UInt8							interfaceNumber;
    UInt8							alternateSetting;
    UInt8							numEndpoints;
    UInt8							interfaceClass;		// should always be 1
    UInt8							interfaceSubClass;	// should always be 1
    UInt8							interfaceProtocol;
    UInt8							numStreamInterfaces;
    UInt8							firstASInterface;

	USBFeatureUnitObject *			GetFeatureUnitObject (UInt8 unitID);
	USBFeatureUnitObject *			GetIndexedFeatureUnitObject (UInt8 index);
	USBInputTerminalObject *		GetInputTerminalObject (UInt8 unitID);
	USBMixerUnitObject *			GetIndexedMixerUnitObject (UInt8 index);
	USBSelectorUnitObject *			GetIndexedSelectorUnitObject (UInt8 index);
	USBMixerUnitObject *			GetMixerObject (UInt8 unitID);
	USBOutputTerminalObject *		GetOutputTerminalObject (UInt8 unitID);
	USBSelectorUnitObject *			GetSelectorUnitObject (UInt8 unitID);
	USBACDescriptorObject *			GetACDescriptorObject (UInt8 unitID);

    void							SetAlternateSetting (UInt8 altIntNumber) {alternateSetting = altIntNumber;}
    void							SetInterfaceClass (UInt8 intClass) {interfaceClass = intClass;}
    void							SetInterfaceNumber (UInt8 intNumber) {interfaceNumber = intNumber;}
    void							SetInterfaceProtocol (UInt8 intProtocol) {interfaceProtocol = intProtocol;}
    void							SetInterfaceSubClass (UInt8 intSubClass) {interfaceSubClass = intSubClass;}
    void							SetNumEndpoints (UInt8 numEndpts) {numEndpoints = numEndpts;}

public:
    static USBAudioControlObject * 	create (void);
    virtual void					free (void);
    USBInterfaceDescriptorPtr		ParseACInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 const currentInterface);

	Boolean							ChannelHasMuteControl (UInt8 featureUnitID, UInt8 channelNum);
	Boolean							ChannelHasVolumeControl (UInt8 featureUnitID, UInt8 channelNum);
	UInt16							GetADCVersion (void) {return adcVersion;}
    UInt8							GetAltInterfaceNum (void) {return alternateSetting;}
	UInt8							GetFeatureSourceID (UInt8 featureUnitID);
	UInt8							GetFeatureUnitID (UInt8 featureUnitID);
	UInt8							GetFeatureUnitIDConnectedToOutputTerminal (UInt8 outputTerminalID);
	UInt8							GetFirstASInterface (void) {return firstASInterface;}
	UInt8							GetIndexedFeatureUnitID (UInt8 featureUnitIndex);
	UInt8							GetIndexedMixerUnitID (UInt8 mixerUnitIndex);
	UInt8							GetIndexedSelectorUnitID (UInt8 selectorUnitIndex);
	UInt16							GetIndexedInputTerminalType (UInt8 index);
	UInt8							GetIndexedInputTerminalID (UInt8 index);
	UInt8							GetIndexedOutputTerminalID (UInt8 index);
	UInt16							GetIndexedOutputTerminalType (UInt8 index);
	UInt16							GetInputTerminalType (UInt8 terminalID);
    UInt8							GetInterfaceNum (void) {return interfaceNumber;}
    UInt8							GetInterfaceClass (void) {return interfaceClass;}
	UInt8							GetInterfaceProtocol (void) {return interfaceProtocol;}
    UInt8							GetInterfaceSubClass (void) {return interfaceSubClass;}
	UInt8							GetNumEndpoints (void) {return numEndpoints;}
	UInt8							GetNumInputTerminals (void);
	UInt8							GetNumOutputTerminals (void);
	UInt8							GetNumSelectorSources (UInt8 unitID);
	UInt8							GetNumStreamInterfaces (void) {return numStreamInterfaces;}
	UInt16							GetOutputTerminalType (UInt8 terminalID);
	UInt8 *							GetSelectorSources (UInt8 unitID);
	Boolean							MasterHasMuteControl (UInt8 featureUnitID);
};

class USBEndpointObject : public OSObject {

    OSDeclareDefaultStructors (USBEndpointObject);

private:
    UInt8							address;
    UInt8							attributes;
    UInt16							maxPacketSize;
    UInt8							synchAddress;
	UInt8							refreshInt;		// interpreted as 2^(10-refreshInt)ms between refreshes

public:
    static USBEndpointObject * 		create (void);
    virtual void					free (void);

	UInt8							GetAddress (void) {return address;}
	UInt8							GetAttributes (void) {return attributes;}
	UInt8							GetDirection (void) {return ((address & 0x80) >> 7);}
	UInt8							GetMaxPacketSize (void) {return maxPacketSize;}
	UInt8							GetSynchAddress (void) {return synchAddress;}
	UInt8							GetSyncType (void) {return (attributes >> 2);}
	UInt8							GetRefreshInt (void) {return refreshInt;}

    void							SetAddress (UInt8 theAddr) {address = theAddr;}
    void							SetAttributes (UInt8 theAttributes) {attributes = theAttributes;}
    void							SetMaxPacketSize (UInt16 maxPacket) {maxPacketSize = maxPacket;}
    void							SetSynchAddress (UInt8 synchAddr) {synchAddress = synchAddr;}
	void							SetRefreshInt (UInt8 refresh) {refreshInt = refresh;}
};

class USBCSASIsocADEndpointObject {
private:
    Boolean							sampleFreqControl;
    Boolean							pitchControl;
    Boolean							maxPacketsOnly;
    UInt8							lockDelayUnits;
    UInt16							lockDelay;
    UInt8							attributes;

	// You shouldn't need to get the attributes directly, instead use DoesMaxPacketsOnly (), HasPitchControl (), and HasSampleFreqControl ()
	UInt8							GetAttributes (void) {return attributes;}

public:
    USBCSASIsocADEndpointObject (Boolean theSampleFreqControl, Boolean thePitchControl, Boolean theMaxPacketsOnly, UInt8 theLockDelayUnits, UInt16 theLockDelay);

	Boolean							DoesMaxPacketsOnly (void) {return maxPacketsOnly;}
	UInt8							GetLockDelay (void) {return lockDelay;}
	UInt8							GetLockDelayUnits (void) {return lockDelayUnits;}
	Boolean							HasPitchControl (void) {return pitchControl;}
	Boolean							HasSampleFreqControl (void) {return sampleFreqControl;}
};

class USBAudioStreamObject : public OSObject {
	friend class USBAudioConfigObject;

    OSDeclareDefaultStructors (USBAudioStreamObject);

private:
    OSArray *						theEndpointObjects;
    USBCSASIsocADEndpointObject *	theIsocEndpointObject;

    UInt32 *						sampleFreqs;
	UInt32							bmAC3BSID;
	UInt16							bmMPEGCapabilities;
    UInt16							formatTag;
	UInt16							maxBitRate;
	UInt16							samplesPerFrame;
	UInt8							bmMPEGFeatures;
	UInt8							bmAC3Features;
    UInt8							interfaceNumber;
    UInt8							alternateSetting;
    UInt8							numEndpoints;
    UInt8							interfaceClass;		// should always be 1
    UInt8							interfaceSubClass;	// should always be 2
    UInt8							interfaceProtocol;
    UInt8							terminalLink;
    UInt8							delay;
    UInt8							numChannels;
    UInt8							subframeSize;
    UInt8							bitResolution;
    UInt8							numSampleFreqs;

	USBEndpointObject *				GetEndpointByAddress (UInt8 address);
    USBEndpointObject *				GetIndexedEndpointObject (UInt8 index);
    USBCSASIsocADEndpointObject *	GetIndexedASIsocEndpointObject (UInt8 index);
    USBEndpointObject *				GetEndpointObjectByAddress (UInt8 address);
    USBCSASIsocADEndpointObject *	GetASIsocEndpointObjectByAddress (UInt8 address);

    void							SetAlternateSetting (UInt8 altIntNumber) {alternateSetting = altIntNumber;}
    void							SetInterfaceClass (UInt8 intClass) {interfaceClass = intClass;}
    void							SetInterfaceNumber (UInt8 intNumber) {interfaceNumber = intNumber;}
    void							SetInterfaceProtocol (UInt8 intProtocol) {interfaceProtocol = intProtocol;}
    void							SetInterfaceSubClass (UInt8 intSubClass) {interfaceSubClass = intSubClass;}
    void							SetNumEndpoints (UInt8 numEndpts) {numEndpoints = numEndpts;}

public:
    static USBAudioStreamObject *	create (void);
    virtual void					free (void);

    USBInterfaceDescriptorPtr		ParseASInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 const currentInterface);

	UInt32							GetAC3BSID (void) {return bmAC3BSID;}
    UInt8							GetAltInterfaceNum (void) {return alternateSetting;}
	UInt8							GetDelay (void) {return delay;}
//	UInt8							GetEndpointAddress (void) {if (theEndpointObject) return theEndpointObject->GetAddress (); else return 0;}
//	UInt8							GetEndpointAttributes (void) {if (theEndpointObject) return theEndpointObject->GetAttributes (); else return 0;}
//	UInt8							GetEndpointDirection (void) {if (theEndpointObject) return theEndpointObject->GetDirection (); else return 0;}
	UInt16							GetFormatTag (void) {return formatTag;}
    UInt8							GetInterfaceNum (void) {return interfaceNumber;}
    UInt8							GetInterfaceClass (void) {return interfaceClass;}
	UInt8							GetInterfaceProtocol (void) {return interfaceProtocol;}
    UInt8							GetInterfaceSubClass (void) {return interfaceSubClass;}
	UInt8							GetIsocAssociatedEndpointAddress (UInt8 address);
	UInt8							GetIsocAssociatedEndpointRefreshInt (UInt8 address);
	UInt8							GetIsocEndpointAddress (UInt8 direction);
	UInt8							GetIsocEndpointDirection (UInt8 index);
	UInt8							GetIsocEndpointSyncType (UInt8 address);
//	UInt8							GetMaxPacketSize (void) {if (theEndpointObject) return theEndpointObject->GetMaxPacketSize (); else return 0;}
	UInt16							GetMaxBitRate (void) {return maxBitRate;}
    UInt8							GetNumChannels (void) {return numChannels;}
	UInt8							GetNumEndpoints (void) {return numEndpoints;}
    UInt8							GetNumSampleRates (void) {return numSampleFreqs;}
	UInt16							GetSamplesPerFrame (void) {return samplesPerFrame;}
    UInt8							GetSampleSize (void) {return bitResolution;}
    UInt8							GetSubframeSize (void) {return subframeSize;}
    UInt32 *						GetSampleRates (void) {return sampleFreqs;}
    UInt8							GetTerminalLink (void) {return terminalLink;}

	Boolean							IsocEndpointDoesMaxPacketsOnly (void) {if (theIsocEndpointObject) return theIsocEndpointObject->DoesMaxPacketsOnly (); else return 0;}
	UInt8							IsocEndpointGetLockDelay (void) {if (theIsocEndpointObject) return theIsocEndpointObject->GetLockDelay (); else return 0;}
	UInt8							IsocEndpointGetLockDelayUnits (void) {if (theIsocEndpointObject) return theIsocEndpointObject->GetLockDelayUnits (); else return 0;}
	Boolean							IsocEndpointHasPitchControl (void) {if (theIsocEndpointObject) return theIsocEndpointObject->HasPitchControl (); else return 0;}
	Boolean							IsocEndpointHasSampleFreqControl (void) {if (theIsocEndpointObject) return theIsocEndpointObject->HasSampleFreqControl (); else return 0;}
};

class USBAudioConfigObject : public OSObject {
    OSDeclareDefaultStructors (USBAudioConfigObject);

private:
    IOUSBConfigurationDescriptor *	theConfigurationDescriptorPtr;
    OSArray *						theControls;
	UInt8							theControlInterfaceNum;
    OSArray *						theStreams;

public:
    static USBAudioConfigObject *	 create (const IOUSBConfigurationDescriptor * newConfigurationDescriptor);
    virtual bool					init (const IOUSBConfigurationDescriptor * newConfigurationDescriptor);
    virtual void					free (void);

	Boolean							ChannelHasMuteControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID, UInt8 channelNum);
	Boolean							ChannelHasVolumeControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID, UInt8 channelNum);
	UInt8							FindNextAltInterfaceWithNumChannels (UInt8 interfaceNum, UInt8 startingAltInterface, UInt8 numChannelsRequested);
	UInt8							FindNextAltInterfaceWithSampleSize (UInt8 interfaceNum, UInt8 startingAltInterface, UInt8 sampleSizeRequested);
	UInt8							FindNextAltInterfaceWithSampleRate (UInt8 interfaceNum, UInt8 startingAltInterface, UInt32 sampleRateRequested);
	UInt8							FindAltInterfaceWithSettings (UInt8 interfaceNum, UInt8 numChannels, UInt8 sampleSize, UInt32 sampleRate = 0);
	UInt32							GetAC3BSID (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetFeatureUnitIDConnectedToOutputTerminal (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 outputTerminalID);
    UInt8							GetFirstStreamInterfaceNum (void);
    UInt8							GetControlInterfaceNum (void);
	UInt16							GetFormat (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt32							GetHighestSampleRate (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetIsocAssociatedEndpointAddress (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address);
	UInt8							GetIsocAssociatedEndpointRefreshInt (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address);
	UInt8							GetIsocEndpointAddress (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 direction);
	UInt8							GetIsocEndpointDirection (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetIsocEndpointSyncType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 address);
	UInt8							GetIndexedFeatureUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitIndex);
	UInt8							GetIndexedMixerUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 mixerUnitIndex);
	UInt8							GetIndexedSelectorUnitID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 selectorUnitIndex);
	UInt16							GetIndexedInputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index);
	UInt8							GetIndexedInputTerminalID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index);
	UInt8							GetIndexedOutputTerminalID (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index);
	UInt16							GetIndexedOutputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 index);
	UInt16							GetInputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 terminalID);
    UInt8							GetInterfaceClass (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt8							GetInterfaceSubClass (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt32							GetLowestSampleRate (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt16							GetMaxBitRate (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt8							GetNumAltStreamInterfaces (UInt8 interfaceNum);
    UInt8							GetNumChannels (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt8							GetNumSampleRates (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetNumInputTerminals (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetNumOutputTerminals (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							GetNumSelectorSources (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 unitID);
    UInt8							GetNumStreamInterfaces (void);
	UInt16							GetOutputTerminalType (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 terminalID);
	UInt16							GetSamplesPerFrame (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt32 *						GetSampleRates (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt8							GetSampleSize (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8 *							GetSelectorSources (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 unitID);
    UInt8							GetSubframeSize (UInt8 interfaceNum, UInt8 altInterfaceNum);
    UInt8							GetTerminalLink (UInt8 interfaceNum, UInt8 altInterfaceNum);
	Boolean							IsocEndpointDoesMaxPacketsOnly (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							IsocEndpointGetLockDelay (UInt8 interfaceNum, UInt8 altInterfaceNum);
	UInt8							IsocEndpointGetLockDelayUnits (UInt8 interfaceNum, UInt8 altInterfaceNum);
	Boolean							IsocEndpointHasPitchControl (UInt8 interfaceNum, UInt8 altInterfaceNum);
	Boolean							IsocEndpointHasSampleFreqControl (UInt8 interfaceNum, UInt8 altInterfaceNum);
	Boolean							MasterHasMuteControl (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt8 featureUnitID);
	Boolean							VerifySampleRateIsSupported (UInt8 interfaceNum, UInt8 altInterfaceNum, UInt32 verifyRate);

private:
	USBAudioControlObject *			GetControlObject (UInt8 interfaceNum, UInt8 altInterfaceNum);
    USBAudioStreamObject *			GetStreamObject (UInt8 interfaceNum, UInt8 altInterfaceNum);
    void							ParseConfigurationDescriptor (void);
    USBInterfaceDescriptorPtr		ParseInterfaceDescriptor (USBInterfaceDescriptorPtr theInterfacePtr, UInt8 * interfaceClass, UInt8 * interfaceSubClass);
	void							DumpConfigMemoryToIOLog (void);

};

#endif
