/*
 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * 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@
 */

/*!
 * @header IOAudioDevice
 */

#ifndef _IOKIT_IOAUDIODEVICE_H
#define _IOKIT_IOAUDIODEVICE_H

#include <IOKit/IOService.h>

#include <IOKit/audio/IOAudioTypes.h>
#include <IOKit/audio/IOAudioStream.h>

class IOAudioEngine;
class IOAudioStream;
class IOAudioPort;
class IOAudioControl;
class OSDictionary;
class OSSet;
class OSArray;
class IOTimerEventSource;
class IOCommandGate;

/*!
 * @class IOAudioDevice
 * @abstract Abstract base class for a single piece of audio hardware.  The IOAudioDevice provides
 *  the central coordination point for an audio driver.
 * @discussion An audio driver is required to subclass IOAudioDevice in order to provide
 *  working audio to the system.  A single driver instance will contain a single instance of the 
 *  driver's IOAudioDevice subclass.  The subclass is responsible for mapping all hardware device
 *  resources from the service provider nub.  It must control access to the hardware so that the
 *  hardware doesn't get into an inconsistent state.  It is possible that different threads may make
 *  requests of the hardware at the same time.  The IOAudioDevice superclass provides an IOWorkLoop
 *  and IOCommandGate on the IOWorkLoop through which all hardware accesses may be synchronized.
 *  All entry points to all parts of the driver controlled by the IOAudioFamily will be synchronized
 *  through this one IOWorkLoop.
 *
 *  The IOAudioDevice subclass is responsible for creating the rest of the pieces of the driver.
 *  It must identify and create all IOAudioEngines that are not automatically created by the system
 *  (i.e. those that are not matched and instantiated by IOKit directly).
 *
 *  The IOAudioDevice subclass must enumerate and create all IOAudioControls to match
 *  the device capabilities.
 *
 *  It must also execute control value chages when requested by the system (i.e. volume adjustments).
 *
 *  In order to allow sleep and work to work on the system, the IOAudioDevice subclass is responsible
 *  for performing the necessary actions to sleep and wake its hardware (and restore necessary state
 *  on wake).
 *
 *  The IOAudioDevice class provides timer services that allow different elements in the audio driver
 *  to receive timer notifications as needed.  These services were designed with the idea that most
 *  timed events in a typical audio driver need to be done at least as often as a certain interval.
 *  Further, it is designed with the idea that being called more often than the specified interval
 *  doesn't hurt anything - and in fact may help.  With this in mind, the timer services provided
 *  by the IOAudioDevice class allow different targets to register for timer callbacks at least as
 *  often as the specified interval.  The actual interval will be the smallest of the intervals of
 *  all of the callbacks.  This way, we avoid the overhead of having many timers in a single audio
 *  device.  As an example, each output IOAudioEngine has a timer to run the erase head.  It doesn't hurt
 *  to have the erase head run more often.  Also, a typical IOAudioDevice subclass may need to run a timer
 *  to check for device state changes (e.g. jack insertions).
 *
 *  There are a number of strings passed from the driver to the CoreAudio.framework and then into
 *  applications.  All of those strings should be localized by the driver.  In order to do that
 *  the kext bundle should have localized string files following the Mac OS X localization 
 *  instructions.  The IOAudioDevice should contain a property with the name of the bundle/kext
 *  that contains the localized string resources.  To do that, the driver's personality in 
 *  the bundle resources could have a property named 'IOAudioDeviceLocalizedBundle' with the path 
 *  of the bundle/kext relative to '/System/Library/Extensions'.  It could also be set by the 
 *  IOAudioDevice subclass in its initHardware() function.  To do so, call
 *  setProperty(kIOAudioDeviceLocalizedBundleKey, "Driver.kext").
 *
 *  In a typical driver, the IOAudioDevice subclass will implement initHardware() to perform the
 *  hardware initialization and driver construction.  Within that initialization it must create at 
 *  least one IOAudioEngine instance and activate it.  In order to activate a new IOAudioEngine
 *  activateAudioEngine() should be called for each one.  It must create the IOAudioControls 
 *  matching the hardware capabilities to allow the system to set volume, mute and input selection.  
 *  To add those controls to the driver, each control should be attached to the IOAudioEngine to
 *  which it applies by calling addDefaultAudioControl() on the IOAudioEngine.
 *  During initialization it should also call setDeviceName(), setDeviceShortName() and 
 *  setManufacturerName() with localized strings representing each of the attributes.
 *
 *  If the driver is to work properly after sleep/wake, it must implement performPowerStateChange()
 *  and deal with the sleep and wake transitions.  It may also deal with the idle state transitions
 *  to turn off device power when it isn't in use (especially useful for devices attached to a 
 *  portable running on battery power).
 */

/*
 * enum IOAudioDevicePowerState
 * @abstract Identifies the power state of the audio device
 * @discussion A newly created IOAudioDevices defaults to the idle state.
 * @constant kIOAudioDeviceSleep State set when the system is going to sleep
 * @constant kIOAudioDeviceIdle State when the system is awake but none of the IOAudioEngines are in use
 * @constant kIOAudioDeviceActive State when one ore more IOAudioEngines are in use.  This state transition must complete before the system will begin playing audio.
 */
typedef enum _IOAudioDevicePowerState {
    kIOAudioDeviceSleep 	= 0,	// When sleeping
    kIOAudioDeviceIdle		= 1,	// When no audio engines running
    kIOAudioDeviceActive 	= 2		// audio engines running
} IOAudioDevicePowerState;

class IOAudioDevice : public IOService
{
    friend class IOAudioEngine;
    
    OSDeclareDefaultStructors(IOAudioDevice)

protected:
    /*! @var workLoop The IOWorkLoop for the driver - this is shared with the other objects in the driver */
    IOWorkLoop				*workLoop;
    /*! @var commandGate The IOCommandGate for this IOAudioDevice.  It is attached to workLoop */
    IOCommandGate			*commandGate;
    /*! @var timerEventSource An IOTimerEventSource attached to workLoop used for the timer services */
    IOTimerEventSource		*timerEventSource;

    /*! @var duringStartup State variable set to true while the driver is starting up and false all other times */
    bool			duringStartup;
    /*! @var familyManagePower Set to true if the family is supposed to manage power - this is the default state.  It can be changed early in the initialization process with a call to setFamilyManagePower(). */
    bool			familyManagePower;
    /*! @var asyncPowerStateChangeInProgress Set to true while an asynchronous power change is pending and false all other times. */
    bool			asyncPowerStateChangeInProgress;
    
    /*! @var numRunningAudioEngines The number of running IOAudioEngines.  This is used to maintain idle vs active power state. */
    UInt32			numRunningAudioEngines;
    
    /*! @var currentPowerState Used to track the existing power state - can be fetched by calling getPowerState() */
    IOAudioDevicePowerState	currentPowerState;
    /*! @var pendingPowerState If a power state change is in progress, this represents the pending power state.  All other times this is the same as the currentPowerState. */
    IOAudioDevicePowerState	pendingPowerState;

    /*! @var audioEngines The set of IOAudioEngine objects vended by the IOAudioDevice. */
    OSArray *			audioEngines;
    /*! @var timerEvents The set of timer events in use by the device.  
     *  @discussion The key for the dictionary is the target of the event.  This means that a single target may
     *   have only a single event associated with it.
     */
    OSDictionary *		timerEvents;
    /*! @var audioPorts The set of IOAudioPort objects associated with the IOAudioDevice */
    OSSet *			audioPorts;

    /*! @var minimumInterval The smallest timer interval requested by all timer event targets. */
    AbsoluteTime		minimumInterval;
    /*! @var previousTimerFire The time of the last timer event.
     *  @discussion This is used to schedule the next timer event.
     */
    AbsoluteTime		previousTimerFire;

public:
    /*! @var gIOAudioPlane A static IORegistryPlane representing the new IOAudioPlane that the IOAudioFamily uses
     *   to represent the signal chain of the device.
     */
    static const IORegistryPlane *gIOAudioPlane;

protected:
    struct ExpansionData {
		unsigned long long			idleSleepDelayTime;
		IOTimerEventSource *		idleTimer;
		IOService *					ourProvider;
	};
    
    ExpansionData *reserved;
    
public:
	static void idleAudioSleepHandlerTimer(OSObject *owner, IOTimerEventSource *sender);
	virtual IOReturn setAggressiveness(unsigned long type, unsigned long newLevel);

	virtual void setDeviceTransportType(const UInt32 transportType);

    /*!
	 * @function setIdleAudioSleepTime
     * @abstract This function is to be called by a driver that doesn't want to be told about the audio
	 * going idle immediately, but at some point in the future.
	 * @discussion This is useful if the device will want to power down its hardware into an idle sleep
	 * state, but doesn't want to do that unless audio hasn't been used for a while.  Calling this function
	 * immediately changes the idle sleep timer and queues it up if the idle is different from the previous
	 * idle time.  The idle time defaults to 0, which means be called immediately (backwards compatible with
	 * previous versions of IOAudioFamily).  A value of 0xffffffffffffffffULL means don't ever tell the
	 * driver about going idle.
     * @param sleepDelay The amount of time, in nanoseconds, before the hardware should be told to go idle.
     */
	virtual void setIdleAudioSleepTime(unsigned long long sleepDelay);
	virtual void scheduleIdleAudioSleep(void);

private:
    OSMetaClassDeclareReservedUsed(IOAudioDevice, 0);
    OSMetaClassDeclareReservedUsed(IOAudioDevice, 1);
    OSMetaClassDeclareReservedUsed(IOAudioDevice, 2);

    OSMetaClassDeclareReservedUnused(IOAudioDevice, 3);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 4);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 5);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 6);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 7);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 8);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 9);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 10);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 11);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 12);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 13);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 14);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 15);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 16);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 17);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 18);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 19);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 20);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 21);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 22);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 23);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 24);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 25);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 26);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 27);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 28);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 29);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 30);
    OSMetaClassDeclareReservedUnused(IOAudioDevice, 31);

public:
    // Initialization
    
    /*!
     * @function init
     * @abstract Initialize a newly created instance of IOAudioDevice.
     * @discussion This implementation initializes all of the data structures and variables used by the
     *  IOAudioDevice.  The currentPowerState and pendingPowerState variables are set to kIOAudioDeviceIdle.
     *  A subclass that overrides this method must call the superclass' implementation.
     * @param properties An OSDictionary of the device properties that gets passed to super::init and set
     *  in the IORegistry.
     * @result true if initialization was successful
     */
    virtual bool init(OSDictionary *properties);

    /*!
     * @function free
     * @abstract Frees resources used by the IOAudioDevice instance
     * @discussion This method will deactivate all audio audio engines and release the audioEngines OSSet.
     *  It will also deactivate all of the audio ports and release the audioPorts OSSet.  It will release
     *  the timerEvents OSDictionary as well as cancel any outstanding timer callbacks.  It will clean up
     *  all of the event sources and the workLoop.
     *
     *  Do not call this directly.  This is called automatically by the system when the instance's
     *  refcount goes to 0.  To decrement the refcount, call release() on the object.
     */
     
    virtual void free();

    /*!
     * @function start
     * @abstract This function is called automatically by the system to tell the driver to start vending
     *  services to the rest of the system.
     * @discussion The start() implementation in IOAudioDevice starts by calling start() on its superclass.
     *  It then calls initHardware() which the subclass should override to properly initialize itself and 
     *  the hardware.  If that call succeeds, it sets up power management if the family is supposed to 
     *  manage power (checking the familyManagePower variable).  Then finally it calls registerService() 
     *  to make the IOAudioDevice visible in the IORegistry.
     * @param provider This is the service provider nub that provides access to the hardware resources.
     * @result Returns true on success
     */
    virtual bool start(IOService *provider);

    /*!
     * @function stop
     * @abstract This is responsible for stopping the device after the system is done with it (or
        if the device is removed from the system).
     * @discussion The IOAudioDevice implentation of stop() disables the timer services, deactivates 
     *  all of the audio audio engines and audio ports and stops power management of the device.
     *  The audio engine and port deactivation causes all of the audio engines to get stopped and 
     *  all of the audio engine and port resources and objects to be released.  A subclass' implementation 
     *  may could shut down hardware here if necessary.  If this function is overridden by a subclass,
     *  the superclass' implementation must be called.
     * @param The service provider nub for the device.
     */
    virtual void stop(IOService *provider);

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

    /*!
     * @function initHardware
     * @abstract This function is called by start() to provide a convenient place for the subclass to 
     *  perform its initialization.
     * @discussion In a typical implementation, a driver would implementation this function and perform
     *  a number of tasks.  Those include mapping hardware resources, initializing the hardware to a known
     *  state, creating the IOAudioEngines, IOAudioControls and IOAudioStreams.  Additionally it 
     *  should also call setDeviceName(), setDeviceShortName(), setManufacturerName().  Upon return of
     *  this function, the device should be ready to begin vending services to the system.
     * @param provider The service provider nub for the device.
     * @result This function should return true on a successful initialization.
     */
    virtual bool initHardware(IOService *provider);
    
    /*!
     * @function setDeviceName
     * @abstract Sets the name of the device
     * @discussion This method should be called during initialization or startup.  It should
     *  be set by the time initHardware() completes.  The device name is used by the 
     *  CoreAudio.framework to identify the particular piece of hardware.  This string should
     *  should be localized by the driver.
     */
    virtual void setDeviceName(const char *deviceName);
    
    /*!
     * @function setDeviceShortName
     * @abstract Sets the short name of the device
     * @discussion The short name is a shorter representation of the device name.  It may be used
     *  by applications when the device name is too long.  It should be set by the time initHardware()
     *  completes.  The string should be localized by the driver.
     */
    virtual void setDeviceShortName(const char *shortName);

    /*!
     * @function setManufacturerName
     * @abstract Sets the manufacturer name of the device
     * @discussion This method should be called during initialization or startup.  This should be 
     *  called by the time initHardware() completes.  The string should be localized by the driver.
     */
    virtual void setManufacturerName(const char *manufacturerName);

    
    // IOWorkLoop, IOCommandGate management
    
    /*!
     * @function getWorkLoop
     * @abstract Returns the IOWorkLoop for the driver
     * @discussion The IOWorkLoop is used to synchronized all critical aspects of the driver.  This
     *  includes all entry points to the driver as well as power management.
     */
    virtual IOWorkLoop *getWorkLoop() const;
    
    /*!
     * @function getCommandGate
     * @abstract Returns the IOCommandGate for this IOAudioDevice
     * @discussion This IOCommandGate allows calls into this IOAudioDevice to be synchronized on 
     *  the IOWorkLoop.
     */
    virtual IOCommandGate *getCommandGate() const;

    
    // IOAudioEngine management
    
    /*!
     * @function activateAudioEngine
     * @abstract This simply calls activateAudioEngine(IOAudioEngine *audioEngine, 
     *  bool shouldStartAudioEngine) with a value of true for shouldStartAudioEngine.
     * @param audioEngine The IOAudioEngine instance to be activated.  It is treated as a newly 
     *  allocated instance.
     * @result Returns true if the audio engine was successfully activated.
     */
    virtual IOReturn activateAudioEngine(IOAudioEngine *audioEngine);

    /*!
     * @function activateAudioEngine
     * @abstract This is called to add a new IOAudioEngine object to the IOAudioDevice.
     * @discussion Once the IOAudioEngine has been activated by this function, it is ready
     *  to begin moving audio data.  This should be called either during the subclass' initHardware()
     *  implementation for each IOAudioEngine the device creates.  Or it should be called by
     *  the IOAudioEngine itself if the audio engine was automatically created by IOKit's matching
     *  process.  The system won't be able to properly track and control IOAudioEngines if
     *  they are not activated though this function.
     *  This implementation will retain the IOAudioEngine while it maintains control of it.  
     *  When the audio engine is deactivated, the IOAudioEngine will be released.  If the 
     *  IOAudioDevice subclass is passing a newly instantiated IOAudioEngine, it will need to release 
     *  the audio engine after it has been activated.  This will insure that the refCount on the audio engine 
     *  is correct when it gets deactivated when the driver is stopped.  That allows the audio engine to be
     *  freed when it is no longer needed.
     * @param audioEngine The IOAudioEngine instance to be activated.
     * @param shouldStartAudioEngine If true, the audio engine is treated as a newly allocated IOAudioEngine
     *  instance and is appropriately attached and started according to IOKit convention.  If it is false
     *  it is assumed that some other process (possibly the IOKit matching process) has started the
     *  IOAudioEngine and will skip that step.
     * @result Returns true if the audio engine was successfully activated.
     */
    virtual IOReturn activateAudioEngine(IOAudioEngine *audioEngine, bool shouldStartAudioEngine);

    /*!
     * @function deactivateAllAudioEngines
     * @abstract Deactivates all of the audio engines in the device.
     * @discussion This is called by the stop() and free() methods in IOAudioDevice to completely
     *  shut down all audio engines as the driver is being shut down.
     */
    virtual void deactivateAllAudioEngines();

    
    // Power management
    
    /*!
     * @function setFamilyManagePower
     * @abstract Called set whether or not the family should manage the device power throught the
     *  IOService power management APIs.
     * @discussion The default behavior is for the family to manage power.  It is only necessary to 
     *  call this function if the driver does not want the family to manage power.  It is not
     *  recommended that this function be called because it makes power management much more
     *  difficult for the driver.  If this function is to be called, it must be called before
     *  initHardware() completes.  Immediately after initHardware() is called by start(), 
     *  the power management system is initialized if the family is to manage power.
     * @param manage Set to false if it is not desired that the family does the power management
     */
    virtual void setFamilyManagePower(bool manage);
    
    /*!
     * @function setPowerState
     * @abstract Called by the power management system in IOService when the power state of this 
     *  service needs to change.
     * @discussion The default implementation of IOAudioDevice sets up two power states for IOService
     *  to use.  State 0 is sleep and state 1 is wake.  This function should not be called directly.
     *  It is only supposed to be used by the IOService power management services.
     * @param powerStateOrdinal The number of the power state as defined by the IOAudioDevice - 
     *  0 for sleep, 1 for wake.
     * @param device The power management policy maker.
     * @result Returns kIOPMAckImplied (0) when the power state change is complete.  Otherwise the an
     *  upper bound on the number of microseconds until the state change is complete is returned.
     */
    virtual IOReturn setPowerState(unsigned long powerStateOrdinal, IOService *device);
    
    /*!
     * @function setPowerStateAction
     * @abstract IOCommandGate Action which calls protectedSetPowerState() while holding the IOCommandGate
     * @discussion This is needed to allow protectedSetPowerState() to be called on the IOWorkLoop
     * @param owner The owner of the IOCommandGate (the IOAudioDevice in this case)
     * @param arg1 The powerStateOrdinal to be passed to protectedSetPowerState()
     * @param arg2 The device to be passed to protectedSetPowerState()
     * @result Returns the result of protectedSetPowerState()
     */
    static IOReturn setPowerStateAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
    
    /*!
     * @function protectedSetPowerState
     * @abstract Called by setPowerStateAction() to deal with a power state change from the IOService
     *  power management facility.
     * @discussion This function is responsible for performing the necessary sleep and wake tasks
     *  when the system is sleeping or waking.  If an outstanding power state change is in progress,
     *  it will wait until the state changes has completed.  While sleeping, all audio engines are
     *  stopped before calling initiatePowerStateChange() to call performPowerStateChange() to let
     *  the driver deal with the sleep request.  When waking, it determines if the device should be
     *  idle or active and continues to call initiatePowerStateChange().  If initiatePowerStateChange()
     *  indicates that the power state change is occuring asynchronously, it returns the number of
     *  microseconds.  This function must be called on the IOWorkLoop, but should not be called
     *  directly.
     * @param powerStateOrdinal Param passed to setPowerState() - 0 for sleep, 1 for wake
     * @param device Param passed to setPowerState - the device initiating the power state change
     * @result Returns 0 if the power state change is complete - the number of microseconds until 
     *  complete if its asynchronous.
     */
    virtual IOReturn protectedSetPowerState(unsigned long powerStateOrdinal, IOService *device);
    
    /*!
     * @function performPowerStateChange
     * @abstract This function is called by the IOAudioDevice when a power state change is needed.
     * @discussion In order to deal with power state changes, a subclass must override this function.
     *  Any combination of old and new power states may be passed to this function.  If work is to
     *  be performed while transitioning to sleep, check for a newPowerState of kIOAudioDeviceSleep.
     *  If work is to be performed while transitioning from sleep, check for an oldPowerState of
     *  kIOAudioDeviceSleep.  A power state of kIOAudioDeviceIdle means the system is awake, but
     *  no clients are currently playing or recording audio (i.e. no IOAudioEngines are active).
     *  A power state of kIOAudioDeviceActive means that at least one IOAudioEngine is active.
     *  It is possible for a power state change to be performed synchronously or asynchronously.
     *  In the case of a synchronous power state change, simple leave microsecondsUntilComplete
     *  alone and return kIOReturnSuccess.  If an asynchronous power state change is needed the 
     *  driver should do whatever needed to schedule another thread to finish the state change
     *  and set the microsecondsUntilComplete to an upper bound on the amount of time it will
     *  take to complete the power state change.  Then when the power state change is complete,
     *  a call must be made to completePowerStateChange().  During an asynchronous power state
     *  change, the current power state will remain the same as before the transition began, 
     *  and the pendingPowerState is set to the new power state that will be set when the 
     *  change is complete.
     * @param oldPowerState The power state before the power state change
     * @param newPowerState The power state being transitioned to
     * @param microsecondsUntilComplete A pointer to a value representing an upper bound on
     *  the number of microseconds to complete an asynchronous power state change.  It points
     *  to a value of zero at the start and if it remains zero, the state change is complete
     *  upon a successful return from the function.
     * @result Returns kIOReturnSuccess on a successful completion
     */
    virtual IOReturn performPowerStateChange(IOAudioDevicePowerState oldPowerState,
                                                IOAudioDevicePowerState newPowerState,
                                                UInt32 *microsecondsUntilComplete);
                                                    
    /*!
     * @function completePowerStateChange
     * @abstract Called when a power state change is complete
     * @discussion In the case of an asynchronous power state change, a subclass is responsible
     *  for calling this function.  It is safe to call this function if not on the IOWorkLoop.
     *  This function calls protectedCompletePowerStateChange() through the IOCommandGate and
     *  completePowerStateChangeAction().  If the call is already on the IOWorkLoop, it is safe
     *  to call protectedCompletePowerStateChange() directly.
     * @result Returns kIOReturnSuccess on a successful completion
     */
    virtual IOReturn completePowerStateChange();
    
    /*!
     * @function completePowerStateChangeAction
     * @abstract IOCommandGate Action which calls protectedCompletePowerStateChange() while holding the
     *  IOCommandGate.
     * @discussion This is needed to allow protectedCompletePowerStateChange() to be called on the IOWorkLoop.
     * @param owner The owner of the IOCommandGate (the IOAudioDevice in this case)
     * @result Returns the result of protectedCompletePowerStateChange()
     */
    static IOReturn completePowerStateChangeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4);
    
    /*!
     * @function protectedCompletePowerStateChange()
     * @abstract Called on the IOWorkLoop when a power state change is complete.
     * @discussion This function does the work to complete a power state change (both synchronous and
     *  asynchronous).  If the system is waking from sleep, the timer system is restarted and the 
     *  audio engines are resumed.  If this was called as a result of an asynchronous power state changed
     *  it makes the IOService power management call acknowledgePowerChange() and resets the
     *  asyncPowerStateChangeInProgress variable.  Finally it sets the currentPowerState to the
     *  pendingPowerState.  This function must be called on the IOWorkLoop.  If a subclass is not
     *  on the IOWorkLoop (e.g. holding the IOCommandGate), call completePowerStateChange() instead.
     * @result Returns kIOReturnSuccess on success
     */
    virtual IOReturn protectedCompletePowerStateChange();

    /*!
     * @function getPowerState
     * @abstract Returns the current power state (the old power state if a change is in progress).
     * @result The current power state
     */
    virtual IOAudioDevicePowerState getPowerState();
    
    /*!
     * @function getPendingPowerState
     * @abstract Returns the pending power state if a state change is in progress.  Otherwise it 
     *  returns the current power state change.
     * @result The pending power state
     */
    virtual IOAudioDevicePowerState getPendingPowerState();
    
    /*!
     * @function waitForPendingPowerStateChange
     * @abstract Called internally to wait until a pending power state change is complete.
     * @discussion This is only used by internal functions to wait during pending power
     *  state changes.  It is used to prevent multiple power state changes at the same time.
     *  This function must be called while holding the IOCommandGate.  If an asynchronous 
     *  power state change is in progress this function will block until the state change
     *  if complete.  Once complete, it will return while still holding the IOCommandGate.
     */
    virtual void waitForPendingPowerStateChange();
    
    /*!
     * @function initiatePowerStateChange
     * @abstract Called internally to execute a power state change
     * @discussion This function must be called on the IOWorkLoop.  It calls performPowerStateChange()
     *  to let the driver process the state change.  If the state change is completed synchronously
     *  by the driver (subclass) it calls protectedCompletePowerStateChange().  If done asynchronously
     *  it returns the microsecondsUntilComplete that was set by performPowerStateChange().  This
     *  function should not be called directly.
     * @param microsecondsUntilComplete Pointer to the microsecondsUntilComplete that should be set
     *  by performPowerStateChange if an asynchronous power state change was started.
     * @result Returns kIOReturnSuccess on success
     */
    virtual IOReturn initiatePowerStateChange(UInt32 *microsecondsUntilComplete = NULL);
    

    // IOAudioControl management
    
    /*!
     * @function flushAudioControls
     * @abstract Forces each IOAudioControl in the driver to have its value flushed out to the hardware.
     *  That will cause either the IOAudioControl's ValueChangeHandler to be called.
     * @discussion This can be used to force the hardware to get updated with the current value 
     *  of each control.  It may be useful during wake for example.
     */
    virtual void flushAudioControls();


    // Timer services
    
    /*!
     * @typedef TimerEvent
     * @abstract Generic timer event callback for IOAudioDevice timer targets
     * @discussion TimerEvent callback function takes two arguments; the target of
     *  the timer event and the IOAudioDevice sending the event.
     * @param target The target of the timer event - passed in when the timer event was registered
     * @param audioDevice The IOAudioDevice sending the event
     */
    typedef void (*TimerEvent)(OSObject *target, IOAudioDevice *audioDevice);

    /*!
     * @function addTimerEvent
     * @abstract Adds a TimerEvent callback for the given target called at least as often
     *  as specified in interval.
     * @discussion The frequency of the timer event callbacks will be the smallest interval
     *  specified by all targets.  Only one interval and callback may be specified per target.
     *  If a addTimerEvent is called twice with the same target, the second one overrides the
     *  first.  There is currently a bug triggered if the first call had the smallest interval.
     *  In that case, that smallest interval would still be used.
     * @param target This parameter is the target object of the TimerEvent.
     * @param event The callback function called each time the timer fires.
     * @param interval The callback will be called at least this often.
     * @result Returns kIOReturnSuccess if the timer event was successfully added.
     */
    virtual IOReturn addTimerEvent(OSObject *target, TimerEvent event, AbsoluteTime interval);

    /*!
     * @function removeTimerEvent
     * @abstract Removes the timer event for the given target.
     * @discussion If the interval for the target to be removed is the smallest interval,
     *  the timer interval is recalculated based on the remaining targets.  The next fire
     *  time is readjusted based on the new interval compared to the last fire time.
     * @param target The target whose timer event will be removed.
     */
    virtual void removeTimerEvent(OSObject *target);
    
    /*!
     * @function removeAllTimerEvents
     * @abstract Removes all timer events and stops the timer
     * @discussion Called during teardown of the driver
     */    
    virtual void removeAllTimerEvents();

    
    // IOAudioPort management

    /*!
     * @function attachAudioPort
     * @abstract Adds the port to the IOAudioDevice's list of ports and attaches the port to its parent
     *  and attaches the child to the port.
     * @discussion This function provides the functionality to represent the device's signal chain in the
     *  IOAudioPlane in the IORegistry.  An IOAudioPort's parent(s) are before it in the signal chain
     *  and its children are after it.  This method may be called multiple times for a single IOAudioPort.
     *  This is necessary when there are many children or parents.  Once a relationship is made, it is not
     *  necessary to make the reverse relationship.  A NULL value may be passed in for either the parent
     *  or child or both.
     *  The IOAudioPort passed in should be a newly allocated IOAudioPort instance.  This function will
     *  appropriately attach and start the port object.  NOTE: It is not necessary to use IOAudioPorts
     *  in a fully functional audio driver.
     * @param port The newly created IOAudioPort instance to be activated.
     * @param parent A parent IOAudioPort or IOAudioEngine of the given port.
     * @param child A child IOAudioPort or IOAudioEngine of the given port.
     * @result Returns true when the port has been successfully added and attached.
     */
    virtual IOReturn attachAudioPort(IOAudioPort *port, IORegistryEntry *parent, IORegistryEntry *child);

    /*!
     * @function detachAllAudioPorts
     * @abstract Deactivates all of the ports in the device.
     * @discussion This is called by the stop() and free() methods in IOAudioDevice to completely
     *  shut down all ports as the driver is being shut down.
     */
    virtual void detachAllAudioPorts();

protected:
    /*!
     * @function timerFired
     * @abstract Internal static function called when the timer fires.
     * @discussion This function simply calls dispatchTimerEvents() on the IOAudioDevice to do just that.
     * @param target The IOAudioDevice instance that initiated the timer callback.
     * @param sender The IOTimerEventSources calling this callback
     */
    static void timerFired(OSObject *target, IOTimerEventSource *sender);

    /*!
     * @function dispatchTimerEvents
     * @abstract Called by timerFired() to cause the timer event callbacks to be called.
     * @discussion This method iterates through all of the timer event targets and calls
     *  the callback on each.  Unless the force flag is set to true, the timer events will
     *  only be dispatched if the power state is not kIOAudioDeviceSleep.  This prevents
     *  unexpected timer firings while making wake->sleep->wake transitions.  This function must
     *  be called on the IOWorkLoop.
     * @function force A bool param to allow the timer events to be dispatched even if the 
     *  device is in the kIOAudioDeviceSleep power state.
     */
    virtual void dispatchTimerEvents(bool force);

    /*!
     * @function audioEngineStarting
     * @abstract Called by IOAudioEngine when it is starting up
     * @discussion This should only be called while on the IOWorkLoop.  It is not intended to be called
     *  directly.  It is called when an IOAudioEngine is starting up to allow the IOAudioDevice
     *  to keep track of running audio engines and change the power state from kIOAudioDeviceIdle to
     *  kIOAudioDeviceActive when the first audio engine starts up.  If the state change is done
     *  asynchronously, it waits for the state change to complete.  This is to ensure that the
     *  system doesn't start playing audio until the IOAudioDevice has completed its transition
     *  to kIOAudioDeviceActive.
     */
    virtual void audioEngineStarting();
    
    /*!
     * @function audioEngineStopped
     * @abstract Called by IOAudioEngine when it has stopped
     * @discussion This should only be called while on the IOWorkLoop.  It is not intended to be called
     *  directly.  It is called when an IOAudioEngine has stopped to allow the IOAudioDevice
     *  to keep track of running audio engines and change the power state from kIOAudioDeviceActive
     *  to kIOAudioDeviceIdle when the last audio engine stops.  If the state change is done 
     *  asynchronously, it waits for the state change to complete.
     */
    virtual void audioEngineStopped();
    
};

#endif /* _IOKIT_IOAUDIODEVICE_H */
