#ifndef _APPLEUSBAUDIOLEVELCONTROL_H
#define _APPLEUSBAUDIOLEVELCONTROL_H

#include <IOKit/audio/IOAudioLevelControl.h>
#include <IOKit/usb/IOUSBInterface.h>

class AppleUSBAudioDevice;
typedef struct call_entry *thread_call_t;

typedef IOReturn (*USBDeviceRequest)(IOUSBDevRequest * request, void * refCon = 0, IOUSBCompletion * completion = 0);

// PRAM read write values
enum{
	kMaximumPRAMVolume 	= 7,
	kMinimumPRAMVolume	= 0,
	KNumPramVolumeSteps	= (kMaximumPRAMVolume - kMinimumPRAMVolume + 1),
	kPRamVolumeAddr	= 8,

	kDefaultVolume	= 0x006E006E,
	kInvalidVolumeMask	= 0xFE00FE00
};

#define kiSubMaxVolume		60
#define kiSubVolumePercent	92

class AppleUSBAudioLevelControl : public IOAudioLevelControl
{
    OSDeclareDefaultStructors(AppleUSBAudioLevelControl);

    UInt8					unitID;
    UInt8					interfaceNumber;
    UInt8					controlSelector;
    UInt8					channelNumber;
    SInt16					offset;
	SInt16					volRes;
    thread_call_t			setValueThreadCall;
    USBDeviceRequest		usbDeviceRequest;
	void *					callerRefCon;
	Boolean					gExpertMode;
    UInt32					fMaxVolume;
    UInt32					fMinVolume;
	Boolean					fShouldUpdatePRAM;

public:
	static AppleUSBAudioLevelControl *create(UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theControlSelector, UInt8 theChannelNumber, Boolean shouldUpdatePRAM, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 subType, UInt32 usage);

	virtual bool init(UInt8 theUnitID, UInt8 theInterfaceNumber, UInt8 theControlSelector, UInt8 theChannelNumber, Boolean shouldUpdatePRAM, USBDeviceRequest theUSBDeviceRequest, void *theCallerRefCon, UInt32 subType, UInt32 usage, OSDictionary *properties = NULL);
	virtual void free();

	virtual IOReturn performValueChange(OSObject * newValue);
	virtual void updateUSBValue();
	virtual void updateUSBValue(SInt32 newValue);

	static void updateValueCallback(void *arg1, void *arg2);

private:
	SInt16	GetCurVolume (UInt8 interfaceNumber, UInt8 channelNumber, IOReturn * error);
	SInt16	GetMaxVolume (UInt8 interfaceNumber, UInt8 channelNumber, IOReturn * error);
	SInt16	GetMinVolume (UInt8 interfaceNumber, UInt8 channelNumber, IOReturn * error);
	UInt16	GetVolumeResolution (UInt8 interfaceNumber, UInt8 channelNumber, IOReturn * error);
	IOReturn	SetCurVolume (UInt8 interfaceNumber, UInt8 channelNumber, SInt16 volume);
	IOFixed		ConvertUSBVolumeTodB (SInt16 volume);
	IORegistryEntry * FindEntryByNameAndProperty (const IORegistryEntry * start, const char * name, const char * key, UInt32 value);
	UInt8 VolumeToPRAMValue (SInt32 leftVol, SInt32 rightVol);
	void WritePRAMVol (SInt32 leftVol, SInt32 rightVol);
};

#endif
