4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/types.h>
27 #include <sys/sysmacros.h>
29 #include <sys/sunddi.h>
30 #include <sys/atomic.h>
32 #include "audio_impl.h"
35 * Audio Control functions.
39 * Given a control structure - free all names
40 * strings allocated to it.
42 * ctrl - The control who's names that will be free'd.
45 audio_control_freenames(audio_ctrl_t
*ctrl
)
49 if (ctrl
->ctrl_name
!= NULL
)
50 strfree((char *)ctrl
->ctrl_name
);
51 ctrl
->ctrl_name
= NULL
;
53 for (indx
= 0; indx
< 64; indx
++) {
54 if (ctrl
->ctrl_enum
[indx
] != NULL
) {
55 strfree((char *)ctrl
->ctrl_enum
[indx
]);
56 ctrl
->ctrl_enum
[indx
] = NULL
;
62 * This will allocate and register a control for my audio device.
64 * d - The audio device the control will be attached to.
65 * desc - Attributes about this new control
66 * read_fn - Callback function in driver to read control
67 * write_fn - Callback function in driver to write control.
68 * arg - driver private context passed to read_fn/write_fn
70 * On success this will return a control structure else NULL.
72 * The value passed in for a control number in the audio_ctrl_desc_t
73 * has some special meaning. If it is less then AUDIO_CONTROL_EXTBASE
74 * then the control is assumed to be a known control. If it is
75 * AUDIO_CONTROL_EXTBASE then the framework will allocate a unique
76 * control number and replace it in the audio_ctrl_desc_t structure
77 * and this control is considered an extended driver private control.
78 * The number that is replaced in audio_ctrl_desc_t will be greater
79 * then AUDIO_CONTROL_EXTBASE.
83 audio_dev_add_control(audio_dev_t
*d
, audio_ctrl_desc_t
*desc
,
84 audio_ctrl_rd_t read_fn
, audio_ctrl_wr_t write_fn
, void *arg
)
87 audio_ctrl_desc_t
*new_desc
;
91 /* Verify arguments */
95 /* We cannot deal with unnamed controls */
96 if ((name
= desc
->acd_name
) == NULL
) {
101 * If this was called with a control name that was already
102 * added, then we do some special things. First we reuse the
103 * control audio_ctrl_t and as far as outside users are
104 * concerned the handle is reused. To users this looks like we
105 * are changing the controls attributes. But what we really do
106 * is free every thing allocated to the control and then
107 * reinit everything. That way the same code can get used for
110 * We verify anything that could fail before we change the
111 * control or commit to any changes. If there is something bad
112 * return null to indicate an error but the original control
113 * is still usable and untouched.
115 ctrl
= auclnt_find_control(d
, name
);
118 /* Allocate a new control */
119 ctrl
= kmem_zalloc(sizeof (*ctrl
), KM_SLEEP
);
121 /* Re-configure an existing control */
122 switch (desc
->acd_type
) {
123 case AUDIO_CTRL_TYPE_BOOLEAN
:
124 case AUDIO_CTRL_TYPE_STEREO
:
125 case AUDIO_CTRL_TYPE_MONO
:
126 case AUDIO_CTRL_TYPE_METER
:
127 case AUDIO_CTRL_TYPE_ENUM
:
130 audio_dev_warn(d
, "bad control type %d for %s "
131 "not replaced", desc
->acd_type
, desc
->acd_name
);
136 * By removing it from the list we prevent the need to lock
137 * and check for locks on the control itself.
138 * Also by doing this we can use the normal add code to do
139 * what it normally does below.
141 mutex_enter(&d
->d_ctrl_lock
);
142 list_remove(&d
->d_controls
, ctrl
);
143 mutex_exit(&d
->d_ctrl_lock
);
145 audio_control_freenames(ctrl
);
146 ctrl
->ctrl_read_fn
= NULL
;
147 ctrl
->ctrl_write_fn
= NULL
;
148 ctrl
->ctrl_arg
= NULL
;
149 ctrl
->ctrl_dev
= NULL
;
151 new_desc
= &ctrl
->ctrl_des
;
153 /* Fill in new control description */
154 new_desc
->acd_type
= desc
->acd_type
;
155 new_desc
->acd_flags
= desc
->acd_flags
;
156 new_desc
->acd_maxvalue
= desc
->acd_maxvalue
;
157 new_desc
->acd_minvalue
= desc
->acd_minvalue
;
158 new_desc
->acd_name
= strdup(name
);
160 /* Process type of control special actions, if any */
161 switch (desc
->acd_type
) {
162 case AUDIO_CTRL_TYPE_BOOLEAN
:
163 case AUDIO_CTRL_TYPE_STEREO
:
164 case AUDIO_CTRL_TYPE_MONO
:
165 case AUDIO_CTRL_TYPE_METER
:
168 case AUDIO_CTRL_TYPE_ENUM
:
169 for (int bit
= 0; bit
< 64; bit
++) {
170 if (((1U << bit
) & desc
->acd_maxvalue
) == 0)
172 name
= desc
->acd_enum
[bit
];
174 (void) snprintf(scratch
, sizeof (scratch
),
178 new_desc
->acd_enum
[bit
] = strdup(name
);
182 audio_dev_warn(d
, "bad control type %d for %s",
183 desc
->acd_type
, desc
->acd_name
);
188 if (new_desc
->acd_flags
& AUDIO_CTRL_FLAG_READABLE
) {
190 ctrl
->ctrl_read_fn
= read_fn
;
191 ctrl
->ctrl_arg
= arg
;
193 if (new_desc
->acd_flags
& AUDIO_CTRL_FLAG_WRITEABLE
) {
195 ctrl
->ctrl_write_fn
= write_fn
;
196 ctrl
->ctrl_arg
= arg
;
199 mutex_enter(&d
->d_ctrl_lock
);
200 list_insert_tail(&d
->d_controls
, ctrl
);
201 mutex_exit(&d
->d_ctrl_lock
);
208 audio_control_freenames(ctrl
);
209 kmem_free(ctrl
, sizeof (*ctrl
));
215 * This will remove a control from my audio device.
217 * ctrl - The control will be removed.
220 audio_dev_del_control(audio_ctrl_t
*ctrl
)
224 /* Verify argument */
229 mutex_enter(&d
->d_ctrl_lock
);
230 list_remove(&d
->d_controls
, ctrl
);
231 mutex_exit(&d
->d_ctrl_lock
);
233 audio_control_freenames(ctrl
);
234 kmem_free(ctrl
, sizeof (*ctrl
));
238 audio_dev_add_soft_volume(audio_dev_t
*d
)
240 audio_ctrl_desc_t desc
;
242 bzero(&desc
, sizeof (desc
));
243 if (d
->d_pcmvol_ctrl
== NULL
) {
244 desc
.acd_name
= AUDIO_CTRL_ID_VOLUME
;
245 desc
.acd_type
= AUDIO_CTRL_TYPE_MONO
;
246 desc
.acd_minvalue
= 0;
247 desc
.acd_maxvalue
= 100;
248 desc
.acd_flags
= AUDIO_CTRL_FLAG_RW
| AUDIO_CTRL_FLAG_PLAY
|
249 AUDIO_CTRL_FLAG_PCMVOL
;
250 d
->d_pcmvol_ctrl
= audio_dev_add_control(d
, &desc
,
251 auimpl_get_pcmvol
, auimpl_set_pcmvol
, d
);
257 * This will notify clients of need to reread control
258 * values since they have changed.
260 * There will be a routine that allows a client to register
261 * a callback. For now we just update the serial number.
263 * d - The device that needs updates.
266 audio_dev_update_controls(audio_dev_t
*d
)
268 atomic_inc_uint(&d
->d_serial
);
273 * This is used to read the current value of a control.
274 * Note, this will cause a callback into the driver to get the value.
276 * ctrl - should be the valid control being read.
277 * value - is a pointer to the place that will contain the value read.
279 * On return zero is returned on success else errno is returned.
283 audio_control_read(audio_ctrl_t
*ctrl
, uint64_t *value
)
285 audio_dev_t
*d
= ctrl
->ctrl_dev
;
291 mutex_enter(&d
->d_ctrl_lock
);
292 while (d
->d_suspended
) {
293 cv_wait(&d
->d_ctrl_cv
, &d
->d_ctrl_lock
);
296 if (!(ctrl
->ctrl_flags
& AUDIO_CTRL_FLAG_READABLE
)) {
297 mutex_exit(&d
->d_ctrl_lock
);
301 ASSERT(ctrl
->ctrl_read_fn
);
303 ret
= ctrl
->ctrl_read_fn(ctrl
->ctrl_arg
, &my_value
);
304 mutex_exit(&d
->d_ctrl_lock
);
314 * This is used to write a value to a control.
315 * Note, this will cause a callback into the driver to write the value.
317 * ctrl - should be the valid control being written.
318 * value - is value to set the control to.
320 * On return zero is returned on success else errno is returned.
324 audio_control_write(audio_ctrl_t
*ctrl
, uint64_t value
)
327 audio_dev_t
*d
= ctrl
->ctrl_dev
;
329 mutex_enter(&d
->d_ctrl_lock
);
330 while (d
->d_suspended
) {
331 cv_wait(&d
->d_ctrl_cv
, &d
->d_ctrl_lock
);
334 if (!(ctrl
->ctrl_flags
& AUDIO_CTRL_FLAG_WRITEABLE
)) {
335 mutex_exit(&d
->d_ctrl_lock
);
339 ASSERT(ctrl
->ctrl_write_fn
);
341 ret
= ctrl
->ctrl_write_fn(ctrl
->ctrl_arg
, value
);
343 ctrl
->ctrl_saved
= value
;
344 ctrl
->ctrl_saved_ok
= B_TRUE
;
346 mutex_exit(&d
->d_ctrl_lock
);
349 audio_dev_update_controls(d
);
356 * This is used to save control values.
359 auimpl_save_controls(audio_dev_t
*d
)
365 ASSERT(mutex_owned(&d
->d_ctrl_lock
));
368 for (ctrl
= list_head(l
); ctrl
; ctrl
= list_next(l
, ctrl
)) {
369 if ((!(ctrl
->ctrl_flags
& AUDIO_CTRL_FLAG_WRITEABLE
)) ||
370 (!(ctrl
->ctrl_flags
& AUDIO_CTRL_FLAG_READABLE
))) {
373 ret
= ctrl
->ctrl_read_fn(ctrl
->ctrl_arg
, &ctrl
->ctrl_saved
);
376 "Unable to save value of control %s",
380 ctrl
->ctrl_saved_ok
= B_TRUE
;
387 auimpl_restore_controls(audio_dev_t
*d
)
394 ASSERT(mutex_owned(&d
->d_ctrl_lock
));
397 for (ctrl
= list_head(l
); ctrl
; ctrl
= list_next(l
, ctrl
)) {
398 if (!ctrl
->ctrl_saved_ok
) {
401 ret
= ctrl
->ctrl_write_fn(ctrl
->ctrl_arg
, ctrl
->ctrl_saved
);
404 "Unable to restore value of control %s",