1/*
2 * Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include "IOAudioDebug.h"
24#include "IOAudioDevice.h"
25#include "IOAudioEngine.h"
26#include "IOAudioPort.h"
27#include "IOAudioTypes.h"
28#include "IOAudioDefines.h"
29#include "IOAudioLevelControl.h"
30#include "IOAudioToggleControl.h"
31#include "AudioTracepoints.h"
32
33#include <IOKit/IOWorkLoop.h>
34#include <IOKit/IOCommandGate.h>
35#include <IOKit/IOTimerEventSource.h>
36#include <IOKit/IOKitKeys.h>
37#include <libkern/c++/OSDictionary.h>
38#include <libkern/c++/OSSet.h>
39#include <libkern/c++/OSCollectionIterator.h>
40
41#include <sys/sysctl.h>
42
43#define NUM_POWER_STATES	2
44
45class IOAudioTimerEvent : public OSObject
46{
47    friend class IOAudioDevice;
48
49    OSDeclareDefaultStructors(IOAudioTimerEvent)
50
51protected:
52    OSObject *	target;
53    IOAudioDevice::TimerEvent event;
54    AbsoluteTime interval;
55};
56
57OSDefineMetaClassAndStructors(IOAudioTimerEvent, OSObject)
58
59class IOAudioEngineEntry : public OSObject
60{
61    friend class IOAudioDevice;
62
63    OSDeclareDefaultStructors(IOAudioEngineEntry);
64
65protected:
66    IOAudioEngine *audioEngine;
67    bool shouldStopAudioEngine;
68};
69
70OSDefineMetaClassAndStructors(IOAudioEngineEntry, OSObject)
71
72#define super IOService
73OSDefineMetaClassAndStructors(IOAudioDevice, IOService)
74OSMetaClassDefineReservedUsed(IOAudioDevice, 0);
75OSMetaClassDefineReservedUsed(IOAudioDevice, 1);
76OSMetaClassDefineReservedUsed(IOAudioDevice, 2);
77OSMetaClassDefineReservedUsed(IOAudioDevice, 3);
78OSMetaClassDefineReservedUsed(IOAudioDevice, 4);
79OSMetaClassDefineReservedUsed(IOAudioDevice, 5);
80
81OSMetaClassDefineReservedUnused(IOAudioDevice, 6);
82OSMetaClassDefineReservedUnused(IOAudioDevice, 7);
83OSMetaClassDefineReservedUnused(IOAudioDevice, 8);
84OSMetaClassDefineReservedUnused(IOAudioDevice, 9);
85OSMetaClassDefineReservedUnused(IOAudioDevice, 10);
86OSMetaClassDefineReservedUnused(IOAudioDevice, 11);
87OSMetaClassDefineReservedUnused(IOAudioDevice, 12);
88OSMetaClassDefineReservedUnused(IOAudioDevice, 13);
89OSMetaClassDefineReservedUnused(IOAudioDevice, 14);
90OSMetaClassDefineReservedUnused(IOAudioDevice, 15);
91OSMetaClassDefineReservedUnused(IOAudioDevice, 16);
92OSMetaClassDefineReservedUnused(IOAudioDevice, 17);
93OSMetaClassDefineReservedUnused(IOAudioDevice, 18);
94OSMetaClassDefineReservedUnused(IOAudioDevice, 19);
95OSMetaClassDefineReservedUnused(IOAudioDevice, 20);
96OSMetaClassDefineReservedUnused(IOAudioDevice, 21);
97OSMetaClassDefineReservedUnused(IOAudioDevice, 22);
98OSMetaClassDefineReservedUnused(IOAudioDevice, 23);
99OSMetaClassDefineReservedUnused(IOAudioDevice, 24);
100OSMetaClassDefineReservedUnused(IOAudioDevice, 25);
101OSMetaClassDefineReservedUnused(IOAudioDevice, 26);
102OSMetaClassDefineReservedUnused(IOAudioDevice, 27);
103OSMetaClassDefineReservedUnused(IOAudioDevice, 28);
104OSMetaClassDefineReservedUnused(IOAudioDevice, 29);
105OSMetaClassDefineReservedUnused(IOAudioDevice, 30);
106OSMetaClassDefineReservedUnused(IOAudioDevice, 31);
107
108// New code added here
109
110//================================================================================================
111//
112//	Start Tracepoint Setup
113//
114//================================================================================================
115class AudioGlobals
116{
117public:
118    AudioGlobals(void);                             // Constructor
119    virtual ~AudioGlobals(void);					// Destructor
120};
121
122static int				AudioSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req );
123static AudioGlobals		gAudioStackGlobals;						// needs to be declared early to register tracepoints via sysctl
124UInt32					gAudioStackDebugFlags = 0;				// extern-ed in IOAudioDebug.h
125
126SYSCTL_PROC ( _debug, OID_AUTO, Audio, CTLFLAG_RW, 0, 0, AudioSysctl, "Audio", "Audio debug interface" );
127
128static int AudioSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req )
129{
130    int                 error = 0;
131    AudioSysctlArgs     audioArgs;
132
133    DEBUG_UNUSED ( oidp );
134    DEBUG_UNUSED ( arg1 );
135    DEBUG_UNUSED ( arg2 );
136
137    //IOLog( "USBSysctl: gUSBStackDebugFlags = 0x%08X\n", ( unsigned int ) gUSBStackDebugFlags );
138
139    error = SYSCTL_IN ( req, &audioArgs, sizeof ( audioArgs ) );
140    if ( ( error == 0 ) && ( audioArgs.type == kAudioTypeDebug ) )
141    {
142        if ( audioArgs.operation == kAudioOperationGetFlags )
143        {
144            audioArgs.debugFlags = gAudioStackDebugFlags;
145            error = SYSCTL_OUT ( req, &audioArgs, sizeof ( audioArgs ) );
146        }
147
148        else if ( audioArgs.operation == kAudioOperationSetFlags )
149        {
150            gAudioStackDebugFlags = audioArgs.debugFlags;
151        }
152    }
153
154    IOLog("AudioSysctl: (%d)\n", gAudioStackDebugFlags);
155    return error;
156}
157
158
159
160AudioGlobals::AudioGlobals ( void )
161{
162    int debugFlags;
163
164    if ( PE_parse_boot_argn ( "audio", &debugFlags, sizeof ( debugFlags ) ) )
165    {
166        gAudioStackDebugFlags = debugFlags;
167    }
168
169    // Register our sysctl interface
170    sysctl_register_oid ( &sysctl__debug_Audio );
171
172}
173
174
175
176AudioGlobals::~AudioGlobals ( void )
177{
178    // Unregister our sysctl interface
179    sysctl_unregister_oid ( &sysctl__debug_Audio );
180
181}
182
183
184
185void IOAudioDevice::setDeviceModelName(const char *modelName)
186{
187    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setDeviceModelName(%p)\n", this, modelName);
188
189    if (modelName) {
190        setProperty(kIOAudioDeviceModelIDKey, modelName);
191    }
192    audioDebugIOLog(3, "- IOAudioDevice[%p]::setDeviceModelName(%p)\n", this, modelName);
193}
194
195void IOAudioDevice::setDeviceTransportType(const UInt32 transportType)
196{
197    if (transportType) {
198        setProperty(kIOAudioDeviceTransportTypeKey, transportType, 32);
199    }
200}
201
202// This needs to be overridden by driver if it wants to know about power manager changes.
203// If overridden, be sure to still call super::setAggressiveness() so we can call our parent.
204IOReturn IOAudioDevice::setAggressiveness(unsigned long type, unsigned long newLevel)
205{
206	return super::setAggressiveness(type, newLevel);
207}
208
209// This was modified for <rdar://problem/3942297>
210void IOAudioDevice::setIdleAudioSleepTime(unsigned long long sleepDelay)
211{
212	assert(reserved);
213
214	audioDebugIOLog(3, "+ IOAudioDevice[%p]::setIdleAudioSleepTime: sleepDelay = %lx%lx\n", this, (long unsigned int)(sleepDelay >> 32), (long unsigned int)sleepDelay);
215
216	if ( reserved->idleTimer ) {
217		reserved->idleTimer->cancelTimeout();
218	}
219
220	if (reserved->idleSleepDelayTime != sleepDelay) { 	// <rdar://problem/6601320>
221		reserved->idleSleepDelayTime = sleepDelay;
222	}
223
224	if ( kNoIdleAudioPowerDown != sleepDelay ) {
225		scheduleIdleAudioSleep();
226	}
227	audioDebugIOLog(3, "- IOAudioDevice[%p]::setIdleAudioSleepTime: sleepDelay = %lx%lx\n", this, (long unsigned int)(sleepDelay >> 32), (long unsigned int)sleepDelay);
228}
229
230// Set up a timer to power down the hardware if we haven't used it in a while.
231//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
232//	the indentifier post processing tool can properly insert scope when post processing a log file
233//	obtained via fwkpfv.
234
235void IOAudioDevice::scheduleIdleAudioSleep(void)
236{
237    AbsoluteTime				fireTime;
238    UInt64						nanos;
239	bool						exit = false;
240
241	assert(reserved);
242
243	audioDebugIOLog(3, "+ IOAudioDevice[%p]::scheduleIdleAudioSleep: idleSleepDelayTime = %lx%lx\n", this, (long unsigned int)(reserved->idleSleepDelayTime >> 32), (long unsigned int)reserved->idleSleepDelayTime);
244	if ( 0 == reserved->idleSleepDelayTime )
245	{
246		// For backwards compatibility, or drivers that don't care, tell them about idle right away.
247		initiatePowerStateChange ();
248	}
249	else
250	{
251		if ( !reserved->idleTimer && ( kNoIdleAudioPowerDown != reserved->idleSleepDelayTime ) )
252		{
253			reserved->idleTimer = IOTimerEventSource::timerEventSource ( this, idleAudioSleepHandlerTimer );
254			if ( !reserved->idleTimer )
255			{
256				exit = true;
257			}
258			else
259			{
260				workLoop->addEventSource ( reserved->idleTimer );
261			}
262		}
263
264		if ( !exit && ( kNoIdleAudioPowerDown != reserved->idleSleepDelayTime ) )
265		{
266			// If the driver wants to know about idle sleep after a specific amount of time, then set the timer to tell them at that time.
267			// If idleSleepDelayTime == 0xffffffff then don't ever tell the driver about going idle
268			clock_get_uptime ( &fireTime );
269			absolutetime_to_nanoseconds ( fireTime, &nanos );
270			nanos += reserved->idleSleepDelayTime;
271			nanoseconds_to_absolutetime ( nanos, &fireTime );
272			reserved->idleTimer->wakeAtTime ( fireTime );		// will call idleAudioSleepHandlerTimer
273		}
274	}
275
276	audioDebugIOLog(3, "- IOAudioDevice[%p]::scheduleIdleAudioSleep: idleSleepDelayTime = %lx%lx\n", this, (long unsigned int)(reserved->idleSleepDelayTime >> 32), (long unsigned int)reserved->idleSleepDelayTime);
277	return;
278}
279
280void IOAudioDevice::idleAudioSleepHandlerTimer(OSObject *owner, IOTimerEventSource *sender)
281{
282	IOAudioDevice *				audioDevice;
283
284	audioDevice = OSDynamicCast(IOAudioDevice, owner);
285	assert(audioDevice);
286
287	audioDebugIOLog(3, "+ IOAudioDevice[%p]idleAudioSleepHandlerTimer: pendingPowerState = %d, idleSleepDelayTime = %lx%lx\n", audioDevice, audioDevice->pendingPowerState, (long unsigned int)(audioDevice->reserved->idleSleepDelayTime >> 32), (long unsigned int)audioDevice->reserved->idleSleepDelayTime);
288	if (audioDevice->reserved->idleSleepDelayTime != kNoIdleAudioPowerDown &&
289		audioDevice->getPendingPowerState () == kIOAudioDeviceIdle) {
290		// If we're still idle, tell the device to go idle now that the requested amount of time has elapsed.
291		audioDevice->initiatePowerStateChange();
292	}
293
294	audioDebugIOLog(3, "- IOAudioDevice[%p]idleAudioSleepHandlerTimer: pendingPowerState = %d, idleSleepDelayTime = %lx%lx\n", audioDevice, audioDevice->pendingPowerState, (long unsigned int)(audioDevice->reserved->idleSleepDelayTime >> 32), (long unsigned int)audioDevice->reserved->idleSleepDelayTime);
295	return;
296}
297
298void IOAudioDevice::setConfigurationApplicationBundle(const char *bundleID)
299{
300    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setConfigurationApplicationBundle(%p)\n", this, bundleID);
301
302    if (bundleID) {
303        setProperty(kIOAudioDeviceConfigurationAppKey, bundleID);
304    }
305    audioDebugIOLog(3, "- IOAudioDevice[%p]::setConfigurationApplicationBundle(%p)\n", this, bundleID);
306}
307
308// OSMetaClassDefineReservedUsed(IOAudioDevice, 4);
309void IOAudioDevice::setDeviceCanBeDefault(UInt32 defaultsFlags)
310{
311	setProperty(kIOAudioDeviceCanBeDefaults, defaultsFlags, sizeof(UInt32) * 8);
312}
313
314//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
315//	the indentifier post processing tool can properly insert scope when post processing a log file
316//	obtained via fwkpfv.
317
318bool IOAudioDevice::init(OSDictionary *properties)
319{
320	bool			result = false;
321
322    audioDebugIOLog(3, "+ IOAudioDevice[%p]::init(%p)\n", this, properties);
323
324	if ( super::init ( properties ) )
325	{
326		reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
327		if ( 0 != reserved )
328		{
329			reserved->idleSleepDelayTime = 0;
330			reserved->idleTimer = NULL;
331
332			audioEngines = OSArray::withCapacity ( 2 );
333			if ( 0 != audioEngines )
334			{
335				audioPorts = OSSet::withCapacity ( 1 );
336				if ( 0 != audioPorts )
337				{
338					workLoop = IOWorkLoop::workLoop ();
339					if ( 0 != workLoop )
340					{
341						familyManagePower = true;
342						asyncPowerStateChangeInProgress = false;
343
344						currentPowerState = kIOAudioDeviceIdle;
345						pendingPowerState = kIOAudioDeviceIdle;
346
347						numRunningAudioEngines = 0;
348						duringStartup = true;
349						result = true;
350					}
351				}
352			}
353		}
354	}
355
356    audioDebugIOLog(3, "- IOAudioDevice[%p]::init(%p) returns %d\n", this, properties, result);
357    return result;
358}
359
360void IOAudioDevice::free()
361{
362    audioDebugIOLog(3, "+ IOAudioDevice[%p]::free()\n", this);
363
364    if (audioEngines) {
365        deactivateAllAudioEngines();
366        audioEngines->release();
367        audioEngines = 0;
368    }
369
370	audioDebugIOLog ( 3, "  did deactiveateAllAudioEngines ()\n" );
371
372    if (audioPorts) {
373        detachAllAudioPorts();
374        audioPorts->release();
375        audioPorts = 0;
376    }
377
378	audioDebugIOLog ( 3, "  did detachAllAudioPorts ()\n" );
379
380    if (timerEvents) {
381        timerEvents->release();
382        timerEvents = 0;
383    }
384
385	audioDebugIOLog ( 3, "  did timerEvents->release ()\n" );
386
387    if (timerEventSource) {
388        if (workLoop) {
389			timerEventSource->cancelTimeout();					// <rdar://problem/7493627,8426296>
390            workLoop->removeEventSource(timerEventSource);
391        }
392
393        timerEventSource->release();
394        timerEventSource = NULL;
395    }
396
397	audioDebugIOLog ( 3, "  did workLoop->removeEventSource ( timerEventSource )\n" );
398
399	if (reserved->idleTimer) {
400		if (workLoop) {
401			reserved->idleTimer->cancelTimeout();			// <rdar://problem/7493627,8426296>
402			workLoop->removeEventSource(reserved->idleTimer);
403		}
404
405		reserved->idleTimer->release();
406		reserved->idleTimer = NULL;
407	}
408
409	audioDebugIOLog ( 3, "  did workLoop->removeEventSource ( reserved->idleTimer )\n" );
410
411    if (commandGate) {
412        if (workLoop) {
413            workLoop->removeEventSource(commandGate);
414        }
415
416        commandGate->release();
417        commandGate = NULL;
418    }
419
420	audioDebugIOLog ( 3, "  did workLoop->removeEventSource ( commandGate )\n" );
421
422    if (workLoop) {
423        workLoop->release();
424        workLoop = NULL;
425    }
426
427	audioDebugIOLog ( 3, "  did workLoop->release ()\n" );
428
429	if (reserved) {
430		IOFree (reserved, sizeof(struct ExpansionData));
431	}
432
433	audioDebugIOLog ( 3, "  did IOFree ()\n" );
434
435    super::free();
436
437    audioDebugIOLog(3, "- IOAudioDevice[%p]::free()\n", this);
438}
439
440bool IOAudioDevice::initHardware(IOService *provider)
441{
442    audioDebugIOLog(3, "+-IOAudioDevice[%p]::initHardware(%p)\n", this, provider);
443
444    return true;
445}
446
447//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
448//	the indentifier post processing tool can properly insert scope when post processing a log file
449//	obtained via fwkpfv.
450
451bool IOAudioDevice::start(IOService *provider)
452{
453	bool			result = false;
454
455    static IOPMPowerState powerStates[2] = {
456        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
457        {1, IOPMDeviceUsable, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0}
458    };
459
460    audioDebugIOLog(3, "+ IOAudioDevice[%p]::start(%p)\n", this, provider);
461    AudioTrace_Start(kAudioTIOAudioDevice, kTPIOAudioDeviceStart, (uintptr_t)this, (uintptr_t)provider, 0, 0);
462
463	if ( super::start ( provider ) )
464	{
465		if ( 0 != provider->getProperty("preserveIODeviceTree\n") )		// <rdar://3206968>
466		{
467			provider->callPlatformFunction("mac-io-publishChildren\n", 0, (void*)this, (void*)0, (void*)0, (void*)0);
468		}
469
470		assert(workLoop);
471
472		commandGate = IOCommandGate::commandGate(this);
473		if ( 0 != commandGate)
474		{
475			workLoop->addEventSource(commandGate);
476
477			setDeviceCanBeDefault (kIOAudioDeviceCanBeDefaultInput | kIOAudioDeviceCanBeDefaultOutput | kIOAudioDeviceCanBeSystemOutput);
478
479			if ( initHardware ( provider ) )
480			{
481				if ( familyManagePower ) {
482					PMinit ();
483					provider->joinPMtree ( this );
484
485					if ( NULL != pm_vars ) {
486						//	duringStartup = true;
487						registerPowerDriver ( this, powerStates, NUM_POWER_STATES );
488						changePowerStateTo ( 1 );
489						//	duringStartup = false;
490					}
491				}
492
493				registerService();
494				result = true;
495			}
496		}
497	}
498
499    audioDebugIOLog(3, "- IOAudioDevice[%p]::start(%p)\n", this, provider);
500    AudioTrace_End(kAudioTIOAudioDevice, kTPIOAudioDeviceStart, (uintptr_t)this, (uintptr_t)provider, result, 0);
501	return result;
502}
503
504void IOAudioDevice::stop(IOService *provider)
505{
506    audioDebugIOLog(3, "+ IOAudioDevice[%p]::stop(%p)\n", this, provider);
507
508    removeAllTimerEvents();					// <rdar://problem/7493627,8426296>
509
510    if (timerEventSource) {
511        if (workLoop) {
512			timerEventSource->cancelTimeout();					// <rdar://problem/7493627,8426296>
513            workLoop->removeEventSource(timerEventSource);
514        }
515
516        timerEventSource->release();
517        timerEventSource = NULL;
518    }
519
520    if (reserved->idleTimer) {
521        if (workLoop) {
522			reserved->idleTimer->cancelTimeout();				// <rdar://problem/7493627,8426296>
523            workLoop->removeEventSource(reserved->idleTimer);
524        }
525
526        reserved->idleTimer->release();
527        reserved->idleTimer = NULL;
528    }
529
530    deactivateAllAudioEngines();
531    detachAllAudioPorts();
532
533    if (familyManagePower) {
534		if (pm_vars != NULL) {
535			PMstop();
536		}
537    }
538
539    if (commandGate) {
540        if (workLoop) {
541            workLoop->removeEventSource(commandGate);
542        }
543
544        commandGate->release();
545        commandGate = NULL;
546    }
547
548    super::stop(provider);
549    audioDebugIOLog(3, "- IOAudioDevice[%p]::stop(%p)\n", this, provider);
550}
551
552bool IOAudioDevice::willTerminate(IOService *provider, IOOptionBits options)
553{
554	bool			result = false;
555
556    audioDebugIOLog(3, "+ IOAudioDevice[%p]::willTerminate(%p, %lx)\n", this, provider, (long unsigned int)options);
557
558    OSCollectionIterator *engineIterator;
559
560    engineIterator = OSCollectionIterator::withCollection(audioEngines);
561    if (engineIterator) {
562        IOAudioEngine *audioEngine;
563
564        while ( (audioEngine = OSDynamicCast(IOAudioEngine, engineIterator->getNextObject())) ) {
565            audioEngine->setState(kIOAudioEngineStopped);
566        }
567        engineIterator->release();
568    }
569
570	result = super::willTerminate(provider, options);
571    audioDebugIOLog(3, "- IOAudioDevice[%p]::willTerminate(%p, %lx) returns %d\n", this, provider, (long unsigned int)options, result );
572	return result;
573}
574
575void IOAudioDevice::setFamilyManagePower(bool manage)
576{
577    familyManagePower = manage;
578}
579
580IOReturn IOAudioDevice::setPowerState(unsigned long powerStateOrdinal, IOService *device)
581{
582    IOReturn result = IOPMAckImplied;
583
584    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setPowerState(%lu, %p)\n", this, powerStateOrdinal, device);
585    if (!duringStartup)
586	{
587        if (powerStateOrdinal >= NUM_POWER_STATES)
588		{
589            result = IOPMNoSuchState;
590        } else
591		{
592			if (workLoop) {																					//	<rdar://8508064>
593				workLoop->runAction(_setPowerStateAction, this, (void *)powerStateOrdinal, (void *)device);	//	<rdar://8508064>
594			}
595        }
596    }
597	duringStartup = false;
598    audioDebugIOLog(3, "- IOAudioDevice[%p]::setPowerState(%lu, %p) returns 0x%lX\n", this, powerStateOrdinal, device, (long unsigned int)result );
599	return result;
600}
601
602// <rdar://8508064>
603IOReturn IOAudioDevice::_setPowerStateAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
604{
605    IOReturn result = IOPMAckImplied;
606
607    if (target) {
608        IOAudioDevice *audioDevice = OSDynamicCast(IOAudioDevice, target);
609        if (audioDevice) {
610            IOCommandGate *cg;
611
612            cg = audioDevice->getCommandGate();
613
614            if (cg) {
615                result = cg->runAction(setPowerStateAction, arg0, arg1, arg2, arg3);
616            }
617        }
618    }
619
620    return result;
621}
622
623IOReturn IOAudioDevice::setPowerStateAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
624{
625    IOReturn result = IOPMAckImplied;
626
627    if (owner) {
628        IOAudioDevice *audioDevice = OSDynamicCast(IOAudioDevice, owner);
629
630        if (audioDevice) {
631            result = audioDevice->protectedSetPowerState((unsigned long)arg1, (IOService *)arg2);
632        }
633    }
634
635    return result;
636}
637
638IOReturn IOAudioDevice::protectedSetPowerState(unsigned long powerStateOrdinal, IOService *device)
639{
640    IOReturn result = IOPMAckImplied;
641
642    audioDebugIOLog(3, "+ IOAudioDevice[%p]::protectedSetPowerState(%lu, %p)\n", this, powerStateOrdinal, device);
643
644    if (asyncPowerStateChangeInProgress) {
645        waitForPendingPowerStateChange();
646    }
647
648    if (powerStateOrdinal == 0) {	// Sleep
649        if (getPowerState() != kIOAudioDeviceSleep) {
650            pendingPowerState = kIOAudioDeviceSleep;
651
652            // Stop all audio engines
653            if (audioEngines && (numRunningAudioEngines > 0)) {
654                OSCollectionIterator *audioEngineIterator;
655
656                audioEngineIterator = OSCollectionIterator::withCollection(audioEngines);
657
658                if (audioEngineIterator) {
659                    IOAudioEngine *audioEngine;
660
661                    while ( (audioEngine = (IOAudioEngine *)audioEngineIterator->getNextObject()) ) {
662                        if (audioEngine->getState() == kIOAudioEngineRunning) {
663                            audioEngine->pauseAudioEngine();
664                        }
665                    }
666
667                    audioEngineIterator->release();
668                }
669            }
670        }
671    } else if (powerStateOrdinal == 1) {	// Wake
672        if (getPowerState() == kIOAudioDeviceSleep) {	// Need to change state if sleeping
673            if (numRunningAudioEngines == 0) {
674                pendingPowerState = kIOAudioDeviceIdle;
675            } else {
676                pendingPowerState = kIOAudioDeviceActive;
677            }
678        }
679    }
680
681    if (currentPowerState != pendingPowerState) {
682        UInt32 microsecondsUntilComplete = 0;
683
684        result = initiatePowerStateChange(&microsecondsUntilComplete);
685        if (result == kIOReturnSuccess) {
686            result = microsecondsUntilComplete;
687        }
688    }
689
690    audioDebugIOLog(3, "- IOAudioDevice[%p]::protectedSetPowerState(%lu, %p) returns 0x%lX\n", this, powerStateOrdinal, device, (long unsigned int)result );
691    return result;
692}
693
694void IOAudioDevice::waitForPendingPowerStateChange()
695{
696    audioDebugIOLog(3, "+ IOAudioDevice[%p]::waitForPendingPowerStateChange()\n", this);
697
698    if (asyncPowerStateChangeInProgress) {
699        IOCommandGate *cg;
700
701        cg = getCommandGate();
702
703        if (cg) {
704            cg->commandSleep((void *)&asyncPowerStateChangeInProgress);
705            assert(!asyncPowerStateChangeInProgress);
706        } else {
707            IOLog("IOAudioDevice[%p]::waitForPendingPowerStateChange() - internal error - unable to get the command gate.\n", this);
708        }
709    }
710    audioDebugIOLog(3, "- IOAudioDevice[%p]::waitForPendingPowerStateChange()\n", this);
711	return;
712}
713
714IOReturn IOAudioDevice::initiatePowerStateChange(UInt32 *microsecondsUntilComplete)
715{
716    IOReturn result = kIOReturnSuccess;
717
718    audioDebugIOLog(3, "+ IOAudioDevice[%p]::initiatePowerStateChange(%p) - current = %d - pending = %d\n", this, microsecondsUntilComplete, currentPowerState, pendingPowerState);
719
720    if (currentPowerState != pendingPowerState) {
721        UInt32 localMicsUntilComplete, *micsUntilComplete = NULL;
722
723        if (microsecondsUntilComplete != NULL) {
724            micsUntilComplete = microsecondsUntilComplete;
725        } else {
726            micsUntilComplete = &localMicsUntilComplete;
727        }
728
729        *micsUntilComplete = 0;
730
731        asyncPowerStateChangeInProgress = true;
732
733        result = performPowerStateChange(currentPowerState, pendingPowerState, micsUntilComplete);
734
735        if (result == kIOReturnSuccess) {
736            if (*micsUntilComplete == 0) {
737                asyncPowerStateChangeInProgress = false;
738                protectedCompletePowerStateChange();
739            }
740        } else if ( result == IOPMWillAckLater ) {
741            asyncPowerStateChangeInProgress = true;
742        }
743        else
744        {
745            asyncPowerStateChangeInProgress = false;
746        }
747    }
748
749    audioDebugIOLog(3, "- IOAudioDevice[%p]::initiatePowerStateChange(%p) - current = %d - pending = %d returns 0x%lX\n", this, microsecondsUntilComplete, currentPowerState, pendingPowerState, (long unsigned int)result );
750    return result;
751}
752
753IOReturn IOAudioDevice::completePowerStateChange()
754{
755    IOReturn result = kIOReturnError;
756    IOCommandGate *cg;
757
758    cg = getCommandGate();
759
760    if (cg) {
761        result = cg->runAction(completePowerStateChangeAction);
762    }
763
764    return result;
765}
766
767IOReturn IOAudioDevice::completePowerStateChangeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
768{
769    IOReturn result = kIOReturnBadArgument;
770
771    if (owner) {
772        IOAudioDevice *audioDevice = OSDynamicCast(IOAudioDevice, owner);
773
774        if (audioDevice) {
775            result = audioDevice->protectedCompletePowerStateChange();
776        }
777    }
778
779    return result;
780}
781
782IOReturn IOAudioDevice::protectedCompletePowerStateChange()
783{
784    IOReturn result = kIOReturnSuccess;
785
786    audioDebugIOLog(3, "+ IOAudioDevice[%p]::protectedCompletePowerStateChange() - current = %d - pending = %d\n", this, currentPowerState, pendingPowerState);
787
788    if (currentPowerState != pendingPowerState) {
789		IOCommandGate *cg;
790
791		cg = getCommandGate();
792        // If we're waking, we fire off the timers and resync them
793        // Then restart the audio engines that were running before the sleep
794        if (currentPowerState == kIOAudioDeviceSleep) {
795            clock_get_uptime(&previousTimerFire);
796            SUB_ABSOLUTETIME(&previousTimerFire, &minimumInterval);
797
798            if (timerEvents && (timerEvents->getCount() > 0)) {
799                dispatchTimerEvents(true);
800            }
801
802            if (audioEngines && (numRunningAudioEngines > 0)) {
803                OSCollectionIterator *audioEngineIterator;
804
805                audioEngineIterator = OSCollectionIterator::withCollection(audioEngines);
806
807                if (audioEngineIterator) {
808                    IOAudioEngine *audioEngine;
809
810                    while ( (audioEngine = (IOAudioEngine *)audioEngineIterator->getNextObject()) ) {
811                        if (audioEngine->getState() == kIOAudioEnginePaused) {
812                            audioEngine->resumeAudioEngine();
813                        }
814                    }
815
816                    audioEngineIterator->release();
817                }
818            }
819        }
820
821        if (asyncPowerStateChangeInProgress) {
822            acknowledgeSetPowerState();
823            asyncPowerStateChangeInProgress = false;
824
825            if (cg) {
826                cg->commandWakeup((void *)&asyncPowerStateChangeInProgress);
827            }
828        }
829
830        currentPowerState = pendingPowerState;
831
832		if (cg) {
833			cg->commandWakeup(&currentPowerState);
834		}
835    }
836
837    audioDebugIOLog(3, "- IOAudioDevice[%p]::protectedCompletePowerStateChange() - current = %d - pending = %d returns 0x%lX\n", this, currentPowerState, pendingPowerState, (long unsigned int)result );
838    return result;
839}
840
841IOReturn IOAudioDevice::performPowerStateChange(IOAudioDevicePowerState oldPowerState,
842                                                IOAudioDevicePowerState newPowerState,
843                                                UInt32 *microsecondsUntilComplete)
844{
845    return kIOReturnSuccess;
846}
847
848IOAudioDevicePowerState IOAudioDevice::getPowerState()
849{
850    return currentPowerState;
851}
852
853IOAudioDevicePowerState IOAudioDevice::getPendingPowerState()
854{
855    return pendingPowerState;
856}
857
858void IOAudioDevice::audioEngineStarting()
859{
860    audioDebugIOLog(3, "+ IOAudioDevice[%p]::audioEngineStarting() - numRunningAudioEngines = %ld\n", this, (long int)( numRunningAudioEngines + 1 ) );
861
862    numRunningAudioEngines++;
863
864    if (numRunningAudioEngines == 1) {	// First audio engine starting - need to be in active state
865        if (getPowerState() == kIOAudioDeviceIdle) {	// Go active
866            if (asyncPowerStateChangeInProgress) {	// Sleep if there is a transition in progress
867                waitForPendingPowerStateChange();
868            }
869
870            pendingPowerState = kIOAudioDeviceActive;
871
872            initiatePowerStateChange();
873
874            if (asyncPowerStateChangeInProgress) {	// Sleep if there is a transition in progress
875                waitForPendingPowerStateChange();
876            }
877        } else if (getPendingPowerState () != kIOAudioDeviceSleep) {
878			// Make sure that when the idle timer fires that we won't go to sleep.
879            pendingPowerState = kIOAudioDeviceActive;
880		}
881    }
882    audioDebugIOLog(3, "- IOAudioDevice[%p]::audioEngineStarting() - numRunningAudioEngines = %ld\n", this, (long int)( numRunningAudioEngines + 1 ) );
883}
884
885void IOAudioDevice::audioEngineStopped()
886{
887    audioDebugIOLog(3, "+ IOAudioDevice[%p]::audioEngineStopped() - numRunningAudioEngines = %ld\n", this, (long int)( numRunningAudioEngines - 1 ) );
888
889	if ( numRunningAudioEngines > 0 ) {
890	    numRunningAudioEngines--;
891	}
892
893    if (numRunningAudioEngines == 0) {	// Last audio engine stopping - need to be idle
894        if (getPowerState() == kIOAudioDeviceActive) {	// Go idle
895			if (asyncPowerStateChangeInProgress) {	// Sleep if there is a transition in progress
896				waitForPendingPowerStateChange();
897			}
898
899			pendingPowerState = kIOAudioDeviceIdle;
900
901			scheduleIdleAudioSleep();
902        }
903    }
904    audioDebugIOLog(3, "- IOAudioDevice[%p]::audioEngineStopped() - numRunningAudioEngines = %ld\n", this, (long int)( numRunningAudioEngines - 1 ) );
905}
906
907IOWorkLoop *IOAudioDevice::getWorkLoop() const
908{
909    return workLoop;
910}
911
912IOCommandGate *IOAudioDevice::getCommandGate() const
913{
914    return commandGate;
915}
916
917void IOAudioDevice::setDeviceName(const char *deviceName)
918{
919    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setDeviceName(%p)\n", this, deviceName);
920
921    if (deviceName) {
922        setProperty(kIOAudioDeviceNameKey, deviceName);
923		if (NULL == getProperty (kIOAudioDeviceModelIDKey)) {
924			int			stringLen, tempLength;
925			char *		string;
926
927			stringLen = 1;
928			stringLen += strlen (deviceName) + 1;
929			stringLen += strlen (getName ());
930			string = (char *)IOMalloc (stringLen);
931			if ( string )									// we should not panic for this
932			{
933				strncpy (string, getName (), stringLen);
934				tempLength = strlen (".");					//	<rdar://problem/6411827>
935				strncat (string, ":", tempLength);
936				tempLength = strlen (deviceName);			//	<rdar://problem/6411827>
937				strncat (string, deviceName, tempLength);
938				setDeviceModelName (string);
939				IOFree (string, stringLen);
940			}
941		}
942    }
943    audioDebugIOLog(3, "- IOAudioDevice[%p]::setDeviceName(%p)\n", this, deviceName);
944}
945
946void IOAudioDevice::setDeviceShortName(const char *shortName)
947{
948    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setDeviceShortName(%p)\n", this, shortName);
949
950    if (shortName) {
951        setProperty(kIOAudioDeviceShortNameKey, shortName);
952    }
953    audioDebugIOLog(3, "- IOAudioDevice[%p]::setDeviceShortName(%p)\n", this, shortName);
954}
955
956void IOAudioDevice::setManufacturerName(const char *manufacturerName)
957{
958    audioDebugIOLog(3, "+ IOAudioDevice[%p]::setManufacturerName(%p)\n", this, manufacturerName);
959
960    if (manufacturerName) {
961        setProperty(kIOAudioDeviceManufacturerNameKey, manufacturerName);
962    }
963    audioDebugIOLog(3, "- IOAudioDevice[%p]::setManufacturerName(%p)\n", this, manufacturerName);
964}
965
966IOReturn IOAudioDevice::activateAudioEngine(IOAudioEngine *audioEngine)
967{
968    return activateAudioEngine(audioEngine, true);
969}
970
971//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
972//	the indentifier post processing tool can properly insert scope when post processing a log file
973//	obtained via fwkpfv.
974
975IOReturn IOAudioDevice::activateAudioEngine(IOAudioEngine *audioEngine, bool shouldStartAudioEngine)
976{
977	IOReturn			result = kIOReturnBadArgument;
978
979	audioDebugIOLog(3, "+ IOAudioDevice[%p]::activateAudioEngine(%p, %d)\n", this, audioEngine, shouldStartAudioEngine);
980
981	if ( audioEngine && audioEngines )
982	{
983		if ( !audioEngine->attach ( this ) )
984		{
985			result = kIOReturnError;
986		}
987		else
988		{
989			if ( shouldStartAudioEngine )
990			{
991				if (!audioEngine->start ( this ) )
992				{
993					audioEngine->detach ( this );
994					result =  kIOReturnError;
995				}
996				else
997				{
998					result =  kIOReturnSuccess;
999				}
1000			}
1001			else // <rdar://8681286>
1002			{
1003				result =  kIOReturnSuccess;
1004			}
1005
1006			if ( kIOReturnSuccess == result ) // <rdar://8681286>
1007			{
1008				audioEngine->deviceStartedAudioEngine = shouldStartAudioEngine;
1009
1010				audioEngines->setObject ( audioEngine );
1011				audioEngine->setIndex ( audioEngines->getCount() - 1 );
1012
1013				audioEngine->registerService ();
1014			}
1015		}
1016	}
1017
1018	audioDebugIOLog(3, "- IOAudioDevice[%p]::activateAudioEngine(%p, %d) returns 0x%lX\n", this, audioEngine, shouldStartAudioEngine, (long unsigned int)result );
1019	return result;
1020}
1021
1022//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
1023//	the indentifier post processing tool can properly insert scope when post processing a log file
1024//	obtained via fwkpfv.
1025
1026void IOAudioDevice::deactivateAllAudioEngines()
1027{
1028    OSCollectionIterator *engineIterator;
1029
1030    audioDebugIOLog(3, "+ IOAudioDevice[%p]::deactivateAllAudioEngines()\n", this);
1031
1032    if ( audioEngines )
1033	{
1034		engineIterator = OSCollectionIterator::withCollection ( audioEngines );
1035		if ( engineIterator )
1036		{
1037			IOAudioEngine *audioEngine;
1038
1039			while ( (audioEngine = OSDynamicCast ( IOAudioEngine, engineIterator->getNextObject ()) ) )
1040			{
1041				audioEngine->stopAudioEngine ();
1042				if ( !isInactive () )
1043				{
1044					audioEngine->terminate ();
1045				}
1046			}
1047			engineIterator->release ();
1048		}
1049
1050		audioEngines->flushCollection ();
1051    }
1052
1053    audioDebugIOLog(3, "- IOAudioDevice[%p]::deactivateAllAudioEngines()\n", this);
1054	return;
1055}
1056
1057IOReturn IOAudioDevice::attachAudioPort(IOAudioPort *port, IORegistryEntry *parent, IORegistryEntry *child)
1058{
1059    return kIOReturnSuccess;
1060}
1061
1062void IOAudioDevice::detachAllAudioPorts()
1063{
1064}
1065
1066void IOAudioDevice::flushAudioControls()
1067{
1068    audioDebugIOLog(3, "+ IOAudioDevice[%p]::flushAudioControls()\n", this);
1069
1070    if (audioPorts) {
1071        OSCollectionIterator *portIterator;
1072
1073        portIterator = OSCollectionIterator::withCollection(audioPorts);
1074        if (portIterator) {
1075            IOAudioPort *audioPort;
1076
1077            while ( (audioPort = (IOAudioPort *)portIterator->getNextObject()) ) {
1078                if (OSDynamicCast(IOAudioPort, audioPort)) {
1079                    if (audioPort->audioControls) {
1080                        OSCollectionIterator *controlIterator;
1081
1082                        controlIterator = OSCollectionIterator::withCollection(audioPort->audioControls);
1083
1084                        if (controlIterator) {
1085                            IOAudioControl *audioControl;
1086
1087                            while ( (audioControl = (IOAudioControl *)controlIterator->getNextObject()) ) {
1088                                audioControl->flushValue();
1089                            }
1090                            controlIterator->release();
1091                        }
1092                    }
1093                }
1094            }
1095            portIterator->release();
1096        }
1097    }
1098
1099    // This code will flush controls attached to an IOAudioPort and a default on a audio engine
1100    // more than once
1101    // We need to update this to create a single master list of controls and use that to flush
1102    // each only once
1103    if (audioEngines) {
1104        OSCollectionIterator *audioEngineIterator;
1105
1106        audioEngineIterator = OSCollectionIterator::withCollection(audioEngines);
1107        if (audioEngineIterator) {
1108            IOAudioEngine *audioEngine;
1109
1110            while ( (audioEngine = (IOAudioEngine *)audioEngineIterator->getNextObject()) ) {
1111                if (audioEngine->defaultAudioControls) {
1112                    OSCollectionIterator *controlIterator;
1113
1114                    controlIterator = OSCollectionIterator::withCollection(audioEngine->defaultAudioControls);
1115                    if (controlIterator) {
1116                        IOAudioControl *audioControl;
1117
1118                        while ( (audioControl = (IOAudioControl *)controlIterator->getNextObject()) ) {
1119                            audioControl->flushValue();
1120                        }
1121                        controlIterator->release();
1122                    }
1123                }
1124            }
1125
1126            audioEngineIterator->release();
1127        }
1128    }
1129    audioDebugIOLog(3, "- IOAudioDevice[%p]::flushAudioControls()\n", this);
1130}
1131
1132//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
1133//	the indentifier post processing tool can properly insert scope when post processing a log file
1134//	obtained via fwkpfv.
1135
1136IOReturn IOAudioDevice::addTimerEvent(OSObject *target, TimerEvent event, AbsoluteTime interval)
1137{
1138    IOReturn			result = kIOReturnSuccess;
1139    IOAudioTimerEvent *	newEvent;
1140
1141#ifdef DEBUG
1142    UInt64 newInt;
1143    absolutetime_to_nanoseconds(interval, &newInt);
1144    audioDebugIOLog(3, "+ IOAudioDevice::addTimerEvent(%p, %p, %lums)\n", target, event, (long unsigned int)(newInt/1000000));
1145#endif
1146
1147    if ( !event )
1148	{
1149        result = kIOReturnBadArgument;
1150    }
1151	else
1152	{
1153		newEvent = new IOAudioTimerEvent;
1154		newEvent->target = target;
1155		newEvent->event = event;
1156		newEvent->interval = interval;
1157
1158		if (!timerEvents) {
1159			IOWorkLoop *wl;
1160
1161			timerEvents = OSDictionary::withObjects((const OSObject **)&newEvent, (const OSSymbol **)&target, 1, 1);
1162
1163			timerEventSource = IOTimerEventSource::timerEventSource(this, timerFired);
1164			wl = getWorkLoop();
1165			if ( !timerEventSource || !wl || ( kIOReturnSuccess != wl->addEventSource ( timerEventSource ) ) )
1166			{
1167				result = kIOReturnError;
1168			}
1169			else
1170			{
1171				timerEventSource->enable ();
1172			}
1173		}
1174		else
1175		{
1176			timerEvents->setObject((OSSymbol *)target, newEvent);
1177		}
1178
1179		if ( kIOReturnSuccess == result )
1180		{
1181			newEvent->release();
1182
1183			assert(timerEvents);
1184
1185			if (timerEvents->getCount() == 1) {
1186				AbsoluteTime nextTimerFire;
1187
1188				minimumInterval = interval;
1189
1190				assert(timerEventSource);
1191
1192				clock_get_uptime(&previousTimerFire);
1193
1194				nextTimerFire = previousTimerFire;
1195				ADD_ABSOLUTETIME(&nextTimerFire, &minimumInterval);
1196
1197				result = timerEventSource->wakeAtTime(nextTimerFire);
1198
1199#ifdef DEBUG
1200				{
1201					UInt64 nanos;
1202					absolutetime_to_nanoseconds(minimumInterval, &nanos);
1203#ifdef __LP64__
1204					audioDebugIOLog(5, "  scheduling timer to fire in %lums - previousTimerFire = {%llu}\n", (long unsigned int) (nanos / 1000000), previousTimerFire);
1205#else	/* __LP64__ */
1206					audioDebugIOLog(5, "  scheduling timer to fire in %lums - previousTimerFire = {%ld,%lu}\n", (long unsigned int) (nanos / 1000000), previousTimerFire.hi, previousTimerFire.lo);
1207#endif	/* __LP64__ */
1208				}
1209#endif
1210
1211				if (result != kIOReturnSuccess) {
1212					IOLog("IOAudioDevice::addTimerEvent() - error 0x%x setting timer wake time - timer events will be disabled.\n", result);
1213				}
1214			} else if (CMP_ABSOLUTETIME(&interval, &minimumInterval) < 0) {
1215				AbsoluteTime currentNextFire, desiredNextFire;
1216
1217				clock_get_uptime(&desiredNextFire);
1218				ADD_ABSOLUTETIME(&desiredNextFire, &interval);
1219
1220				currentNextFire = previousTimerFire;
1221				ADD_ABSOLUTETIME(&currentNextFire, &minimumInterval);
1222
1223				minimumInterval = interval;
1224
1225				if (CMP_ABSOLUTETIME(&desiredNextFire, &currentNextFire) < 0) {
1226					assert(timerEventSource);
1227
1228#ifdef DEBUG
1229					{
1230						UInt64 nanos;
1231						absolutetime_to_nanoseconds(interval, &nanos);
1232#ifdef __LP64__
1233						audioDebugIOLog(5, "  scheduling timer to fire in %lums at {%llu} - previousTimerFire = {%llu}\n", (long unsigned int) (nanos / 1000000), desiredNextFire, previousTimerFire);
1234#else	/* __LP64__ */
1235						audioDebugIOLog(5, "  scheduling timer to fire in %lums at {%ld,%lu} - previousTimerFire = {%ld,%lu}\n", (long unsigned int) (nanos / 1000000), desiredNextFire.hi, desiredNextFire.lo, previousTimerFire.hi, previousTimerFire.lo);
1236#endif	/* __LP64__ */
1237					}
1238#endif
1239
1240					result = timerEventSource->wakeAtTime(desiredNextFire);
1241					if (result != kIOReturnSuccess) {
1242						IOLog("IOAudioDevice::addTimerEvent() - error 0x%x setting timer wake time - timer events will be disabled.\n", result);
1243					}
1244				}
1245			}
1246		}
1247	}
1248
1249#ifdef DEBUG
1250    audioDebugIOLog(3, "- IOAudioDevice::addTimerEvent(%p, %p, %lums) returns 0x%lX\n", target, event, (long unsigned int)(newInt/1000000), (long unsigned int)result );
1251#endif
1252    return result;
1253}
1254
1255//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
1256//	the indentifier post processing tool can properly insert scope when post processing a log file
1257//	obtained via fwkpfv.
1258
1259void IOAudioDevice::removeTimerEvent(OSObject *target)
1260{
1261    IOAudioTimerEvent *removedTimerEvent;
1262
1263    audioDebugIOLog(3, "+ IOAudioDevice::removeTimerEvent(%p)\n", target);
1264
1265	if ( timerEvents )
1266	{
1267		removedTimerEvent = (IOAudioTimerEvent *)timerEvents->getObject((const OSSymbol *)target);
1268		if (removedTimerEvent) {
1269			removedTimerEvent->retain();
1270			timerEvents->removeObject((const OSSymbol *)target);
1271			if (timerEvents->getCount() == 0) {
1272				assert(timerEventSource);
1273				timerEventSource->cancelTimeout();
1274			} else if (CMP_ABSOLUTETIME(&removedTimerEvent->interval, &minimumInterval) <= 0) { // Need to find a new minimum interval
1275				OSCollectionIterator *iterator;
1276				IOAudioTimerEvent *timerEvent;
1277				AbsoluteTime nextTimerFire;
1278				OSSymbol *obj;
1279
1280				iterator = OSCollectionIterator::withCollection(timerEvents);
1281
1282				if (iterator) {
1283					obj = (OSSymbol *)iterator->getNextObject();
1284					timerEvent = (IOAudioTimerEvent *)timerEvents->getObject(obj);
1285
1286					if (timerEvent) {
1287						minimumInterval = timerEvent->interval;
1288
1289						while ((obj = (OSSymbol *)iterator->getNextObject()) && (timerEvent = (IOAudioTimerEvent *)timerEvents->getObject(obj))) {
1290							if (CMP_ABSOLUTETIME(&timerEvent->interval, &minimumInterval) < 0) {
1291								minimumInterval = timerEvent->interval;
1292							}
1293						}
1294					}
1295
1296					iterator->release();
1297				}
1298
1299				assert(timerEventSource);
1300
1301				nextTimerFire = previousTimerFire;
1302				ADD_ABSOLUTETIME(&nextTimerFire, &minimumInterval);
1303
1304#ifdef DEBUG
1305				{
1306					AbsoluteTime now, then;
1307					UInt64 nanos, mi;
1308					clock_get_uptime(&now);
1309					then = nextTimerFire;
1310					absolutetime_to_nanoseconds(minimumInterval, &mi);
1311					if (CMP_ABSOLUTETIME(&then, &now)) {
1312						SUB_ABSOLUTETIME(&then, &now);
1313						absolutetime_to_nanoseconds(then, &nanos);
1314#ifdef __LP64__
1315						audioDebugIOLog(5, "IOAudioDevice::removeTimerEvent() - scheduling timer to fire in %lums at {%llu} - previousTimerFire = {%llu} - interval=%lums\n", (long unsigned int) (nanos / 1000000), nextTimerFire, previousTimerFire, (long unsigned int)(mi/1000000));
1316#else	/* __LP64__ */
1317						audioDebugIOLog(5, "IOAudioDevice::removeTimerEvent() - scheduling timer to fire in %lums at {%ld,%lu} - previousTimerFire = {%ld,%lu} - interval=%lums\n", (long unsigned int) (nanos / 1000000), nextTimerFire.hi, nextTimerFire.lo, previousTimerFire.hi, previousTimerFire.lo, (long unsigned int)(mi/1000000));
1318#endif	/* __LP64__ */
1319
1320
1321					} else {
1322						SUB_ABSOLUTETIME(&now, &then);
1323						absolutetime_to_nanoseconds(now, &nanos);
1324#ifdef __LP64__
1325						audioDebugIOLog(5, "IOAudioDevice::removeTimerEvent() - scheduling timer to fire in -%lums - previousTimerFire = {%llu}\n", (long unsigned int) (nanos / 1000000), previousTimerFire);
1326#else	/* __LP64__ */
1327						audioDebugIOLog(5, "IOAudioDevice::removeTimerEvent() - scheduling timer to fire in -%lums - previousTimerFire = {%ld,%lu}\n", (long unsigned int) (nanos / 1000000), previousTimerFire.hi, previousTimerFire.lo);
1328#endif	/* __LP64__ */
1329
1330					}
1331				}
1332#endif
1333
1334				timerEventSource->wakeAtTime(nextTimerFire);
1335			}
1336
1337			removedTimerEvent->release();
1338		}
1339	}
1340    audioDebugIOLog(3, "- IOAudioDevice::removeTimerEvent(%p)\n", target);
1341	return;
1342}
1343
1344void IOAudioDevice::removeAllTimerEvents()
1345{
1346    audioDebugIOLog(3, "+ IOAudioDevice[%p]::removeAllTimerEvents()\n", this);
1347
1348    if (timerEventSource) {
1349        timerEventSource->cancelTimeout();
1350    }
1351
1352    if (timerEvents) {
1353        timerEvents->flushCollection();
1354    }
1355    audioDebugIOLog(3, "- IOAudioDevice[%p]::removeAllTimerEvents()\n", this);
1356}
1357
1358void IOAudioDevice::timerFired(OSObject *target, IOTimerEventSource *sender)
1359{
1360    if (target) {
1361        IOAudioDevice *audioDevice = OSDynamicCast(IOAudioDevice, target);
1362
1363        if (audioDevice) {
1364            audioDevice->dispatchTimerEvents(false);
1365        }
1366    }
1367}
1368
1369void IOAudioDevice::dispatchTimerEvents(bool force)
1370{
1371	audioDebugIOLog(5, "+ IOAudioDevice::dispatchTimerEvents( %d )\n", force );
1372
1373    if (timerEvents) {
1374#ifdef DEBUG
1375        AbsoluteTime now, delta;
1376        UInt64 nanos;
1377
1378        clock_get_uptime(&now);
1379        delta = now;
1380        SUB_ABSOLUTETIME(&delta, &previousTimerFire);
1381        absolutetime_to_nanoseconds(delta, &nanos);
1382#ifdef __LP64__
1383        audioDebugIOLog(5, "  woke up %lums after last fire - now = {%llu} - previousFire = {%llu}\n", (long unsigned int)(nanos / 1000000), now, previousTimerFire);
1384#else	/* __LP64__ */
1385		audioDebugIOLog(5, "  woke up %lums after last fire - now = {%ld,%lu} - previousFire = {%ld,%lu}\n", (UInt32)(nanos / 1000000), now.hi, now.lo, previousTimerFire.hi, previousTimerFire.lo);
1386#endif	/* __LP64__ */
1387#endif	/* DEBUG */
1388
1389        if (force || (getPowerState() != kIOAudioDeviceSleep)) {
1390            OSIterator *iterator;
1391            OSSymbol *target;
1392            AbsoluteTime nextTimerFire, currentInterval;
1393
1394            currentInterval = minimumInterval;
1395
1396            assert(timerEvents);
1397
1398            iterator = OSCollectionIterator::withCollection(timerEvents);
1399
1400            if (iterator) {
1401                while ( (target = (OSSymbol *)iterator->getNextObject()) ) {
1402                    IOAudioTimerEvent *timerEvent;
1403                    timerEvent = (IOAudioTimerEvent *)timerEvents->getObject(target);
1404
1405                    if (timerEvent) {
1406                        (*timerEvent->event)(timerEvent->target, this);
1407                    }
1408                }
1409
1410                iterator->release();
1411            }
1412
1413            if (timerEvents->getCount() > 0) {
1414                ADD_ABSOLUTETIME(&previousTimerFire, &currentInterval);
1415                nextTimerFire = previousTimerFire;
1416                ADD_ABSOLUTETIME(&nextTimerFire, &minimumInterval);
1417
1418                assert(timerEventSource);
1419
1420#ifdef DEBUG
1421                {
1422                    AbsoluteTime later;
1423                    UInt64 mi;
1424                    later = nextTimerFire;
1425                    absolutetime_to_nanoseconds(minimumInterval, &mi);
1426                    if (CMP_ABSOLUTETIME(&later, &now)) {
1427                        SUB_ABSOLUTETIME(&later, &now);
1428                        absolutetime_to_nanoseconds(later, &nanos);
1429#ifdef __LP64__
1430						audioDebugIOLog(5, "  scheduling timer to fire in %lums at {%llu} - previousTimerFire = {%llu} - interval=%lums\n", (long unsigned int) (nanos / 1000000), nextTimerFire, previousTimerFire, (long unsigned int)(mi/1000000));
1431#else	/* __LP64__ */
1432						audioDebugIOLog(5, "  scheduling timer to fire in %lums at {%ld,%lu} - previousTimerFire = {%ld,%lu} - interval=%lums\n", (UInt32) (nanos / 1000000), nextTimerFire.hi, nextTimerFire.lo, previousTimerFire.hi, previousTimerFire.lo, (UInt32)(mi/1000000));
1433#endif	/* __LP64__*/
1434                    }
1435					else
1436					{
1437                        SUB_ABSOLUTETIME(&now, &later);
1438                        absolutetime_to_nanoseconds(now, &nanos);
1439#ifdef __LP64__
1440                        audioDebugIOLog(5, "  scheduling timer to fire in -%lums - previousTimerFire = {%llu}\n", (long unsigned int) (nanos / 1000000), previousTimerFire);
1441#else	/* __LP64__ */
1442						audioDebugIOLog(5, "  scheduling timer to fire in -%lums - previousTimerFire = {%ld,%lu}\n", (UInt32) (nanos / 1000000), previousTimerFire.hi, previousTimerFire.lo);
1443#endif	/* __LP64__*/
1444                    }
1445                }
1446#endif	/* DEBUG */
1447
1448                timerEventSource->wakeAtTime(nextTimerFire);
1449            }
1450        }
1451    }
1452	audioDebugIOLog(5, "- IOAudioDevice::dispatchTimerEvents()\n" );
1453	return;
1454}
1455
1456