Branch data Line data Source code
1 : : /*
2 : : * Virtual master and slave controls
3 : : *
4 : : * Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de>
5 : : *
6 : : * This program is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU General Public License as
8 : : * published by the Free Software Foundation, version 2.
9 : : *
10 : : */
11 : :
12 : : #include <linux/slab.h>
13 : : #include <linux/export.h>
14 : : #include <sound/core.h>
15 : : #include <sound/control.h>
16 : : #include <sound/tlv.h>
17 : :
18 : : /*
19 : : * a subset of information returned via ctl info callback
20 : : */
21 : : struct link_ctl_info {
22 : : snd_ctl_elem_type_t type; /* value type */
23 : : int count; /* item count */
24 : : int min_val, max_val; /* min, max values */
25 : : };
26 : :
27 : : /*
28 : : * link master - this contains a list of slave controls that are
29 : : * identical types, i.e. info returns the same value type and value
30 : : * ranges, but may have different number of counts.
31 : : *
32 : : * The master control is so far only mono volume/switch for simplicity.
33 : : * The same value will be applied to all slaves.
34 : : */
35 : : struct link_master {
36 : : struct list_head slaves;
37 : : struct link_ctl_info info;
38 : : int val; /* the master value */
39 : : unsigned int tlv[4];
40 : : void (*hook)(void *private_data, int);
41 : : void *hook_private_data;
42 : : };
43 : :
44 : : /*
45 : : * link slave - this contains a slave control element
46 : : *
47 : : * It fakes the control callbacsk with additional attenuation by the
48 : : * master control. A slave may have either one or two channels.
49 : : */
50 : :
51 : : struct link_slave {
52 : : struct list_head list;
53 : : struct link_master *master;
54 : : struct link_ctl_info info;
55 : : int vals[2]; /* current values */
56 : : unsigned int flags;
57 : : struct snd_kcontrol *kctl; /* original kcontrol pointer */
58 : : struct snd_kcontrol slave; /* the copy of original control entry */
59 : : };
60 : :
61 : 0 : static int slave_update(struct link_slave *slave)
62 : : {
63 : : struct snd_ctl_elem_value *uctl;
64 : : int err, ch;
65 : :
66 : : uctl = kmalloc(sizeof(*uctl), GFP_KERNEL);
67 [ # # ]: 0 : if (!uctl)
68 : : return -ENOMEM;
69 : 0 : uctl->id = slave->slave.id;
70 : 0 : err = slave->slave.get(&slave->slave, uctl);
71 [ # # ]: 0 : for (ch = 0; ch < slave->info.count; ch++)
72 : 0 : slave->vals[ch] = uctl->value.integer.value[ch];
73 : 0 : kfree(uctl);
74 : 0 : return 0;
75 : : }
76 : :
77 : : /* get the slave ctl info and save the initial values */
78 : 0 : static int slave_init(struct link_slave *slave)
79 : : {
80 : : struct snd_ctl_elem_info *uinfo;
81 : : int err;
82 : :
83 [ # # ]: 0 : if (slave->info.count) {
84 : : /* already initialized */
85 [ # # ]: 0 : if (slave->flags & SND_CTL_SLAVE_NEED_UPDATE)
86 : 0 : return slave_update(slave);
87 : : return 0;
88 : : }
89 : :
90 : : uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
91 [ # # ]: 0 : if (!uinfo)
92 : : return -ENOMEM;
93 : 0 : uinfo->id = slave->slave.id;
94 : 0 : err = slave->slave.info(&slave->slave, uinfo);
95 [ # # ]: 0 : if (err < 0) {
96 : 0 : kfree(uinfo);
97 : 0 : return err;
98 : : }
99 : 0 : slave->info.type = uinfo->type;
100 : 0 : slave->info.count = uinfo->count;
101 [ # # ][ # # ]: 0 : if (slave->info.count > 2 ||
102 : 0 : (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER &&
103 : : slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) {
104 : 0 : snd_printk(KERN_ERR "invalid slave element\n");
105 : 0 : kfree(uinfo);
106 : 0 : return -EINVAL;
107 : : }
108 : 0 : slave->info.min_val = uinfo->value.integer.min;
109 : 0 : slave->info.max_val = uinfo->value.integer.max;
110 : 0 : kfree(uinfo);
111 : :
112 : 0 : return slave_update(slave);
113 : : }
114 : :
115 : : /* initialize master volume */
116 : 0 : static int master_init(struct link_master *master)
117 : : {
118 : : struct link_slave *slave;
119 : :
120 [ # # ]: 0 : if (master->info.count)
121 : : return 0; /* already initialized */
122 : :
123 [ # # ]: 0 : list_for_each_entry(slave, &master->slaves, list) {
124 : 0 : int err = slave_init(slave);
125 [ # # ]: 0 : if (err < 0)
126 : : return err;
127 : 0 : master->info = slave->info;
128 : 0 : master->info.count = 1; /* always mono */
129 : : /* set full volume as default (= no attenuation) */
130 : 0 : master->val = master->info.max_val;
131 [ # # ]: 0 : if (master->hook)
132 : 0 : master->hook(master->hook_private_data, master->val);
133 : : return 1;
134 : : }
135 : : return -ENOENT;
136 : : }
137 : :
138 : 0 : static int slave_get_val(struct link_slave *slave,
139 : : struct snd_ctl_elem_value *ucontrol)
140 : : {
141 : : int err, ch;
142 : :
143 : 0 : err = slave_init(slave);
144 [ # # ]: 0 : if (err < 0)
145 : : return err;
146 [ # # ]: 0 : for (ch = 0; ch < slave->info.count; ch++)
147 : 0 : ucontrol->value.integer.value[ch] = slave->vals[ch];
148 : : return 0;
149 : : }
150 : :
151 : 0 : static int slave_put_val(struct link_slave *slave,
152 : : struct snd_ctl_elem_value *ucontrol)
153 : : {
154 : : int err, ch, vol;
155 : :
156 : 0 : err = master_init(slave->master);
157 [ # # ]: 0 : if (err < 0)
158 : : return err;
159 : :
160 [ # # # ]: 0 : switch (slave->info.type) {
161 : : case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
162 [ # # ]: 0 : for (ch = 0; ch < slave->info.count; ch++)
163 : 0 : ucontrol->value.integer.value[ch] &=
164 : 0 : !!slave->master->val;
165 : : break;
166 : : case SNDRV_CTL_ELEM_TYPE_INTEGER:
167 [ # # ]: 0 : for (ch = 0; ch < slave->info.count; ch++) {
168 : : /* max master volume is supposed to be 0 dB */
169 : 0 : vol = ucontrol->value.integer.value[ch];
170 : 0 : vol += slave->master->val - slave->master->info.max_val;
171 [ # # ]: 0 : if (vol < slave->info.min_val)
172 : : vol = slave->info.min_val;
173 [ # # ]: 0 : else if (vol > slave->info.max_val)
174 : : vol = slave->info.max_val;
175 : 0 : ucontrol->value.integer.value[ch] = vol;
176 : : }
177 : : break;
178 : : }
179 : 0 : return slave->slave.put(&slave->slave, ucontrol);
180 : : }
181 : :
182 : : /*
183 : : * ctl callbacks for slaves
184 : : */
185 : 0 : static int slave_info(struct snd_kcontrol *kcontrol,
186 : : struct snd_ctl_elem_info *uinfo)
187 : : {
188 : 0 : struct link_slave *slave = snd_kcontrol_chip(kcontrol);
189 : 0 : return slave->slave.info(&slave->slave, uinfo);
190 : : }
191 : :
192 : 0 : static int slave_get(struct snd_kcontrol *kcontrol,
193 : : struct snd_ctl_elem_value *ucontrol)
194 : : {
195 : 0 : struct link_slave *slave = snd_kcontrol_chip(kcontrol);
196 : 0 : return slave_get_val(slave, ucontrol);
197 : : }
198 : :
199 : 0 : static int slave_put(struct snd_kcontrol *kcontrol,
200 : : struct snd_ctl_elem_value *ucontrol)
201 : : {
202 : 0 : struct link_slave *slave = snd_kcontrol_chip(kcontrol);
203 : : int err, ch, changed = 0;
204 : :
205 : 0 : err = slave_init(slave);
206 [ # # ]: 0 : if (err < 0)
207 : : return err;
208 [ # # ]: 0 : for (ch = 0; ch < slave->info.count; ch++) {
209 [ # # ]: 0 : if (slave->vals[ch] != ucontrol->value.integer.value[ch]) {
210 : : changed = 1;
211 : 0 : slave->vals[ch] = ucontrol->value.integer.value[ch];
212 : : }
213 : : }
214 [ # # ]: 0 : if (!changed)
215 : : return 0;
216 : 0 : err = slave_put_val(slave, ucontrol);
217 [ # # ]: 0 : if (err < 0)
218 : 0 : return err;
219 : : return 1;
220 : : }
221 : :
222 : 0 : static int slave_tlv_cmd(struct snd_kcontrol *kcontrol,
223 : : int op_flag, unsigned int size,
224 : : unsigned int __user *tlv)
225 : : {
226 : 0 : struct link_slave *slave = snd_kcontrol_chip(kcontrol);
227 : : /* FIXME: this assumes that the max volume is 0 dB */
228 : 0 : return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv);
229 : : }
230 : :
231 : 0 : static void slave_free(struct snd_kcontrol *kcontrol)
232 : : {
233 : 0 : struct link_slave *slave = snd_kcontrol_chip(kcontrol);
234 [ # # ]: 0 : if (slave->slave.private_free)
235 : 0 : slave->slave.private_free(&slave->slave);
236 [ # # ]: 0 : if (slave->master)
237 : : list_del(&slave->list);
238 : 0 : kfree(slave);
239 : 0 : }
240 : :
241 : : /*
242 : : * Add a slave control to the group with the given master control
243 : : *
244 : : * All slaves must be the same type (returning the same information
245 : : * via info callback). The function doesn't check it, so it's your
246 : : * responsibility.
247 : : *
248 : : * Also, some additional limitations:
249 : : * - at most two channels
250 : : * - logarithmic volume control (dB level), no linear volume
251 : : * - master can only attenuate the volume, no gain
252 : : */
253 : 0 : int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave,
254 : : unsigned int flags)
255 : : {
256 : 0 : struct link_master *master_link = snd_kcontrol_chip(master);
257 : : struct link_slave *srec;
258 : :
259 : 0 : srec = kzalloc(sizeof(*srec) +
260 : 0 : slave->count * sizeof(*slave->vd), GFP_KERNEL);
261 [ # # ]: 0 : if (!srec)
262 : : return -ENOMEM;
263 : 0 : srec->kctl = slave;
264 : 0 : srec->slave = *slave;
265 : 0 : memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd));
266 : 0 : srec->master = master_link;
267 : 0 : srec->flags = flags;
268 : :
269 : : /* override callbacks */
270 : 0 : slave->info = slave_info;
271 : 0 : slave->get = slave_get;
272 : 0 : slave->put = slave_put;
273 [ # # ]: 0 : if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)
274 : 0 : slave->tlv.c = slave_tlv_cmd;
275 : 0 : slave->private_data = srec;
276 : 0 : slave->private_free = slave_free;
277 : :
278 : 0 : list_add_tail(&srec->list, &master_link->slaves);
279 : 0 : return 0;
280 : : }
281 : : EXPORT_SYMBOL(_snd_ctl_add_slave);
282 : :
283 : : /*
284 : : * ctl callbacks for master controls
285 : : */
286 : 0 : static int master_info(struct snd_kcontrol *kcontrol,
287 : : struct snd_ctl_elem_info *uinfo)
288 : : {
289 : 0 : struct link_master *master = snd_kcontrol_chip(kcontrol);
290 : : int ret;
291 : :
292 : 0 : ret = master_init(master);
293 [ # # ]: 0 : if (ret < 0)
294 : : return ret;
295 : 0 : uinfo->type = master->info.type;
296 : 0 : uinfo->count = master->info.count;
297 : 0 : uinfo->value.integer.min = master->info.min_val;
298 : 0 : uinfo->value.integer.max = master->info.max_val;
299 : 0 : return 0;
300 : : }
301 : :
302 : 0 : static int master_get(struct snd_kcontrol *kcontrol,
303 : : struct snd_ctl_elem_value *ucontrol)
304 : : {
305 : 0 : struct link_master *master = snd_kcontrol_chip(kcontrol);
306 : 0 : int err = master_init(master);
307 [ # # ]: 0 : if (err < 0)
308 : : return err;
309 : 0 : ucontrol->value.integer.value[0] = master->val;
310 : 0 : return 0;
311 : : }
312 : :
313 : 0 : static int sync_slaves(struct link_master *master, int old_val, int new_val)
314 : : {
315 : : struct link_slave *slave;
316 : : struct snd_ctl_elem_value *uval;
317 : :
318 : : uval = kmalloc(sizeof(*uval), GFP_KERNEL);
319 [ # # ]: 0 : if (!uval)
320 : : return -ENOMEM;
321 [ # # ]: 0 : list_for_each_entry(slave, &master->slaves, list) {
322 : 0 : master->val = old_val;
323 : 0 : uval->id = slave->slave.id;
324 : 0 : slave_get_val(slave, uval);
325 : 0 : master->val = new_val;
326 : 0 : slave_put_val(slave, uval);
327 : : }
328 : 0 : kfree(uval);
329 : 0 : return 0;
330 : : }
331 : :
332 : 0 : static int master_put(struct snd_kcontrol *kcontrol,
333 : : struct snd_ctl_elem_value *ucontrol)
334 : : {
335 : 0 : struct link_master *master = snd_kcontrol_chip(kcontrol);
336 : : int err, new_val, old_val;
337 : : bool first_init;
338 : :
339 : 0 : err = master_init(master);
340 [ # # ]: 0 : if (err < 0)
341 : : return err;
342 : : first_init = err;
343 : 0 : old_val = master->val;
344 : 0 : new_val = ucontrol->value.integer.value[0];
345 [ # # ]: 0 : if (new_val == old_val)
346 : : return 0;
347 : :
348 : 0 : err = sync_slaves(master, old_val, new_val);
349 [ # # ]: 0 : if (err < 0)
350 : : return err;
351 [ # # ][ # # ]: 0 : if (master->hook && !first_init)
352 : 0 : master->hook(master->hook_private_data, master->val);
353 : : return 1;
354 : : }
355 : :
356 : 0 : static void master_free(struct snd_kcontrol *kcontrol)
357 : : {
358 : 0 : struct link_master *master = snd_kcontrol_chip(kcontrol);
359 : : struct link_slave *slave, *n;
360 : :
361 : : /* free all slave links and retore the original slave kctls */
362 [ # # ]: 0 : list_for_each_entry_safe(slave, n, &master->slaves, list) {
363 : 0 : struct snd_kcontrol *sctl = slave->kctl;
364 : 0 : struct list_head olist = sctl->list;
365 : 0 : memcpy(sctl, &slave->slave, sizeof(*sctl));
366 : 0 : memcpy(sctl->vd, slave->slave.vd,
367 : 0 : sctl->count * sizeof(*sctl->vd));
368 : 0 : sctl->list = olist; /* keep the current linked-list */
369 : 0 : kfree(slave);
370 : : }
371 : 0 : kfree(master);
372 : 0 : }
373 : :
374 : :
375 : : /**
376 : : * snd_ctl_make_virtual_master - Create a virtual master control
377 : : * @name: name string of the control element to create
378 : : * @tlv: optional TLV int array for dB information
379 : : *
380 : : * Creates a virtual master control with the given name string.
381 : : *
382 : : * After creating a vmaster element, you can add the slave controls
383 : : * via snd_ctl_add_slave() or snd_ctl_add_slave_uncached().
384 : : *
385 : : * The optional argument @tlv can be used to specify the TLV information
386 : : * for dB scale of the master control. It should be a single element
387 : : * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or
388 : : * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB.
389 : : *
390 : : * Return: The created control element, or %NULL for errors (ENOMEM).
391 : : */
392 : 0 : struct snd_kcontrol *snd_ctl_make_virtual_master(char *name,
393 : : const unsigned int *tlv)
394 : : {
395 : : struct link_master *master;
396 : : struct snd_kcontrol *kctl;
397 : : struct snd_kcontrol_new knew;
398 : :
399 : 0 : memset(&knew, 0, sizeof(knew));
400 : 0 : knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
401 : 0 : knew.name = name;
402 : 0 : knew.info = master_info;
403 : :
404 : : master = kzalloc(sizeof(*master), GFP_KERNEL);
405 [ # # ]: 0 : if (!master)
406 : : return NULL;
407 : 0 : INIT_LIST_HEAD(&master->slaves);
408 : :
409 : 0 : kctl = snd_ctl_new1(&knew, master);
410 [ # # ]: 0 : if (!kctl) {
411 : 0 : kfree(master);
412 : 0 : return NULL;
413 : : }
414 : : /* override some callbacks */
415 : 0 : kctl->info = master_info;
416 : 0 : kctl->get = master_get;
417 : 0 : kctl->put = master_put;
418 : 0 : kctl->private_free = master_free;
419 : :
420 : : /* additional (constant) TLV read */
421 [ # # ][ # # ]: 0 : if (tlv &&
422 : 0 : (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE ||
423 [ # # ]: 0 : tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX ||
424 : : tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) {
425 : 0 : kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
426 : 0 : memcpy(master->tlv, tlv, sizeof(master->tlv));
427 : 0 : kctl->tlv.p = master->tlv;
428 : : }
429 : :
430 : 0 : return kctl;
431 : : }
432 : : EXPORT_SYMBOL(snd_ctl_make_virtual_master);
433 : :
434 : : /**
435 : : * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control
436 : : * @kcontrol: vmaster kctl element
437 : : * @hook: the hook function
438 : : * @private_data: the private_data pointer to be saved
439 : : *
440 : : * Adds the given hook to the vmaster control element so that it's called
441 : : * at each time when the value is changed.
442 : : *
443 : : * Return: Zero.
444 : : */
445 : 0 : int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
446 : : void (*hook)(void *private_data, int),
447 : : void *private_data)
448 : : {
449 : 0 : struct link_master *master = snd_kcontrol_chip(kcontrol);
450 : 0 : master->hook = hook;
451 : 0 : master->hook_private_data = private_data;
452 : 0 : return 0;
453 : : }
454 : : EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
455 : :
456 : : /**
457 : : * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
458 : : * @kcontrol: vmaster kctl element
459 : : * @hook_only: sync only the hook
460 : : *
461 : : * Forcibly call the put callback of each slave and call the hook function
462 : : * to synchronize with the current value of the given vmaster element.
463 : : * NOP when NULL is passed to @kcontrol.
464 : : */
465 : 0 : void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
466 : : {
467 : : struct link_master *master;
468 : : bool first_init = false;
469 : :
470 [ # # ]: 0 : if (!kcontrol)
471 : : return;
472 : 0 : master = snd_kcontrol_chip(kcontrol);
473 [ # # ]: 0 : if (!hook_only) {
474 : 0 : int err = master_init(master);
475 [ # # ]: 0 : if (err < 0)
476 : : return;
477 : 0 : first_init = err;
478 : 0 : err = sync_slaves(master, master->val, master->val);
479 [ # # ]: 0 : if (err < 0)
480 : : return;
481 : : }
482 : :
483 [ # # ][ # # ]: 0 : if (master->hook && !first_init)
484 : 0 : master->hook(master->hook_private_data, master->val);
485 : : }
486 : : EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);
|