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 "IOAudioControl.h"
25#include "IOAudioControlUserClient.h"
26#include "IOAudioTypes.h"
27#include "IOAudioDefines.h"
28
29#include <IOKit/IOLib.h>
30#include <IOKit/IOWorkLoop.h>
31#include <IOKit/IOCommandGate.h>
32
33// <rdar://8518215>
34enum
35{
36	kCommandGateStatus_Normal				= 0,
37	kCommandGateStatus_RemovalPending,
38	kCommandGateStatus_Invalid
39};
40
41#define super IOService
42
43OSDefineMetaClassAndStructors(IOAudioControl, IOService)
44OSMetaClassDefineReservedUsed(IOAudioControl, 0);
45OSMetaClassDefineReservedUsed(IOAudioControl, 1);
46OSMetaClassDefineReservedUsed(IOAudioControl, 2);
47OSMetaClassDefineReservedUsed(IOAudioControl, 3);
48
49OSMetaClassDefineReservedUnused(IOAudioControl, 4);
50OSMetaClassDefineReservedUnused(IOAudioControl, 5);
51OSMetaClassDefineReservedUnused(IOAudioControl, 6);
52OSMetaClassDefineReservedUnused(IOAudioControl, 7);
53OSMetaClassDefineReservedUnused(IOAudioControl, 8);
54OSMetaClassDefineReservedUnused(IOAudioControl, 9);
55OSMetaClassDefineReservedUnused(IOAudioControl, 10);
56OSMetaClassDefineReservedUnused(IOAudioControl, 11);
57OSMetaClassDefineReservedUnused(IOAudioControl, 12);
58OSMetaClassDefineReservedUnused(IOAudioControl, 13);
59OSMetaClassDefineReservedUnused(IOAudioControl, 14);
60OSMetaClassDefineReservedUnused(IOAudioControl, 15);
61OSMetaClassDefineReservedUnused(IOAudioControl, 16);
62OSMetaClassDefineReservedUnused(IOAudioControl, 17);
63OSMetaClassDefineReservedUnused(IOAudioControl, 18);
64OSMetaClassDefineReservedUnused(IOAudioControl, 19);
65OSMetaClassDefineReservedUnused(IOAudioControl, 20);
66OSMetaClassDefineReservedUnused(IOAudioControl, 21);
67OSMetaClassDefineReservedUnused(IOAudioControl, 22);
68OSMetaClassDefineReservedUnused(IOAudioControl, 23);
69
70// New code
71
72// OSMetaClassDefineReservedUsed(IOAudioControl, 3);
73IOReturn IOAudioControl::createUserClient(task_t task, void *securityID, UInt32 type, IOAudioControlUserClient **newUserClient, OSDictionary *properties)
74{
75    IOReturn result = kIOReturnSuccess;
76    IOAudioControlUserClient *userClient;
77
78    userClient = IOAudioControlUserClient::withAudioControl(this, task, securityID, type, properties);
79
80    if (userClient) {
81        *newUserClient = userClient;
82    } else {
83        result = kIOReturnNoMemory;
84    }
85
86    return result;
87}
88
89void IOAudioControl::sendChangeNotification(UInt32 notificationType)
90{
91    OSCollectionIterator *iterator;
92    IOAudioControlUserClient *client;
93
94    if (!userClients || !isStarted) {
95        return;
96    }
97
98	// If we're doing a config change, just queue the notification for later.
99	if (reserved->providerEngine->configurationChangeInProgress) {
100		OSNumber *notificationNumber;
101		UInt32		i, count;
102		bool		dupe = FALSE;
103
104		if (!reserved->notificationQueue) {
105			reserved->notificationQueue = OSArray::withCapacity (1);
106			if (!reserved->notificationQueue) {
107				return;
108			}
109		}
110
111		notificationNumber = OSNumber::withNumber (notificationType, sizeof (notificationType) * 8);
112		if (!notificationNumber)
113			return;
114
115		// Check to see if this is a unique notification, there is no need to send dupes.
116		count = reserved->notificationQueue->getCount ();
117		for (i = 0; i < count; i++) {
118			if (notificationNumber->isEqualTo ((OSNumber *)reserved->notificationQueue->getObject (i))) {
119				dupe = TRUE;
120				break;		// no need to send duplicate notifications
121			}
122		}
123		if (!dupe) {
124			reserved->notificationQueue->setObject (notificationNumber);
125		}
126		notificationNumber->release ();
127	} else {
128		iterator = OSCollectionIterator::withCollection(userClients);
129		if (iterator) {
130			while ( (client = (IOAudioControlUserClient *)iterator->getNextObject()) ) {
131				client->sendChangeNotification(notificationType);
132			}
133
134			iterator->release();
135		}
136	}
137}
138
139void IOAudioControl::sendQueuedNotifications(void)
140{
141	UInt32				i;
142	UInt32				count;
143
144	// Send our the queued notications and release the queue.
145	if (reserved && reserved->notificationQueue) {
146		count = reserved->notificationQueue->getCount ();
147		for (i = 0; i < count; i++) {
148			if (!isInactive()) {		// <radr://9320521,9040208>
149				sendChangeNotification(((OSNumber *)reserved->notificationQueue->getObject(i))->unsigned32BitValue());
150			}
151		}
152		reserved->notificationQueue->release();
153		reserved->notificationQueue = NULL;
154	}
155}
156
157// Original code here...
158IOAudioControl *IOAudioControl::withAttributes(UInt32 type,
159                                               OSObject *initialValue,
160                                               UInt32 channelID,
161                                               const char *channelName,
162                                               UInt32 cntrlID,
163                                               UInt32 subType,
164                                               UInt32 usage)
165{
166    IOAudioControl *control;
167
168    control = new IOAudioControl;
169
170    if (control) {
171        if (!control->init(type, initialValue, channelID, channelName, cntrlID, subType, usage)) {
172            control->release();
173            control = 0;
174        }
175    }
176
177    return control;
178}
179
180bool IOAudioControl::init(UInt32 type,
181                          OSObject *initialValue,
182                          UInt32 newChannelID,
183                          const char *channelName,
184                          UInt32 cntrlID,
185                          UInt32 subType,
186                          UInt32 usage,
187                          OSDictionary *properties)
188{
189    if (!super::init(properties)) {
190        return false;
191    }
192
193    if (initialValue == NULL) {
194        return false;
195    }
196
197    if (type == 0) {
198        return false;
199    }
200
201    setType(type);
202
203    setChannelID(newChannelID);
204    setControlID(cntrlID);
205
206	setSubType(subType);
207
208    if (channelName) {
209        setChannelName(channelName);
210    }
211
212    if (usage != 0) {
213        setUsage(usage);
214    }
215
216    _setValue(initialValue);
217
218    userClients = OSSet::withCapacity(1);
219    if (!userClients) {
220        return false;
221    }
222
223	reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
224	if (!reserved) {
225		return false;
226	}
227
228	reserved->providerEngine = NULL;
229	reserved->notificationQueue = NULL;
230	reserved->commandGateStatus = kCommandGateStatus_Normal;	// <rdar://8518215>
231	reserved->commandGateUsage = 0;								// <rdar://8518215>
232    isStarted = false;
233
234    return true;
235}
236
237void IOAudioControl::setType(UInt32 type)
238{
239    this->type = type;
240    setProperty(kIOAudioControlTypeKey, type, sizeof(UInt32)*8);
241}
242
243void IOAudioControl::setSubType(UInt32 subType)
244{
245    this->subType = subType;
246    setProperty(kIOAudioControlSubTypeKey, subType, sizeof(UInt32)*8);
247}
248
249void IOAudioControl::setChannelName(const char *channelName)
250{
251    setProperty(kIOAudioControlChannelNameKey, channelName);
252}
253
254void IOAudioControl::setUsage(UInt32 usage)
255{
256    this->usage = usage;
257    setProperty(kIOAudioControlUsageKey, usage, sizeof(UInt32)*8);
258}
259
260void IOAudioControl::setCoreAudioPropertyID(UInt32 propertyID)
261{
262    setProperty(kIOAudioControlCoreAudioPropertyIDKey, propertyID, sizeof(UInt32)*8);
263    setUsage(kIOAudioControlUsageCoreAudioProperty);
264}
265
266void IOAudioControl::setReadOnlyFlag()
267{
268    setProperty(kIOAudioControlValueIsReadOnlyKey, (bool)true);
269}
270
271UInt32 IOAudioControl::getType()
272{
273    return type;
274}
275
276UInt32 IOAudioControl::getSubType()
277{
278    return subType;
279}
280
281UInt32 IOAudioControl::getUsage()
282{
283    return usage;
284}
285
286void IOAudioControl::free()
287{
288    audioDebugIOLog(3, "+ IOAudioControl[%p]::free()\n", this);
289
290    if (userClients) {
291        // should we do some sort of notification here?
292        userClients->release();
293        userClients = NULL;
294    }
295
296    if (valueChangeTarget) {
297        valueChangeTarget->release();
298        valueChangeTarget = NULL;
299    }
300
301    if (commandGate) {
302        if (workLoop) {
303            workLoop->removeEventSource(commandGate);
304        }
305
306        commandGate->release();
307        commandGate = NULL;
308    }
309
310    if (workLoop) {
311        workLoop->release();
312        workLoop = NULL;
313    }
314
315	if (reserved) {
316		if (reserved->notificationQueue) {
317			reserved->notificationQueue->release();
318			reserved->notificationQueue = NULL;
319		}
320
321		IOFree (reserved, sizeof (struct ExpansionData));
322		reserved = NULL;
323	}
324
325    super::free();
326    audioDebugIOLog(3, "- IOAudioControl[%p]::free()\n", this);
327}
328
329bool IOAudioControl::start(IOService *provider)
330{
331    if (!super::start(provider)) {
332        return false;
333    }
334
335    isStarted = true;
336	reserved->providerEngine = OSDynamicCast (IOAudioEngine, provider);
337
338    return true;
339}
340
341bool IOAudioControl::attachAndStart(IOService *provider)
342{
343    bool result = true;
344
345    if (attach(provider)) {
346        if (!isStarted) {
347            result = start(provider);
348            if (!result) {
349                detach(provider);
350            }
351        }
352    } else {
353        result = false;
354    }
355
356    return result;
357}
358
359void IOAudioControl::stop(IOService *provider)
360{
361    audioDebugIOLog(3, "+ IOAudioControl[%p]::stop(%p)\n", this, provider);
362
363    if (userClients && (userClients->getCount() > 0)) {
364        IOCommandGate *cg;
365
366        cg = getCommandGate();
367
368		if (cg) {
369			cg->runAction(detachUserClientsAction);
370		}
371    }
372
373    if (valueChangeTarget) {
374        valueChangeTarget->release();
375        valueChangeTarget = NULL;
376        valueChangeHandler.intHandler = NULL;
377    }
378
379	// <rdar://7233118>, <rdar://7029696> Remove the event source here as performing heavy workloop operation in free() could lead
380	// to deadlock since the context which free() is called is not known. stop() is called on the workloop, so it is safe to remove
381	// the event source here.
382	if (reserved->commandGateUsage == 0) {							// <rdar://8518215>
383		reserved->commandGateStatus = kCommandGateStatus_Invalid;	// <rdar://8518215>
384
385		if (commandGate) {
386			if (workLoop) {
387				workLoop->removeEventSource(commandGate);
388			}
389
390			commandGate->release();
391			commandGate = NULL;
392		}
393	}
394	else {	// <rdar://8518215>
395		reserved->commandGateStatus = kCommandGateStatus_RemovalPending;
396	}
397
398    super::stop(provider);
399
400    isStarted = false;
401
402    audioDebugIOLog(3, "- IOAudioControl[%p]::stop(%p)\n", this, provider);
403}
404
405bool IOAudioControl::getIsStarted()
406{
407    return isStarted;
408}
409
410IOWorkLoop *IOAudioControl::getWorkLoop()
411{
412    return workLoop;
413}
414
415void IOAudioControl::setWorkLoop(IOWorkLoop *wl)
416{
417	if (!workLoop) {
418		workLoop = wl;
419
420		if (workLoop) {
421			workLoop->retain();
422
423			commandGate = IOCommandGate::commandGate(this);
424
425			if (commandGate) {
426				workLoop->addEventSource(commandGate);
427			}
428		}
429	}
430}
431
432IOCommandGate *IOAudioControl::getCommandGate()
433{
434    return commandGate;
435}
436
437// <rdar://7529580>
438IOReturn IOAudioControl::_setValueAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
439{
440    IOReturn result = kIOReturnBadArgument;
441
442    if (target) {
443        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target);
444        if (audioControl) {
445            IOCommandGate *cg;
446
447            cg = audioControl->getCommandGate();
448
449            if (cg) {
450				setCommandGateUsage(audioControl, true);	// <rdar://8518215>
451                result = cg->runAction(setValueAction, arg0, arg1, arg2, arg3);
452				setCommandGateUsage(audioControl, false);	// <rdar://8518215>
453            } else {
454                result = kIOReturnError;
455            }
456        }
457    }
458
459    return result;
460}
461
462IOReturn IOAudioControl::setValueAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
463{
464    IOReturn result = kIOReturnBadArgument;
465
466    if (owner) {
467        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner);
468        if (audioControl) {
469            result = audioControl->setValue((OSObject *)arg1);
470        }
471    }
472
473    return result;
474}
475
476IOReturn IOAudioControl::setValue(OSObject *newValue)
477{
478    IOReturn result = kIOReturnSuccess;
479
480    if (OSDynamicCast(OSNumber, newValue)) {
481        audioDebugIOLog(3, "+ IOAudioControl[%p]::setValue(int = %d)\n", this, ((OSNumber *)newValue)->unsigned32BitValue());
482    } else {
483        audioDebugIOLog(3, "+ IOAudioControl[%p]::setValue(%p)\n", this, newValue);
484    }
485
486    if (newValue) {
487        if (!value || !value->isEqualTo(newValue)) {
488            result = validateValue(newValue);
489            if (result == kIOReturnSuccess) {
490                result = performValueChange(newValue);
491                if (result == kIOReturnSuccess) {
492                    result = updateValue(newValue);
493                } else {
494                    audioDebugIOLog(2, "  Error 0x%x received from driver - value not set!\n", result);
495                }
496            } else {
497                audioDebugIOLog(2, "  Error 0x%x - invalid value.\n", result);
498            }
499        }
500    } else {
501        result = kIOReturnBadArgument;
502    }
503
504    if (OSDynamicCast(OSNumber, newValue)) {
505        audioDebugIOLog(3, "- IOAudioControl[%p]::setValue(int = %d) returns 0x%lX\n", this, ((OSNumber *)newValue)->unsigned32BitValue(), (long unsigned int)result );
506    } else {
507        audioDebugIOLog(3, "- IOAudioControl[%p]::setValue(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result );
508    }
509
510    return result;
511}
512
513IOReturn IOAudioControl::setValue(SInt32 intValue)
514{
515    IOReturn result = kIOReturnError;
516    OSNumber *number;
517
518    number = OSNumber::withNumber(intValue, sizeof(SInt32)*8);
519    if (number) {
520        result = setValue(number);
521        number->release();
522    }
523
524    return result;
525}
526
527IOReturn IOAudioControl::validateValue(OSObject *value)
528{
529    return kIOReturnSuccess;
530}
531
532IOReturn IOAudioControl::updateValue(OSObject *newValue)
533{
534    IOReturn result;
535
536    result = _setValue(newValue);
537    if (result == kIOReturnSuccess) {
538        sendValueChangeNotification();
539    }
540
541    return result;
542}
543
544IOReturn IOAudioControl::_setValue(OSObject *newValue)
545{
546    if (value != newValue) {
547        if (value) {
548            value->release();
549        }
550        value = newValue;
551        value->retain();
552
553        setProperty(kIOAudioControlValueKey, value);
554    }
555
556    return kIOReturnSuccess;
557}
558
559IOReturn IOAudioControl::hardwareValueChanged(OSObject *newValue)
560{
561    IOReturn result = kIOReturnSuccess;
562
563    audioDebugIOLog(3, "+ IOAudioControl[%p]::hardwareValueChanged(%p)\n", this, newValue);
564
565    if (newValue) {
566        if (!value || !value->isEqualTo(newValue)) {
567            result = validateValue(newValue);
568            if (result == kIOReturnSuccess) {
569                result = updateValue(newValue);
570            } else {
571                IOLog("IOAudioControl[%p]::hardwareValueChanged(%p) - Error 0x%x - invalid value.\n", this, newValue, result);
572            }
573        }
574    } else {
575        result = kIOReturnBadArgument;
576    }
577
578    audioDebugIOLog(3, "- IOAudioControl[%p]::hardwareValueChanged(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result );
579    return result;
580}
581
582void IOAudioControl::setValueChangeHandler(IntValueChangeHandler intValueChangeHandler, OSObject *target)
583{
584    valueChangeHandlerType = kIntValueChangeHandler;
585    valueChangeHandler.intHandler = intValueChangeHandler;
586    setValueChangeTarget(target);
587}
588
589void IOAudioControl::setValueChangeHandler(DataValueChangeHandler dataValueChangeHandler, OSObject *target)
590{
591    valueChangeHandlerType = kDataValueChangeHandler;
592    valueChangeHandler.dataHandler = dataValueChangeHandler;
593    setValueChangeTarget(target);
594}
595
596void IOAudioControl::setValueChangeHandler(ObjectValueChangeHandler objectValueChangeHandler, OSObject *target)
597{
598    valueChangeHandlerType = kObjectValueChangeHandler;
599    valueChangeHandler.objectHandler = objectValueChangeHandler;
600    setValueChangeTarget(target);
601}
602
603void IOAudioControl::setValueChangeTarget(OSObject *target)
604{
605    if (target) {
606        target->retain();
607    }
608
609    if (valueChangeTarget) {
610        valueChangeTarget->release();
611    }
612
613    valueChangeTarget = target;
614}
615
616IOReturn IOAudioControl::performValueChange(OSObject *newValue)
617{
618    IOReturn result = kIOReturnError;
619
620    audioDebugIOLog(3, "+ IOAudioControl[%p]::performValueChange(%p)\n", this, newValue);
621
622    if (valueChangeHandler.intHandler != NULL) {
623        switch(valueChangeHandlerType) {
624            case kIntValueChangeHandler:
625                OSNumber *oldNumber, *newNumber;
626
627                if ((oldNumber = OSDynamicCast(OSNumber, getValue())) == NULL) {
628                    IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - int handler set and old value is not an OSNumber.\n", this, newValue);
629                    break;
630                }
631
632                if ((newNumber = OSDynamicCast(OSNumber, newValue)) == NULL) {
633                    IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - int handler set and new value is not an OSNumber.\n", this, newValue);
634                    break;
635                }
636
637                result = valueChangeHandler.intHandler(valueChangeTarget, this, oldNumber->unsigned32BitValue(), newNumber->unsigned32BitValue());
638
639                break;
640            case kDataValueChangeHandler:
641                OSData *oldData, *newData;
642                const void *oldBytes, *newBytes;
643                UInt32 oldSize, newSize;
644
645                if (getValue()) {
646                    if ((oldData = OSDynamicCast(OSData, getValue())) == NULL) {
647                        IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - data handler set and old value is not an OSData.\n", this, newValue);
648                        break;
649                    }
650
651                    oldBytes = oldData->getBytesNoCopy();
652                    oldSize = oldData->getLength();
653                } else {
654                    oldBytes = NULL;
655                    oldSize = 0;
656                }
657
658                if (newValue) {
659                    if ((newData = OSDynamicCast(OSData, newValue)) == NULL) {
660                        IOLog("IOAudioControl[%p]::performValueChange(%p) - Error: can't call handler - data handler set and new value is not an OSData.\n", this, newValue);
661                        break;
662                    }
663
664                    newBytes = newData->getBytesNoCopy();
665                    newSize = newData->getLength();
666                } else {
667                    newBytes = NULL;
668                    newSize = 0;
669                }
670
671                result = valueChangeHandler.dataHandler(valueChangeTarget, this, oldBytes, oldSize, newBytes, newSize);
672
673                break;
674            case kObjectValueChangeHandler:
675                result = valueChangeHandler.objectHandler(valueChangeTarget, this, getValue(), newValue);
676                break;
677        }
678    }
679
680    audioDebugIOLog(3, "- IOAudioControl[%p]::performValueChange(%p) returns 0x%lX\n", this, newValue, (long unsigned int)result );
681    return result;
682}
683
684IOReturn IOAudioControl::flushValue()
685{
686    return performValueChange(getValue());
687}
688
689OSObject *IOAudioControl::getValue()
690{
691    return value;
692}
693
694SInt32 IOAudioControl::getIntValue()
695{
696    OSNumber *number;
697    SInt32 intValue = 0;
698
699    number = OSDynamicCast(OSNumber, getValue());
700    if (number) {
701        intValue = (SInt32)number->unsigned32BitValue();
702    }
703
704    return intValue;
705}
706
707const void *IOAudioControl::getDataBytes()
708{
709    const void *bytes = NULL;
710    OSData *data;
711
712    data = OSDynamicCast(OSData, getValue());
713    if (data) {
714        bytes = data->getBytesNoCopy();
715    }
716
717    return bytes;
718}
719
720UInt32 IOAudioControl::getDataLength()
721{
722    UInt32 length = 0;
723    OSData *data;
724
725    data = OSDynamicCast(OSData, getValue());
726    if (data) {
727        length = data->getLength();
728    }
729
730    return length;
731}
732
733void IOAudioControl::sendValueChangeNotification()
734{
735    OSCollectionIterator *iterator;
736    IOAudioControlUserClient *client;
737
738    if (!userClients) {
739        return;
740    }
741
742    iterator = OSCollectionIterator::withCollection(userClients);
743    if (iterator) {
744        while ( (client = (IOAudioControlUserClient *)iterator->getNextObject()) ) {
745            client->sendValueChangeNotification();
746        }
747
748        iterator->release();
749    }
750}
751
752void IOAudioControl::setControlID(UInt32 newControlID)
753{
754    controlID = newControlID;
755    setProperty(kIOAudioControlIDKey, newControlID, sizeof(UInt32)*8);
756}
757
758UInt32 IOAudioControl::getControlID()
759{
760    return controlID;
761}
762
763void IOAudioControl::setChannelID(UInt32 newChannelID)
764{
765    channelID = newChannelID;
766    setProperty(kIOAudioControlChannelIDKey, newChannelID, sizeof(UInt32)*8);
767}
768
769UInt32 IOAudioControl::getChannelID()
770{
771    return channelID;
772}
773
774void IOAudioControl::setChannelNumber(SInt32 channelNumber)
775{
776    setProperty(kIOAudioControlChannelNumberKey, channelNumber, sizeof(SInt32)*8);
777}
778
779IOReturn IOAudioControl::createUserClient(task_t task, void *securityID, UInt32 type, IOAudioControlUserClient **newUserClient)
780{
781    IOReturn result = kIOReturnSuccess;
782    IOAudioControlUserClient *userClient;
783
784    userClient = IOAudioControlUserClient::withAudioControl(this, task, securityID, type);
785
786    if (userClient) {
787        *newUserClient = userClient;
788    } else {
789        result = kIOReturnNoMemory;
790    }
791
792    return result;
793}
794
795IOReturn IOAudioControl::newUserClient(task_t task, void *securityID, UInt32 type, IOUserClient **handler)
796{
797#if __i386__ || __x86_64__
798	return kIOReturnUnsupported;
799#else
800    IOReturn result = kIOReturnSuccess;
801    IOAudioControlUserClient *client = NULL;
802
803    audioDebugIOLog(3, "+ IOAudioControl[%p]::newUserClient()\n", this);
804
805	*handler = NULL;		// <rdar://8370885>
806
807    if (!isInactive()) {	// <rdar://7324947>
808		result = createUserClient(task, securityID, type, &client);
809
810		if ((result == kIOReturnSuccess) && (client != NULL)) {
811			if (workLoop) {		// <rdar://7324947>
812				result = workLoop->runAction(_addUserClientAction, this, client);	// <rdar://7324947>, <rdar://7529580>
813
814				if (result == kIOReturnSuccess) {
815					*handler = client;
816				} else {
817					client->release();	// <rdar://8370885>
818				}
819
820			} else {
821				client->release();		// <rdar://8370885>
822				result = kIOReturnError;
823			}
824		}
825    } else {	// <rdar://7324947>
826        result = kIOReturnNoDevice;
827    }
828
829    audioDebugIOLog(3, "- IOAudioControl[%p]::newUserClient() returns 0x%lX\n", this, (long unsigned int)result );
830    return result;
831#endif
832}
833
834//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
835//	the indentifier post processing tool can properly insert scope when post processing a log file
836//	obtained via fwkpfv.
837
838IOReturn IOAudioControl::newUserClient(task_t task, void *securityID, UInt32 type, OSDictionary *properties, IOUserClient **handler)
839{
840    IOReturn					result = kIOReturnSuccess;
841    IOAudioControlUserClient *	client = NULL;
842
843    audioDebugIOLog(3, "+ IOAudioControl[%p]::newUserClient()\n", this);
844
845	*handler = NULL;		// <rdar://8370885>
846
847    if ( !isInactive () )	// <rdar://7324947>
848	{
849		if ( kIOReturnSuccess != newUserClient ( task, securityID, type, handler ) )
850		{
851			result = createUserClient ( task, securityID, type, &client, properties );
852
853			if ( ( kIOReturnSuccess == result ) && ( NULL != client ) )
854			{
855				if ( workLoop )	// <rdar://7324947>
856				{
857					result = workLoop->runAction ( _addUserClientAction, this, client );	// <rdar://7324947>, <rdar://7529580>
858
859					if ( result == kIOReturnSuccess )
860					{
861						*handler = client;
862					}
863					else
864					{
865						client->release();		// <rdar://8370885>
866					}
867				}
868				else
869				{
870					client->release();			// <rdar://8370885>
871					result = kIOReturnError;
872				}
873			}
874		}
875    }
876    else	// <rdar://7324947>
877    {
878        result = kIOReturnNoDevice;
879    }
880
881    audioDebugIOLog(3, "- IOAudioControl[%p]::newUserClient() returns 0x%lX\n", this, (long unsigned int)result );
882    return result;
883}
884
885void IOAudioControl::clientClosed(IOAudioControlUserClient *client)
886{
887    audioDebugIOLog(3, "+ IOAudioControl[%p]::clientClosed(%p)\n", this, client);
888
889    if (client) {
890		if (workLoop) {														// <rdar://7529580>
891			workLoop->runAction(_removeUserClientAction, this, client);		// <rdar://7529580>
892		}
893    }
894    audioDebugIOLog(3, "- IOAudioControl[%p]::clientClosed(%p)\n", this, client);
895}
896
897// <rdar://7529580>
898IOReturn IOAudioControl::_addUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
899{
900    IOReturn result = kIOReturnBadArgument;
901
902    if (target) {
903        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target);
904        if (audioControl) {
905            IOCommandGate *cg;
906
907            cg = audioControl->getCommandGate();
908
909            if (cg) {
910				setCommandGateUsage(audioControl, true);	// <rdar://8518215>
911                result = cg->runAction(addUserClientAction, arg0, arg1, arg2, arg3);
912				setCommandGateUsage(audioControl, false);	// <rdar://8518215>
913            } else {
914                result = kIOReturnError;
915            }
916        }
917    }
918
919    return result;
920}
921
922IOReturn IOAudioControl::addUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
923{
924    IOReturn result = kIOReturnBadArgument;
925
926    if (owner) {
927        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner);
928        if (audioControl) {
929            result = audioControl->addUserClient((IOAudioControlUserClient *)arg1);
930        }
931    }
932
933    return result;
934}
935
936// <rdar://7529580>
937IOReturn IOAudioControl::_removeUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
938{
939    IOReturn result = kIOReturnBadArgument;
940
941    if (target) {
942        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, target);
943        if (audioControl) {
944            IOCommandGate *cg;
945
946            cg = audioControl->getCommandGate();
947
948            if (cg) {
949				setCommandGateUsage(audioControl, true);	// <rdar://8518215>
950                result = cg->runAction(removeUserClientAction, arg0, arg1, arg2, arg3);
951				setCommandGateUsage(audioControl, false);	// <rdar://8518215>
952            } else {
953                result = kIOReturnError;
954            }
955        }
956    }
957
958    return result;
959}
960
961IOReturn IOAudioControl::removeUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
962{
963    IOReturn result = kIOReturnBadArgument;
964
965    if (owner) {
966        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner);
967        if (audioControl) {
968            result = audioControl->removeUserClient((IOAudioControlUserClient *)arg1);
969        }
970    }
971
972    return result;
973}
974
975IOReturn IOAudioControl::detachUserClientsAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
976{
977    IOReturn result = kIOReturnBadArgument;
978
979    if (owner) {
980        IOAudioControl *audioControl = OSDynamicCast(IOAudioControl, owner);
981        if (audioControl) {
982            result = audioControl->detachUserClients();
983        }
984    }
985
986    return result;
987}
988
989IOReturn IOAudioControl::addUserClient(IOAudioControlUserClient *newUserClient)
990{
991    IOReturn					result = kIOReturnSuccess;		// <rdar://8370885>
992
993    audioDebugIOLog(3, "+ IOAudioControl[%p]::addUserClient(%p)\n", this, newUserClient);
994
995    assert(userClients);
996
997	// <rdar://8370885>
998	if (!isInactive()) {
999		if (!newUserClient->attach(this)) {
1000			result = kIOReturnError;
1001		} else if (!newUserClient->start(this) || !userClients) {
1002			newUserClient->detach(this);
1003			result = kIOReturnError;
1004		} else {
1005			userClients->setObject(newUserClient);
1006		}
1007	} else {
1008        result = kIOReturnNoDevice;
1009    }
1010
1011    audioDebugIOLog(3, "- IOAudioControl[%p]::addUserClient(%p) returns 0x%lX\n", this, newUserClient, (long unsigned int)kIOReturnSuccess );
1012    return result;	// <rdar://8370885>
1013}
1014
1015IOReturn IOAudioControl::removeUserClient(IOAudioControlUserClient *userClient)
1016{
1017    audioDebugIOLog(3, "+ IOAudioControl[%p]::removeUserClient(%p)\n", this, userClient);
1018
1019    assert(userClients);
1020
1021    userClient->retain();
1022
1023    userClients->removeObject(userClient);
1024
1025    if (!isInactive()) {
1026        userClient->terminate();
1027    }
1028
1029    userClient->release();
1030
1031    audioDebugIOLog(3, "- IOAudioControl[%p]::removeUserClient(%p) returns 0x%lX\n", this, userClient, (long unsigned int)kIOReturnSuccess );
1032    return kIOReturnSuccess;
1033}
1034
1035IOReturn IOAudioControl::detachUserClients()
1036{
1037    IOReturn result = kIOReturnSuccess;
1038
1039    audioDebugIOLog(3, "+ IOAudioControl[%p]::detachUserClients()\n", this);
1040
1041    assert(userClients);
1042
1043    if (!isInactive()) {
1044        OSIterator *iterator;
1045
1046        iterator = OSCollectionIterator::withCollection(userClients);
1047
1048        if (iterator) {
1049            IOAudioControlUserClient *userClient;
1050
1051            while ( (userClient = (IOAudioControlUserClient *)iterator->getNextObject()) ) {
1052                userClient->terminate();
1053            }
1054
1055            iterator->release();
1056        }
1057    }
1058
1059    userClients->flushCollection();
1060
1061    audioDebugIOLog(3, "- IOAudioControl[%p]::detachUserClients() returns 0x%lX\n", this, (long unsigned int)result );
1062    return result;
1063}
1064
1065// <rdar://8518215>
1066void IOAudioControl::setCommandGateUsage(IOAudioControl *control, bool increment)
1067{
1068	if (control->reserved) {
1069		if (increment) {
1070			switch (control->reserved->commandGateStatus)
1071			{
1072				case kCommandGateStatus_Normal:
1073				case kCommandGateStatus_RemovalPending:
1074					control->reserved->commandGateUsage++;
1075					break;
1076				case kCommandGateStatus_Invalid:
1077					// Should never be here. If so, something went bad...
1078					break;
1079			}
1080		}
1081		else {
1082			switch (control->reserved->commandGateStatus)
1083			{
1084				case kCommandGateStatus_Normal:
1085					if (control->reserved->commandGateUsage > 0) {
1086						control->reserved->commandGateUsage--;
1087					}
1088					break;
1089				case kCommandGateStatus_RemovalPending:
1090					if (control->reserved->commandGateUsage > 0) {
1091						control->reserved->commandGateUsage--;
1092
1093						if (control->reserved->commandGateUsage == 0) {
1094							control->reserved->commandGateStatus = kCommandGateStatus_Invalid;
1095
1096							if (control->commandGate) {
1097								if (control->workLoop) {
1098									control->workLoop->removeEventSource(control->commandGate);
1099								}
1100
1101								control->commandGate->release();
1102								control->commandGate = NULL;
1103							}
1104						}
1105					}
1106					break;
1107				case kCommandGateStatus_Invalid:
1108					// Should never be here. If so, something went bad...
1109					break;
1110			}
1111		}
1112	}
1113}
1114
1115IOReturn IOAudioControl::setProperties(OSObject *properties)
1116{
1117    OSDictionary *props;
1118    IOReturn result = kIOReturnSuccess;
1119
1120    if (properties && (props = OSDynamicCast(OSDictionary, properties))) {
1121        OSNumber *number = OSDynamicCast(OSNumber, props->getObject(kIOAudioControlValueKey));
1122
1123        if (number) {
1124        	if (workLoop) {																// <rdar://7529580>
1125				result = workLoop->runAction(_setValueAction, this, (void *)number);	// <rdar://7529580>
1126            } else {
1127                result = kIOReturnError;
1128            }
1129        }
1130    } else {
1131        result = kIOReturnBadArgument;
1132    }
1133
1134    return result;
1135}
1136