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 "IOAudioSelectorControl.h"
24#include "IOAudioTypes.h"
25#include "IOAudioDefines.h"
26
27#include <libkern/c++/OSString.h>
28#include <libkern/c++/OSArray.h>
29#include <libkern/c++/OSDictionary.h>
30
31#define super IOAudioControl
32
33OSDefineMetaClassAndStructors(IOAudioSelectorControl, IOAudioControl)
34OSMetaClassDefineReservedUsed(IOAudioSelectorControl, 0);
35OSMetaClassDefineReservedUsed(IOAudioSelectorControl, 1);
36OSMetaClassDefineReservedUsed(IOAudioSelectorControl, 2);
37OSMetaClassDefineReservedUsed(IOAudioSelectorControl, 3);										// <rdar://8202424>
38
39OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 4);										// <rdar://8202424>
40OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 5);
41OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 6);
42OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 7);
43OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 8);
44OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 9);
45OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 10);
46OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 11);
47OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 12);
48OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 13);
49OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 14);
50OSMetaClassDefineReservedUnused(IOAudioSelectorControl, 15);
51
52// New code
53IOAudioSelectorControl *IOAudioSelectorControl::createOutputClockSelector(SInt32 initialValue,
54                                                                    UInt32 channelID,
55																	UInt32 clockSource,
56                                                                    const char *channelName,
57                                                                    UInt32 cntrlID)
58{
59	IOAudioSelectorControl *clockControl;
60
61	if ((clockControl = create (initialValue,
62                    channelID,
63                    channelName,
64                    cntrlID,
65                    kIOAudioSelectorControlSubTypeClockSource,
66                    kIOAudioControlUsageOutput))) {
67        clockControl->setProperty(kIOAudioSelectorControlClockSourceKey, clockSource);
68	}
69
70	return clockControl;
71}
72
73IOAudioSelectorControl *IOAudioSelectorControl::createInputClockSelector(SInt32 initialValue,
74                                                                    UInt32 channelID,
75																	UInt32 clockSource,
76                                                                    const char *channelName,
77                                                                    UInt32 cntrlID)
78{
79	IOAudioSelectorControl *clockControl;
80
81	if ((clockControl = create (initialValue,
82                    channelID,
83                    channelName,
84                    cntrlID,
85                    kIOAudioSelectorControlSubTypeClockSource,
86                    kIOAudioControlUsageInput))) {
87        clockControl->setProperty(kIOAudioSelectorControlClockSourceKey, clockSource);
88	}
89
90	return clockControl;
91}
92
93IOAudioSelectorControl *IOAudioSelectorControl::createOutputSelector(SInt32 initialValue,
94                                                                    UInt32 channelID,
95                                                                    const char *channelName,
96                                                                    UInt32 cntrlID)
97{
98    return create(initialValue,
99                    channelID,
100                    channelName,
101                    cntrlID,
102                    kIOAudioSelectorControlSubTypeOutput,
103                    kIOAudioControlUsageOutput);
104}
105
106IOReturn IOAudioSelectorControl::removeAvailableSelection(SInt32 selectionValue)
107{
108    OSCollectionIterator *iterator;
109	OSArray *newSelections;
110	OSArray *oldAvailableSelections;
111    IOReturn result = kIOReturnNotFound;
112
113    assert(availableSelections);
114
115	oldAvailableSelections = availableSelections;
116	newSelections = OSArray::withArray(availableSelections);
117	if (!newSelections)
118		return kIOReturnNoMemory;
119
120    iterator = OSCollectionIterator::withCollection(newSelections);
121    if (iterator) {
122        OSDictionary *	selection;
123		UInt32			index;
124
125		index = 0;
126        while ( (selection = (OSDictionary *)iterator->getNextObject()) ) {
127            OSNumber *	sValue;
128
129            sValue = (OSNumber *)selection->getObject(kIOAudioSelectorControlSelectionValueKey);
130
131            if (sValue && ((SInt32)sValue->unsigned32BitValue() == selectionValue)) {
132				// Remove the selected dictionary from the array
133				newSelections->removeObject(index);
134				result = kIOReturnSuccess;
135                break;
136            }
137			index++;
138        }
139		availableSelections = newSelections;
140        setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
141		oldAvailableSelections->release();
142
143        iterator->release();
144    }
145
146	if (kIOReturnSuccess == result) {
147		sendChangeNotification(kIOAudioControlRangeChangeNotification);
148	}
149
150    return result;
151}
152
153IOReturn IOAudioSelectorControl::replaceAvailableSelection(SInt32 selectionValue, const char *selectionDescription)
154{
155    IOReturn result = kIOReturnBadArgument;
156
157    if (selectionDescription != NULL) {
158        OSString *selDesc;
159
160        selDesc = OSString::withCString(selectionDescription);
161        if (selDesc) {
162            result = replaceAvailableSelection(selectionValue, selDesc);
163        } else {
164            result = kIOReturnNoMemory;
165        }
166    }
167
168    return result;
169}
170
171IOReturn IOAudioSelectorControl::replaceAvailableSelection(SInt32 selectionValue, OSString *selectionDescription)
172{
173    OSCollectionIterator *iterator;
174	OSArray *newSelections;
175	OSArray *oldAvailableSelections;
176    IOReturn result = kIOReturnSuccess;
177
178    assert(availableSelections);
179
180	oldAvailableSelections = availableSelections;
181	newSelections = OSArray::withArray(availableSelections);
182	if (!newSelections)
183		return kIOReturnNoMemory;
184
185    iterator = OSCollectionIterator::withCollection(newSelections);
186    if (iterator) {
187        OSDictionary *	selection;
188		UInt32			index;
189
190		index = 0;
191        while ( (selection = (OSDictionary *)iterator->getNextObject() )) {
192            OSNumber *	sValue;
193
194            sValue = (OSNumber *)selection->getObject(kIOAudioSelectorControlSelectionValueKey);
195
196            if (sValue && ((SInt32)sValue->unsigned32BitValue() == selectionValue)) {
197				// Replace the selected dictionary in the array
198				newSelections->replaceObject(index, selectionDescription);
199				result = kIOReturnSuccess;
200                break;
201            }
202			index++;
203        }
204		availableSelections = newSelections;
205        setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
206		oldAvailableSelections->release();
207
208        iterator->release();
209    }
210
211	if (kIOReturnSuccess == result) {
212		sendChangeNotification(kIOAudioControlRangeChangeNotification);
213	}
214
215    return result;
216}
217
218// Original code...
219IOAudioSelectorControl *IOAudioSelectorControl::create(SInt32 initialValue,
220                                                        UInt32 channelID,
221                                                        const char *channelName,
222                                                        UInt32 cntrlID,
223                                                        UInt32 subType,
224                                                        UInt32 usage)
225{
226    IOAudioSelectorControl *control;
227
228    control = new IOAudioSelectorControl;
229
230    if (control) {
231        if (!control->init(initialValue,
232                            channelID,
233                            channelName,
234                            cntrlID,
235                            subType,
236                            usage)) {
237            control->release();
238            control = NULL;
239        }
240    }
241
242    return control;
243}
244
245IOAudioSelectorControl *IOAudioSelectorControl::createInputSelector(SInt32 initialValue,
246                                                                    UInt32 channelID,
247                                                                    const char *channelName,
248                                                                    UInt32 cntrlID)
249{
250    return create(initialValue,
251                    channelID,
252                    channelName,
253                    cntrlID,
254                    kIOAudioSelectorControlSubTypeInput,
255                    kIOAudioControlUsageInput);
256}
257
258bool IOAudioSelectorControl::init(SInt32 initialValue,
259                                    UInt32 channelID,
260                                    const char *channelName,
261                                    UInt32 cntrlID,
262                                    UInt32 subType,
263                                    UInt32 usage,
264                                    OSDictionary *properties)
265{
266    bool result = false;
267    OSNumber *number;
268
269    number = OSNumber::withNumber(initialValue, sizeof(SInt32)*8);
270
271    if (number) {
272        result = super::init(kIOAudioControlTypeSelector,
273                        number,
274                        channelID,
275                        channelName,
276                        cntrlID,
277                        subType,
278                        usage,
279                        properties);
280
281        number->release();
282    }
283
284    if (result) {
285        availableSelections = OSArray::withCapacity(2);
286        setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
287    }
288
289    return result;
290}
291
292void IOAudioSelectorControl::free()
293{
294    if (availableSelections) {
295        availableSelections->release();
296        availableSelections = NULL;
297    }
298
299    super::free();
300}
301
302IOReturn IOAudioSelectorControl::addAvailableSelection(SInt32 selectionValue, const char *selectionDescription)
303{
304    IOReturn result = kIOReturnBadArgument;
305
306    if (selectionDescription != NULL) {
307        OSString *selDesc;
308
309        selDesc = OSString::withCString(selectionDescription);
310        if (selDesc) {
311            result = addAvailableSelection(selectionValue, selDesc);
312        } else {
313            result = kIOReturnNoMemory;
314        }
315    }
316
317    return result;
318}
319
320IOReturn IOAudioSelectorControl::addAvailableSelection(SInt32 selectionValue, OSString *selectionDescription)
321{
322	OSArray *newSelections;
323	OSArray *oldAvailableSelections;
324    IOReturn result = kIOReturnSuccess;
325
326	oldAvailableSelections = availableSelections;
327	newSelections = OSArray::withArray(availableSelections);
328	if (!newSelections)
329		return kIOReturnNoMemory;
330
331    if (selectionDescription == NULL) {
332        result = kIOReturnBadArgument;
333    } else {
334        if (valueExists(selectionValue)) {
335            result = kIOReturnError;
336        } else {
337            OSDictionary *newSelection;
338
339            newSelection = OSDictionary::withCapacity(2);
340
341            if (newSelection) {
342                OSNumber *number;
343
344                number = OSNumber::withNumber(selectionValue, sizeof(SInt32)*8);
345
346                if (number) {
347                    newSelection->setObject(kIOAudioSelectorControlSelectionValueKey, number);
348                    newSelection->setObject(kIOAudioSelectorControlSelectionDescriptionKey, selectionDescription);
349                    newSelections->setObject(newSelection);
350
351                    number->release();
352                } else {
353                    result = kIOReturnError;
354                }
355				availableSelections = newSelections;
356				setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
357				oldAvailableSelections->release();
358
359                newSelection->release();
360            } else {
361                result = kIOReturnError;
362            }
363        }
364    }
365
366	if (kIOReturnSuccess == result) {
367		sendChangeNotification(kIOAudioControlRangeChangeNotification);
368	}
369
370    return result;
371}
372
373// <rdar://8202424>
374IOReturn IOAudioSelectorControl::addAvailableSelection(SInt32 selectionValue, OSString *selectionDescription, const char* tagName, OSObject* tag)
375{
376	OSArray *newSelections;
377	OSArray *oldAvailableSelections;
378    IOReturn result = kIOReturnSuccess;
379
380	oldAvailableSelections = availableSelections;
381	newSelections = OSArray::withArray(availableSelections);
382	if (!newSelections)
383		return kIOReturnNoMemory;
384
385    if (selectionDescription == NULL) {
386        result = kIOReturnBadArgument;
387    } else {
388        if (valueExists(selectionValue)) {
389            result = kIOReturnError;
390        } else {
391            OSDictionary *newSelection;
392
393            newSelection = OSDictionary::withCapacity(2);
394
395            if (newSelection) {
396                OSNumber *number;
397
398                number = OSNumber::withNumber(selectionValue, sizeof(SInt32)*8);
399
400                if (number) {
401                    newSelection->setObject(kIOAudioSelectorControlSelectionValueKey, number);
402                    newSelection->setObject(kIOAudioSelectorControlSelectionDescriptionKey, selectionDescription);
403                    newSelections->setObject(newSelection);
404
405                    number->release();
406                } else {
407                    result = kIOReturnError;
408                }
409
410				if ( tagName && tag ) {
411					newSelection->setObject(tagName, tag);
412				}
413
414				availableSelections = newSelections;
415				setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
416				oldAvailableSelections->release();
417
418                newSelection->release();
419            } else {
420                result = kIOReturnError;
421            }
422        }
423    }
424
425	if (kIOReturnSuccess == result) {
426		sendChangeNotification(kIOAudioControlRangeChangeNotification);
427	}
428
429    return result;
430}
431
432bool IOAudioSelectorControl::valueExists(SInt32 selectionValue)
433{
434    bool found = false;
435    OSCollectionIterator *iterator;
436
437    assert(availableSelections);
438
439    iterator = OSCollectionIterator::withCollection(availableSelections);
440    if (iterator) {
441        OSDictionary *selection;
442
443        while ( (selection = (OSDictionary *)iterator->getNextObject()) ) {
444            OSNumber *sValue;
445
446            sValue = (OSNumber *)selection->getObject(kIOAudioSelectorControlSelectionValueKey);
447
448            if (sValue && ((SInt32)sValue->unsigned32BitValue() == selectionValue)) {
449                found = true;
450                break;
451            }
452        }
453
454        iterator->release();
455    }
456
457    return found;
458}
459
460IOReturn IOAudioSelectorControl::validateValue(OSObject *newValue)
461{
462    IOReturn result = kIOReturnBadArgument;
463    OSNumber *number;
464
465    number = OSDynamicCast(OSNumber, newValue);
466
467    if (number) {
468        result = super::validateValue(newValue);
469
470        if (result == kIOReturnSuccess) {
471            if (valueExists((SInt32)number->unsigned32BitValue())) {
472                result = kIOReturnSuccess;
473            } else {
474                result = kIOReturnNotFound;
475            }
476        }
477    }
478
479    return result;
480}
481
482