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);