/*
 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
 
//--------------------------------------------------------------------------------
//
//	File:		AppleUSBAudioDevice.h
//
//	Contains:	Support for the USB Audio Class Control Interface.
//
//	Technology:	OS X
//
//--------------------------------------------------------------------------------

#ifndef _APPLEUSBAUDIODEVICE_H
#define _APPLEUSBAUDIODEVICE_H

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

#include <IOKit/IOLocks.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IORegistryEntry.h>
#include <IOKit/IOMessage.h>

#include <IOKit/audio/IOAudioDevice.h>
#include <IOKit/audio/IOAudioEngine.h>
#include <IOKit/audio/IOAudioPort.h>
#include <IOKit/audio/IOAudioControl.h>
#include <IOKit/audio/IOAudioStream.h>
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/audio/IOAudioSelectorControl.h>

#include <IOKit/usb/USB.h>
#include <IOKit/usb/IOUSBInterface.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>

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

#define kStringBufferSize				255
// The following value is defined in USB 1.0 Class Spec section 5.2.2.4.3.2
#define kNegativeInfinity				0x8000

enum {
	kIOUSBVendorIDHarmonKardon			= 0x05FC, 
	kIOUSBVendorMicronas				= 0x074D
};

enum {
	kVolumeControl						= 1,
	kMuteControl						= 2
};

enum {
	kStudioDisplay15CRT					= 0x9115,
	kStudioDisplay17CRT					= 0x9113,
	kCinemaDisplay						= 0x9116,
	kStudioDisplay17FP					= 0x9117
};

class IOUSBInterface;
class AppleUSBAudioEngine;

/*
 * @class AppleUSBAudioDevice
 * @abstract : universal Apple USB driver
 * @discussion : Current version of the driver deals with outputing stereo 16 bits data at 44100kHz
 */

#define kEngine							"engine"
#define kInterface						"interface"
#define kAltSetting						"altsetting"
#define kInputGainControls				"inputgaincontrols"
#define kInputMuteControls				"inputmutecontrols"
#define kPassThruVolControls			"passthrucontrols"
#define kOutputVolControls				"outputvolcontrols"
#define kPassThruPathsArray				"passthrupathsarray"

#define kWallTimeExtraPrecision         10000

class AppleUSBAudioDevice : public IOAudioDevice {
    OSDeclareDefaultStructors (AppleUSBAudioDevice);

public:
    IOUSBInterface *					mControlInterface;
	
	// These member variables are for anchored time stamp algorithm
	
	UInt64								mWallTimePerUSBCycle;
	UInt64								mNewReferenceUSBFrame;
	AbsoluteTime						mNewReferenceWallTime;
	UInt64								mLastUSBFrame;
	UInt64								mLastWallTime_nanos;
	#if DEBUGANCHORS
	UInt64								mAnchorFrames[kAnchorsToAccumulate];
	AbsoluteTime						mAnchorTimes[kAnchorsToAccumulate];
	#endif

protected:
    USBAudioConfigObject *				mUSBAudioConfig;
	OSArray *							mControlGraph;
    IORecursiveLock *					mInterfaceLock;
	Boolean								mTerminatingDriver;
	thread_call_t						mInitHardwareThread;
	thread_call_t						mRetryEQDownloadThread;
	Boolean								mDeviceIsInMonoMode;
	OSArray *							mMonoControlsArray;		// this flag is set by AppleUSBAudioEngine::performFormatChange
	OSArray *							mRegisteredEngines;
	
	// These member variables are for anchored time stamp algorithm
	
	UInt8								mAnchorResetCount;
	IOTimerEventSource *				mUpdateTimer;
	bool								mSingleSampleRateDevice;
	AppleUSBAudioEngine *				mFailingAudioEngine;

public:
	virtual	bool			start (IOService * provider);
    virtual	void			free ();
    virtual	void			stop (IOService *provider);
	virtual	bool			initHardware (IOService * provider);
	static	void			initHardwareThread (AppleUSBAudioDevice * aua, void * provider);
	static	IOReturn		initHardwareThreadAction (OSObject * owner, void * provider, void * arg2, void * arg3, void * arg4);
	virtual	IOReturn		protectedInitHardware (IOService * provider);
	virtual	Boolean			ShouldUpdatePRAM (void);
			Boolean			FindSoundNode (void);
    virtual	IOReturn		message (UInt32 type, IOService * provider, void * arg);
	virtual	bool			ControlsStreamNumber (UInt8 streamNumber);
	virtual	IOReturn		createControlsForInterface (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altSettingNum);
	virtual void			setConfigurationApp (const char *bundleID);
	virtual	IOReturn		performPowerStateChange (IOAudioDevicePowerState oldPowerState, IOAudioDevicePowerState newPowerState, UInt32 *microSecsUntilComplete);
    virtual	USBAudioConfigObject * GetUSBAudioConfigObject (void) {return mUSBAudioConfig;}
	virtual	bool			willTerminate (IOService * provider, IOOptionBits options);
	virtual	OSArray * 		BuildConnectionGraph (UInt8 controlInterfaceNum);
	virtual	OSArray * 		BuildPath (UInt8 controlInterfaceNum, UInt8 startingUnitID, OSArray *allPaths, OSArray * thisPath);
	virtual	char * 			TerminalTypeString (UInt16 terminalType);

	virtual	SInt32			getEngineInfoIndex (AppleUSBAudioEngine * inAudioEngine);
	virtual	IOReturn		doControlStuff (IOAudioEngine *audioEngine, UInt8 interfaceNum, UInt8 altSettingNum);
	virtual	IOReturn		doPlaythroughSetup (AppleUSBAudioEngine * usbAudioEngine, OSArray * playThroughPaths, UInt8 interfaceNum, UInt8 altSettingNum);
	virtual	IOReturn		addSelectorSourcesToSelectorControl (IOAudioSelectorControl * theSelectorControl, OSArray * arrayOfPathsFromOutputTerminal, UInt32 pathsToOutputTerminalN, UInt8 selectorIndex);
	virtual	OSString *		getNameForPath (OSArray * arrayOfPathsFromOutputTerminal, UInt32 * pathIndex, UInt8 startingPoint);
	virtual	OSString *		getNameForMixerPath (OSArray * arrayOfPathsFromOutputTerminal, UInt32 * pathIndex, UInt8 startingPoint);

	static	IOReturn		controlChangedHandler (OSObject *target, IOAudioControl *audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	IOReturn		protectedControlChangedHandler (IOAudioControl *audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	IOReturn		doSelectorControlChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	UInt8			getSelectorSetting (UInt8 selectorID);
	virtual	IOReturn		setSelectorSetting (UInt8 selectorID, UInt8 setting);
	virtual	IOReturn		getFeatureUnitSetting (UInt8 controlSelector, UInt8 unitID, UInt8 channelNumber, UInt8 requestType, SInt16 * target);
	virtual	IOReturn		setFeatureUnitSetting (UInt8 controlSelector, UInt8 unitID, UInt8 channelNumber, UInt8 requestType, UInt16 newValue, UInt16 newValueLen);
	virtual	OSArray *		getPlaythroughPaths ();
	virtual	UInt8			getBestFeatureUnitInPath (OSArray * thePath, UInt32 direction, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 controlTypeWanted);
	virtual	void			addVolumeControls (AppleUSBAudioEngine * usbAudioEngine, UInt8 featureUnitID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage);
	virtual	void			addMuteControl (AppleUSBAudioEngine * usbAudioEngine, UInt8 featureUnitID, UInt8 interfaceNum, UInt8 altSettingNum, UInt32 usage);
	virtual	IOReturn		getCurMute (UInt8 unitID, UInt8 channelNumber, SInt16 * target);
	virtual	IOReturn		getCurVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target);
	virtual	IOReturn		getMaxVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target);
	virtual	IOReturn		getMinVolume (UInt8 unitID, UInt8 channelNumber, SInt16 * target);
	virtual	IOReturn		getVolumeResolution (UInt8 unitID, UInt8 channelNumber, UInt16 * target);
	virtual	IOReturn		setCurVolume (UInt8 unitID, UInt8 channelNumber, SInt16 volume);
	virtual	IOReturn		setCurMute (UInt8 unitID, UInt8 channelNumber, SInt16 mute);
	virtual	IOReturn		doInputSelectorChange (IOAudioControl *audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	IOReturn		doVolumeControlChange (IOAudioControl *audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	IOReturn		doToggleControlChange (IOAudioControl *audioControl, SInt32 oldValue, SInt32 newValue);
	virtual IOReturn		doPassThruSelectorChange (IOAudioControl * audioControl, SInt32 oldValue, SInt32 newValue);
	virtual	IOFixed			ConvertUSBVolumeTodB (SInt16 volume);
	virtual void			setMonoState (Boolean state);
	virtual UInt8			getDeviceSpeed (); // added for rdar://4168019
	virtual	bool			detectSplitTransactions (); // added for rdar://3959606
	virtual Boolean			checkForUHCI (); // added for rdar://3727110

	virtual	IOReturn		deviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion = NULL);			// Depricated, don't use
	virtual	IOReturn		deviceRequest (IOUSBDevRequestDesc * request, IOUSBCompletion * completion = NULL);
	static	IOReturn		deviceRequest (IOUSBDevRequest * request, AppleUSBAudioDevice * self, IOUSBCompletion * completion = 0);

	#ifdef DEBUG
    virtual void			retain() const;
    virtual void			release() const;
	#endif
	virtual bool			matchPropertyTable (OSDictionary * table, SInt32 *score);

	// The following methods are for the anchored time stamp algorithm
	virtual IOReturn		getAnchorFrameAndTimeStamp (UInt64 *frame, AbsoluteTime *time);
	virtual IOReturn		getFrameAndTimeStamp (UInt64 *frame, AbsoluteTime *time);
	virtual UInt64			getWallTimeInNanos (void);
	virtual	UInt64			jitterFilter (UInt64 invCoefficient, UInt64 prev, UInt64 curr);
	
	// The following method is for regulating format changes
	virtual	UInt32			formatChangeController (IOAudioEngine *audioEngine, IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate);
	virtual bool			getSingleSampleRateDevice (void) {return mSingleSampleRateDevice;};
	virtual void			setSingleSampleRateDevice (bool isSingleSampleRateDevice) {mSingleSampleRateDevice = isSingleSampleRateDevice;};
	virtual void			setShouldSyncSampleRates (AppleUSBAudioEngine * problemEngine) {mFailingAudioEngine = problemEngine;};
	
	virtual	AppleUSBAudioEngine * otherEngine (AppleUSBAudioEngine * thisEngine);
	virtual IOReturn		getBothEngines (AppleUSBAudioEngine ** firstEngine, AppleUSBAudioEngine ** secondEngine);
	
private:
	virtual	void			updateWallTimePerUSBCycle ();
	static	void			TimerAction (OSObject * owner, IOTimerEventSource * sender);
	virtual	void			doTimerAction (IOTimerEventSource * timer);
	#if DEBUGANCHORS
	virtual void			accumulateAnchor (UInt64 anchorFrame, AbsoluteTime timeStamp);
	#endif
	
};

#endif /* _APPLEUSBAUDIODEVICE_H */

