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