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 "IOAudioLevelControl.h"
24#include "IOAudioTypes.h"
25#include "IOAudioDefines.h"
26#include "IOAudioDebug.h"
27
28#define super IOAudioControl
29
30OSDefineMetaClassAndStructors(IOAudioLevelControl, IOAudioControl)
31
32OSMetaClassDefineReservedUsed(IOAudioLevelControl, 0);
33
34OSMetaClassDefineReservedUnused(IOAudioLevelControl, 1);
35OSMetaClassDefineReservedUnused(IOAudioLevelControl, 2);
36OSMetaClassDefineReservedUnused(IOAudioLevelControl, 3);
37OSMetaClassDefineReservedUnused(IOAudioLevelControl, 4);
38OSMetaClassDefineReservedUnused(IOAudioLevelControl, 5);
39OSMetaClassDefineReservedUnused(IOAudioLevelControl, 6);
40OSMetaClassDefineReservedUnused(IOAudioLevelControl, 7);
41OSMetaClassDefineReservedUnused(IOAudioLevelControl, 8);
42OSMetaClassDefineReservedUnused(IOAudioLevelControl, 9);
43OSMetaClassDefineReservedUnused(IOAudioLevelControl, 10);
44OSMetaClassDefineReservedUnused(IOAudioLevelControl, 11);
45OSMetaClassDefineReservedUnused(IOAudioLevelControl, 12);
46OSMetaClassDefineReservedUnused(IOAudioLevelControl, 13);
47OSMetaClassDefineReservedUnused(IOAudioLevelControl, 14);
48OSMetaClassDefineReservedUnused(IOAudioLevelControl, 15);
49
50// New code added here
51IOAudioLevelControl *IOAudioLevelControl::createPassThruVolumeControl (SInt32 initialValue,
52                                                                SInt32 minValue,
53                                                                SInt32 maxValue,
54                                                                IOFixed minDB,
55                                                                IOFixed maxDB,
56                                                                UInt32 channelID,
57                                                                const char *channelName,
58                                                                UInt32 cntrlID)
59{
60    return IOAudioLevelControl::create(initialValue,
61                                        minValue,
62                                        maxValue,
63                                        minDB,
64                                        maxDB,
65                                        channelID,
66                                        channelName,
67                                        cntrlID,
68                                        kIOAudioLevelControlSubTypeVolume,
69                                        kIOAudioControlUsagePassThru);
70}
71
72// OSMetaClassDefineReservedUnused(IOAudioLevelControl, 0);
73void IOAudioLevelControl::setLinearScale(bool useLinearScale)
74{
75    setProperty(kIOAudioLevelControlUseLinearScale, useLinearScale, sizeof(bool)*8);
76}
77
78// Original code...
79IOAudioLevelControl *IOAudioLevelControl::create(SInt32 initialValue,
80                                                 SInt32 minValue,
81                                                 SInt32 maxValue,
82                                                 IOFixed minDB,
83                                                 IOFixed maxDB,
84                                                 UInt32 channelID,
85                                                 const char *channelName,
86                                                 UInt32 cntrlID,
87                                                 UInt32 subType,
88                                                 UInt32 usage)
89{
90    IOAudioLevelControl *control;
91
92    control = new IOAudioLevelControl;
93
94    if (control) {
95        if (!control->init(initialValue,
96                           minValue,
97                           maxValue,
98                           minDB,
99                           maxDB,
100                           channelID,
101                           channelName,
102                           cntrlID,
103                           subType,
104                           usage)) {
105            control->release();
106            control = 0;
107        }
108    }
109
110    return control;
111}
112
113IOAudioLevelControl *IOAudioLevelControl::createVolumeControl(SInt32 initialValue,
114                                                                SInt32 minValue,
115                                                                SInt32 maxValue,
116                                                                IOFixed minDB,
117                                                                IOFixed maxDB,
118                                                                UInt32 channelID,
119                                                                const char *channelName,
120                                                                UInt32 cntrlID,
121                                                                UInt32 usage)
122{
123    return IOAudioLevelControl::create(initialValue,
124                                        minValue,
125                                        maxValue,
126                                        minDB,
127                                        maxDB,
128                                        channelID,
129                                        channelName,
130                                        cntrlID,
131                                        kIOAudioLevelControlSubTypeVolume,
132                                        usage);
133}
134
135bool IOAudioLevelControl::init(SInt32 initialValue,
136                               SInt32 _minValue,
137                               SInt32 _maxValue,
138                               IOFixed _minDB,
139                               IOFixed _maxDB,
140                               UInt32 channelID,
141                               const char *channelName,
142                               UInt32 cntrlID,
143                               UInt32 subType,
144                               UInt32 usage,
145                               OSDictionary *properties)
146{
147    bool result = true;
148    OSNumber *number;
149
150    number = OSNumber::withNumber(initialValue, sizeof(SInt32)*8);
151
152    if ((number == NULL) || !super::init(kIOAudioControlTypeLevel, number, channelID, channelName, cntrlID, subType, usage, properties)) {
153        result = false;
154        goto Done;
155    }
156
157    setMinValue(_minValue);
158    setMaxValue(_maxValue);
159    setMinDB(_minDB);
160    setMaxDB(_maxDB);
161
162Done:
163    if (number) {
164        number->release();
165    }
166
167    return result;
168}
169
170void IOAudioLevelControl::free()
171{
172    if (ranges) {
173        ranges->release();
174        ranges = NULL;
175    }
176
177    super::free();
178}
179
180void IOAudioLevelControl::setMinValue(SInt32 newMinValue)
181{
182    minValue = newMinValue;
183    setProperty(kIOAudioLevelControlMinValueKey, newMinValue, sizeof(SInt32)*8);
184	sendChangeNotification(kIOAudioControlRangeChangeNotification);
185}
186
187SInt32 IOAudioLevelControl::getMinValue()
188{
189    return minValue;
190}
191
192void IOAudioLevelControl::setMaxValue(SInt32 newMaxValue)
193{
194    maxValue = newMaxValue;
195    setProperty(kIOAudioLevelControlMaxValueKey, newMaxValue, sizeof(SInt32)*8);
196	sendChangeNotification(kIOAudioControlRangeChangeNotification);
197}
198
199SInt32 IOAudioLevelControl::getMaxValue()
200{
201    return maxValue;
202}
203
204void IOAudioLevelControl::setMinDB(IOFixed newMinDB)
205{
206    minDB = newMinDB;
207    setProperty(kIOAudioLevelControlMinDBKey, newMinDB, sizeof(IOFixed)*8);
208	sendChangeNotification(kIOAudioControlRangeChangeNotification);
209}
210
211IOFixed IOAudioLevelControl::getMinDB()
212{
213    return minDB;
214}
215
216void IOAudioLevelControl::setMaxDB(IOFixed newMaxDB)
217{
218    setProperty(kIOAudioLevelControlMaxDBKey, newMaxDB, sizeof(IOFixed)*8);
219	sendChangeNotification(kIOAudioControlRangeChangeNotification);
220}
221
222IOFixed IOAudioLevelControl::getMaxDB()
223{
224    return maxDB;
225}
226
227// Should only be done during init time - this is not thread safe
228IOReturn IOAudioLevelControl::addRange(SInt32 minRangeValue,
229                                        SInt32 maxRangeValue,
230                                        IOFixed minRangeDB,
231                                        IOFixed maxRangeDB)
232{
233    IOReturn result = kIOReturnSuccess;
234
235    // We should verify the new range doesn't overlap any others here
236
237    if (ranges == NULL) {
238        ranges = OSArray::withCapacity(1);
239        if (ranges) {
240            setProperty(kIOAudioLevelControlRangesKey, ranges);
241        }
242    }
243
244    if (ranges) {
245        OSDictionary *newRange;
246		OSArray *newRanges;
247		OSArray *oldRanges;
248
249		oldRanges = ranges;
250        newRanges = OSArray::withArray(ranges);
251		if (!newRanges)
252			return kIOReturnNoMemory;
253
254        newRange = OSDictionary::withCapacity(4);
255        if (newRange) {
256            OSNumber *number;
257
258            number = OSNumber::withNumber(minRangeValue, sizeof(SInt32)*8);
259            newRange->setObject(kIOAudioLevelControlMinValueKey, number);
260            number->release();
261
262            number = OSNumber::withNumber(maxRangeValue, sizeof(SInt32)*8);
263            newRange->setObject(kIOAudioLevelControlMaxValueKey, number);
264            number->release();
265
266            number = OSNumber::withNumber(minRangeDB, sizeof(IOFixed)*8);
267            newRange->setObject(kIOAudioLevelControlMinDBKey, number);
268            number->release();
269
270            number = OSNumber::withNumber(maxRangeDB, sizeof(IOFixed)*8);
271            newRange->setObject(kIOAudioLevelControlMaxDBKey, number);
272            number->release();
273
274            newRanges->setObject(newRange);
275            setProperty(kIOAudioLevelControlRangesKey, newRanges);
276			ranges = newRanges;
277			oldRanges->release();
278
279            newRange->release();
280        } else {
281            result = kIOReturnError;
282        }
283    } else {
284        result = kIOReturnError;
285    }
286
287    return result;
288}
289
290IOReturn IOAudioLevelControl::addNegativeInfinity(SInt32 negativeInfinityValue)
291{
292    return addRange(negativeInfinityValue, negativeInfinityValue, kIOAudioLevelControlNegativeInfinity, kIOAudioLevelControlNegativeInfinity);
293}
294
295IOReturn IOAudioLevelControl::validateValue(OSObject *newValue)
296{
297    IOReturn result = kIOReturnBadArgument;
298    OSNumber *number;
299
300    number = OSDynamicCast(OSNumber, newValue);
301
302	audioDebugIOLog(3, "+ IOAudioLevelControl::validateValue[%p] (%p)\n", this, newValue);
303
304    if (number) {
305        SInt32 newIntValue;
306
307        newIntValue = (SInt32)number->unsigned32BitValue();
308
309		audioDebugIOLog(3, "  IOAudioLevelControl::validateValue[%p] - newIntValue = %ld, min = %ld, max = %ld\n", this, (long int)newIntValue, (long int)minValue, (long int)maxValue);
310
311        if ((newIntValue >= minValue) && (newIntValue <= maxValue)) {
312            result = kIOReturnSuccess;
313        } else {
314            result = kIOReturnError;
315        }
316    }
317
318	audioDebugIOLog(3, "- IOAudioLevelControl::validateValue[%p] (%p) returns 0x%lX\n", this, newValue, (long unsigned int)result );
319    return result;
320}
321
322
323