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