/*
 * 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:		AppleUSBAudioEngine.h
//
//	Contains:	Support for the USB Audio Class Stream Interface.
//
//	Technology:	Mac OS X
//
//--------------------------------------------------------------------------------

#ifndef _APPLEUSBAUDIOENGINE_H
#define _APPLEUSBAUDIOENGINE_H

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

#include <IOKit/IOLib.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOService.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOMultiMemoryDescriptor.h>

#include <IOKit/audio/IOAudioDevice.h>
#include <IOKit/audio/IOAudioPort.h>
#include <IOKit/audio/IOAudioTypes.h>
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/audio/IOAudioLevelControl.h>
#include <IOKit/audio/IOAudioEngine.h>
#include <IOKit/audio/IOAudioStream.h>

#include <IOKit/usb/IOUSBPipe.h>
#include <IOKit/usb/IOUSBDevice.h>
#include <IOKit/usb/IOUSBInterface.h>

#include "AppleUSBAudioCommon.h"
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioMuteControl.h"

#include "USBAudioObject.h"
#include "AppleiSubEngine.h"
#include "AppleUSBAudioClip.h"

class AppleUSBAudioDevice;

//	-----------------------------------------------------------------

#define	kSampleRate_44100				44100
#define kDefaultSamplingRate			kSampleRate_44100
#define	kBitDepth_16bits				16
#define	kChannelDepth_MONO				1
#define	kChannelDepth_STEREO			2

#define kFixedPoint10_14ByteSize		3
#define	kFixedPoint16_16ByteSize		4

#define kMinimumFrameOffset				5
#define kRefreshInterval				128
#define kRefreshCount					8

#define RECORD_NUM_USB_FRAME_LISTS				128
#define RECORD_NUM_USB_FRAMES_PER_LIST			2
#define RECORD_NUM_USB_FRAME_LISTS_TO_QUEUE		64

#define PLAY_NUM_USB_FRAME_LISTS				4
#define PLAY_NUM_USB_FRAMES_PER_LIST			64
#define PLAY_NUM_USB_FRAME_LISTS_TO_QUEUE		2

class IOSyncer;
class AppleUSBAudioEngine;
class AppleUSBAudioPlugin;

/* THIS LOOKS UNUSED
typedef struct FrameListWriteInfo {
    AppleUSBAudioEngine *				audioEngine;
    UInt32								frameListNum;
    UInt32								retryCount;
} FrameListWriteInfo;
*/

class AppleUSBAudioEngine : public IOAudioEngine {
    friend class AppleUSBAudioDevice;

    OSDeclareDefaultStructors (AppleUSBAudioEngine);

public:
    virtual bool init (OSDictionary *properties);
    virtual void free ();
    virtual bool initHardware (IOService *provider);
    virtual bool start (IOService *provider);
    virtual void stop (IOService *provider);
	virtual bool requestTerminate (IOService * provider, IOOptionBits options);
    virtual bool terminate (IOOptionBits options = 0);

    virtual IOReturn performAudioEngineStart ();
    virtual IOReturn performAudioEngineStop ();
    
//    virtual IOAudioEngineState _setState (IOAudioEngineState newState);
	static void requestiSubClose (IOAudioEngine * audioEngine);

	static void sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames);
	#if PRIMEISOCINPUT
	static void primeInputPipeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
	#endif
    static void readHandler (void * object, void * frameListIndex, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
    static void writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
	static void writeHandlerForUHCI (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames);
	static IOReturn iSubAttachChangeHandler (IOService *target, IOAudioControl *passThruControl, SInt32 oldValue, SInt32 newValue);
	virtual IOReturn iSubAttachChangeCall (Boolean isiSubCompatible);
	virtual IOReturn pluginDeviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion);
	virtual void pluginSetConfigurationApp (const char * bundleID);
	virtual void registerPlugin (AppleUSBAudioPlugin * thePlugin);
	static void	pluginLoaded (AppleUSBAudioEngine * usbAudioEngineObject);

protected:
	volatile UInt32						mCurrentFrameList;
	volatile UInt32						mShouldStop;
	UInt64								mUSBFrameToQueue;
	UInt64								mNextSyncReadFrame;
	
	UInt64 *							mFrameQueuedForList;
	#if DEBUGTIMESTAMPS
		UInt64								mLastTimeStamp_nanos;
		UInt64								mLastStampDifference;
		SInt64								mStampDrift;
		UInt64								mLastWrapFrame;
	#endif
	// UInt64							mReferenceUSBFrame;
	// AbsoluteTime						mReferenceWallTime;
	bool								mSplitTransactions;
	IOLock *							mCoalescenceMutex;
	
	IOUSBLowLatencyIsocFrame *			mUSBIsocFrames;
	IOUSBIsocFrame						mSampleRateFrame;
	IOUSBLowLatencyIsocCompletion *		mUSBCompletion;
	IOUSBIsocCompletion					mSampleRateCompletion;
	IOUSBInterface *					mStreamInterface;
	IOUSBPipe *							mPipe;
	IOUSBPipe *							mAssociatedPipe;
	IOSyncer *							mDeviceAndEngineSyncer;
	AppleUSBAudioDevice *				mUSBAudioDevice;
	IOBufferMemoryDescriptor *			mUSBBufferDescriptor;
	IOBufferMemoryDescriptor *			mSampleBufferMemoryDescriptor;
	#if PRIMEISOCINPUT
	IOUSBLowLatencyIsocFrame *			mPrimeInputIsocFrames;
	IOUSBLowLatencyIsocCompletion		mPrimeInputCompletion;
	#endif
	IOMultiMemoryDescriptor *			mWrapRangeDescriptor;
	IOSubMemoryDescriptor *				mWrapDescriptors[2];
	IOSubMemoryDescriptor **			mSampleBufferDescriptors;
	IOMemoryDescriptor *				mAssociatedEndpointMemoryDescriptor;
	
	// UHCI additions
	
	UInt32								mSampleBufferSizeExtended;			
	UInt16								mNumFramesInFirstList;
	IOUSBLowLatencyIsocCompletion		mExtraUSBCompletion;
	UInt16								mAverageFrameSize;					// These sizes are in bytes.
	UInt16								mAlternateFrameSize;
	UInt16								mReadUSBFrameSize;

	// end UHCI additions
	
	void *								mReadBuffer;			
	UInt32 *							mAverageSampleRateBuffer;		// needs to be 4 bytes for a 10.14 or 16.16 value
	thread_call_t						miSubTeardownThreadCall;
	thread_call_t						mPluginInitThread;
	thread_call_t						miSubOpenThreadCall;
	IOAudioSampleRate					mCurSampleRate;
	UInt32								mLastPreparedBufferOffset;
	UInt32								mSafeErasePoint;
	UInt32								mLastSafeErasePoint;
	UInt32								mLastClippedFrame;
	UInt32								mReadUSBFrameListSize;
	UInt32								mBufferOffset;
	UInt32								mAverageSampleRate;
	UInt32								mNumUSBFrameLists;
	UInt32								mNumUSBFramesPerList;
	UInt32								mNumUSBFrameListsToQueue;
	UInt32								mSampleBufferSize;
	UInt32								mBytesPerSampleFrame;
	UInt32								mFractionalSamplesLeft;
	#if DEBUGLATENCY
		UInt32								mLastFrameListSize;
		UInt32								mThisFrameListSize;
	#endif
	UInt16								mSampleSize;
	UInt8								mInterfaceNumber;
	UInt8								mAlternateSettingID;
	UInt8								mRefreshInterval;
	UInt8								mFramesUntilRefresh;
	UInt8								mFeedbackPacketSize;
	UInt8								mDirection;
	Boolean								mInCompletion;
	Boolean								mUSBStreamRunning;
	Boolean								mStartiSub;
	Boolean								mJustResetClipPosition;	// aml 3.29.02 added to match AOA
	Boolean								miSubIsOpen;
	Boolean								mTerminatingDriver;
	Boolean								mUHCISupport;
	IOAudioStream *						mMainStream;

	IONotifier *						mPluginNotification;
	AppleUSBAudioPlugin *				mPlugin;

	// For iSub
	IOMemoryDescriptor *				miSubBufferMemory;
	UInt32								miSubLoopCount;
	SInt32								miSubBufferOffset;		// Where we are writing to in the iSub buffer
	IONotifier *						miSubEngineNotifier;
	IOAudioToggleControl *				miSubAttachToggle;
	AppleiSubEngine *					miSubEngine;
	AppleiSubEngine *					mOldiSubEngine;
	float *								mLowFreqSamples;
	float *								mHighFreqSamples;
	PreviousValues						mFilterState;
	PreviousValues						mFilterState2;
	PreviousValues						mPhaseCompState;
	float								mSrcPhase;
	float								mSrcState;
	Boolean								mNeedToSync;
	Boolean								mNeedTimeStamps;
	#if DEBUGLATENCY
		bool								mHaveClipped;
	#endif
	bool								mHaveTakenFirstTimeStamp;
	
	// Default stream format and sample rate are stored.
	IOAudioStreamFormat					mDefaultAudioStreamFormat;
	IOAudioSampleRate					mDefaultAudioSampleRate;
	
	static inline IOFixed IOUFixedDivide(UInt32 a, UInt32 b)
	{
		return (IOFixed)((((UInt64) a) << 16) / ((UInt64) b));
	}

	static inline UInt32 IOUFixedMultiply(UInt32 a, UInt32 b)
	{
		return (UInt32)((((UInt64) a) * ((UInt64) b)) >> 16);
	}

	void		GetDeviceInfo (void);
	IOReturn	PrepareWriteFrameList (UInt32 usbFrameListIndex);
	IOReturn	PrepareAndReadFrameLists (UInt8 sampleSize, UInt8 numChannels, UInt32 usbFrameListIndex);
	IOReturn	SetSampleRate (USBAudioConfigObject *usbAudio, UInt32 sampleRate);
	IOReturn	AddAvailableFormatsFromDevice (USBAudioConfigObject *usbAudio);
	IOReturn	CheckForAssociatedEndpoint (USBAudioConfigObject *usbAudio);
	IOReturn	GetDefaultSettings (UInt8 * altSettingID, IOAudioSampleRate * sampleRate);	// added for rdar://3866513 

    static bool audioDevicePublished (AppleUSBAudioEngine *audioEngine, void *ref, IOService *newService);
    static bool	iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService);

	virtual bool willTerminate (IOService * provider, IOOptionBits options);

	virtual OSString * getGlobalUniqueID ();
    virtual IOReturn readFrameList (UInt32 frameListNum);
    virtual IOReturn writeFrameList (UInt32 frameListNum);

    virtual IOReturn startUSBStream ();
    virtual IOReturn stopUSBStream ();

	static IOReturn iSubCloseAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
	static IOReturn iSubOpenAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
	static void iSubTeardown (AppleUSBAudioEngine *usbAudioEngine, thread_call_t iSubTeardownThreadCall);
	static void iSubOpen (AppleUSBAudioEngine *usbAudioEngineObject);
	virtual void iSubTeardownConnection (void);
	bool isiSubCompatibleFormat (const IOAudioStreamFormat *format, IOAudioSampleRate sampleRate);

    virtual UInt32 getCurrentSampleFrame (void);

    virtual IOAudioStreamDirection getDirection (void);
    virtual void *getSampleBuffer (void);
	virtual UInt32 getSampleBufferSize (void);
	virtual void CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBLowLatencyIsocFrame * pFrames);
	virtual void resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame);
    virtual IOReturn clipOutputSamples (const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream);
	virtual IOReturn convertInputSamples (const void *sampleBuf, void *destBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream);
	
    virtual IOReturn performFormatChange (IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate);
	virtual	IOReturn controlledFormatChange (IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate);
	void CalculateSamplesPerFrame (UInt32 sampleRate, UInt16 * averageFrameSize, UInt16 * additionalSampleFrameFreq);
	#if DEBUGLATENCY
	virtual UInt64 getQueuedFrameForSample (UInt32 sampleFrame);
	#endif
	virtual	void takeTimeStamp (bool incrementLoopCount = true, AbsoluteTime *timestamp = NULL);
	#if PRIMEISOCINPUT
	virtual	void primeInputPipe (IOUSBPipe * pipeToPrime, UInt32 bytesPerUSBFrame);
	#endif
	virtual AbsoluteTime generateTimeStamp (UInt32 usbFrameIndex, UInt32 preWrapBytes, UInt32 byteCount);
	virtual IOReturn copyAnchor (UInt64 * anchorFrame, AbsoluteTime * anchorTime); 
	
	// for UHCI
	virtual IOReturn eraseOutputSamples(const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream);

	// for IODMACommand
	virtual IOBufferMemoryDescriptor * allocateBufferDescriptor (IOOptionBits options, vm_size_t capacity, vm_offset_t alignment = 1);

};

#endif /* _APPLEUSBAUDIOENGINE_H */
