1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Virtual master and follower 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 follower 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 followers. 30 */ 31 struct link_master { 32 struct list_head followers; 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 follower - this contains a follower control element 42 * 43 * It fakes the control callbacks with additional attenuation by the 44 * master control. A follower may have either one or two channels. 45 */ 46 47 struct link_follower { 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 follower; /* the copy of original control entry */ 55 }; 56 57 static int follower_update(struct link_follower *follower) 58 { 59 struct snd_ctl_elem_value *uctl __free(kfree) = NULL; 60 int err, ch; 61 62 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); 63 if (!uctl) 64 return -ENOMEM; 65 uctl->id = follower->follower.id; 66 err = follower->follower.get(&follower->follower, uctl); 67 if (err < 0) 68 return err; 69 for (ch = 0; ch < follower->info.count; ch++) 70 follower->vals[ch] = uctl->value.integer.value[ch]; 71 return 0; 72 } 73 74 /* get the follower ctl info and save the initial values */ 75 static int follower_init(struct link_follower *follower) 76 { 77 struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; 78 int err; 79 80 if (follower->info.count) { 81 /* already initialized */ 82 if (follower->flags & SND_CTL_FOLLOWER_NEED_UPDATE) 83 return follower_update(follower); 84 return 0; 85 } 86 87 uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); 88 if (!uinfo) 89 return -ENOMEM; 90 uinfo->id = follower->follower.id; 91 err = follower->follower.info(&follower->follower, uinfo); 92 if (err < 0) 93 return err; 94 follower->info.type = uinfo->type; 95 follower->info.count = uinfo->count; 96 if (follower->info.count > 2 || 97 (follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER && 98 follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) { 99 pr_err("ALSA: vmaster: invalid follower element\n"); 100 return -EINVAL; 101 } 102 follower->info.min_val = uinfo->value.integer.min; 103 follower->info.max_val = uinfo->value.integer.max; 104 105 return follower_update(follower); 106 } 107 108 /* initialize master volume */ 109 static int master_init(struct link_master *master) 110 { 111 struct link_follower *follower; 112 113 if (master->info.count) 114 return 0; /* already initialized */ 115 116 list_for_each_entry(follower, &master->followers, list) { 117 int err = follower_init(follower); 118 if (err < 0) 119 return err; 120 master->info = follower->info; 121 master->info.count = 1; /* always mono */ 122 /* set full volume as default (= no attenuation) */ 123 master->val = master->info.max_val; 124 if (master->hook) 125 master->hook(master->hook_private_data, master->val); 126 return 1; 127 } 128 return -ENOENT; 129 } 130 131 static int follower_get_val(struct link_follower *follower, 132 struct snd_ctl_elem_value *ucontrol) 133 { 134 int err, ch; 135 136 err = follower_init(follower); 137 if (err < 0) 138 return err; 139 for (ch = 0; ch < follower->info.count; ch++) 140 ucontrol->value.integer.value[ch] = follower->vals[ch]; 141 return 0; 142 } 143 144 static int follower_put_val(struct link_follower *follower, 145 struct snd_ctl_elem_value *ucontrol) 146 { 147 int err, ch, vol; 148 149 err = master_init(follower->master); 150 if (err < 0) 151 return err; 152 153 switch (follower->info.type) { 154 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 155 for (ch = 0; ch < follower->info.count; ch++) 156 ucontrol->value.integer.value[ch] &= 157 !!follower->master->val; 158 break; 159 case SNDRV_CTL_ELEM_TYPE_INTEGER: 160 for (ch = 0; ch < follower->info.count; ch++) { 161 /* max master volume is supposed to be 0 dB */ 162 vol = ucontrol->value.integer.value[ch]; 163 vol += follower->master->val - follower->master->info.max_val; 164 if (vol < follower->info.min_val) 165 vol = follower->info.min_val; 166 else if (vol > follower->info.max_val) 167 vol = follower->info.max_val; 168 ucontrol->value.integer.value[ch] = vol; 169 } 170 break; 171 } 172 return follower->follower.put(&follower->follower, ucontrol); 173 } 174 175 /* 176 * ctl callbacks for followers 177 */ 178 static int follower_info(struct snd_kcontrol *kcontrol, 179 struct snd_ctl_elem_info *uinfo) 180 { 181 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 182 return follower->follower.info(&follower->follower, uinfo); 183 } 184 185 static int follower_get(struct snd_kcontrol *kcontrol, 186 struct snd_ctl_elem_value *ucontrol) 187 { 188 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 189 return follower_get_val(follower, ucontrol); 190 } 191 192 static int follower_put(struct snd_kcontrol *kcontrol, 193 struct snd_ctl_elem_value *ucontrol) 194 { 195 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 196 int err, ch, changed = 0; 197 198 err = follower_init(follower); 199 if (err < 0) 200 return err; 201 for (ch = 0; ch < follower->info.count; ch++) { 202 if (ucontrol->value.integer.value[ch] < follower->info.min_val || 203 ucontrol->value.integer.value[ch] > follower->info.max_val) 204 return -EINVAL; 205 } 206 207 for (ch = 0; ch < follower->info.count; ch++) { 208 if (follower->vals[ch] != ucontrol->value.integer.value[ch]) { 209 changed = 1; 210 follower->vals[ch] = ucontrol->value.integer.value[ch]; 211 } 212 } 213 if (!changed) 214 return 0; 215 err = follower_put_val(follower, ucontrol); 216 if (err < 0) 217 return err; 218 return 1; 219 } 220 221 static int follower_tlv_cmd(struct snd_kcontrol *kcontrol, 222 int op_flag, unsigned int size, 223 unsigned int __user *tlv) 224 { 225 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 226 /* FIXME: this assumes that the max volume is 0 dB */ 227 return follower->follower.tlv.c(&follower->follower, op_flag, size, tlv); 228 } 229 230 static void follower_free(struct snd_kcontrol *kcontrol) 231 { 232 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 233 if (follower->follower.private_free) 234 follower->follower.private_free(&follower->follower); 235 if (follower->master) 236 list_del(&follower->list); 237 kfree(follower); 238 } 239 240 /* 241 * Add a follower control to the group with the given master control 242 * 243 * All followers 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 int _snd_ctl_add_follower(struct snd_kcontrol *master, 253 struct snd_kcontrol *follower, 254 unsigned int flags) 255 { 256 struct link_master *master_link = snd_kcontrol_chip(master); 257 struct link_follower *srec; 258 259 srec = kzalloc(struct_size(srec, follower.vd, follower->count), 260 GFP_KERNEL); 261 if (!srec) 262 return -ENOMEM; 263 srec->kctl = follower; 264 srec->follower = *follower; 265 memcpy(srec->follower.vd, follower->vd, follower->count * sizeof(*follower->vd)); 266 srec->master = master_link; 267 srec->flags = flags; 268 269 /* override callbacks */ 270 follower->info = follower_info; 271 follower->get = follower_get; 272 follower->put = follower_put; 273 if (follower->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) 274 follower->tlv.c = follower_tlv_cmd; 275 follower->private_data = srec; 276 follower->private_free = follower_free; 277 278 list_add_tail(&srec->list, &master_link->followers); 279 return 0; 280 } 281 EXPORT_SYMBOL(_snd_ctl_add_follower); 282 283 /** 284 * snd_ctl_add_followers - add multiple followers to vmaster 285 * @card: card instance 286 * @master: the target vmaster kcontrol object 287 * @list: NULL-terminated list of name strings of followers to be added 288 * 289 * Adds the multiple follower kcontrols with the given names. 290 * Returns 0 for success or a negative error code. 291 */ 292 int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master, 293 const char * const *list) 294 { 295 struct snd_kcontrol *follower; 296 int err; 297 298 for (; *list; list++) { 299 follower = snd_ctl_find_id_mixer(card, *list); 300 if (follower) { 301 err = snd_ctl_add_follower(master, follower); 302 if (err < 0) 303 return err; 304 } 305 } 306 307 return 0; 308 } 309 EXPORT_SYMBOL_GPL(snd_ctl_add_followers); 310 311 /* 312 * ctl callbacks for master controls 313 */ 314 static int master_info(struct snd_kcontrol *kcontrol, 315 struct snd_ctl_elem_info *uinfo) 316 { 317 struct link_master *master = snd_kcontrol_chip(kcontrol); 318 int ret; 319 320 ret = master_init(master); 321 if (ret < 0) 322 return ret; 323 uinfo->type = master->info.type; 324 uinfo->count = master->info.count; 325 uinfo->value.integer.min = master->info.min_val; 326 uinfo->value.integer.max = master->info.max_val; 327 return 0; 328 } 329 330 static int master_get(struct snd_kcontrol *kcontrol, 331 struct snd_ctl_elem_value *ucontrol) 332 { 333 struct link_master *master = snd_kcontrol_chip(kcontrol); 334 int err = master_init(master); 335 if (err < 0) 336 return err; 337 ucontrol->value.integer.value[0] = master->val; 338 return 0; 339 } 340 341 static int sync_followers(struct link_master *master, int old_val, int new_val) 342 { 343 struct link_follower *follower; 344 struct snd_ctl_elem_value *uval __free(kfree) = NULL; 345 346 uval = kmalloc(sizeof(*uval), GFP_KERNEL); 347 if (!uval) 348 return -ENOMEM; 349 list_for_each_entry(follower, &master->followers, list) { 350 master->val = old_val; 351 uval->id = follower->follower.id; 352 follower_get_val(follower, uval); 353 master->val = new_val; 354 follower_put_val(follower, uval); 355 } 356 return 0; 357 } 358 359 static int master_put(struct snd_kcontrol *kcontrol, 360 struct snd_ctl_elem_value *ucontrol) 361 { 362 struct link_master *master = snd_kcontrol_chip(kcontrol); 363 int err, new_val, old_val; 364 bool first_init; 365 366 err = master_init(master); 367 if (err < 0) 368 return err; 369 first_init = err; 370 old_val = master->val; 371 new_val = ucontrol->value.integer.value[0]; 372 if (new_val == old_val) 373 return 0; 374 if (new_val < master->info.min_val || new_val > master->info.max_val) 375 return -EINVAL; 376 377 err = sync_followers(master, old_val, new_val); 378 if (err < 0) 379 return err; 380 if (master->hook && !first_init) 381 master->hook(master->hook_private_data, master->val); 382 return 1; 383 } 384 385 static void master_free(struct snd_kcontrol *kcontrol) 386 { 387 struct link_master *master = snd_kcontrol_chip(kcontrol); 388 struct link_follower *follower, *n; 389 390 /* free all follower links and retore the original follower kctls */ 391 list_for_each_entry_safe(follower, n, &master->followers, list) { 392 struct snd_kcontrol *sctl = follower->kctl; 393 struct list_head olist = sctl->list; 394 memcpy(sctl, &follower->follower, sizeof(*sctl)); 395 memcpy(sctl->vd, follower->follower.vd, 396 sctl->count * sizeof(*sctl->vd)); 397 sctl->list = olist; /* keep the current linked-list */ 398 kfree(follower); 399 } 400 kfree(master); 401 } 402 403 404 /** 405 * snd_ctl_make_virtual_master - Create a virtual master control 406 * @name: name string of the control element to create 407 * @tlv: optional TLV int array for dB information 408 * 409 * Creates a virtual master control with the given name string. 410 * 411 * After creating a vmaster element, you can add the follower controls 412 * via snd_ctl_add_follower() or snd_ctl_add_follower_uncached(). 413 * 414 * The optional argument @tlv can be used to specify the TLV information 415 * for dB scale of the master control. It should be a single element 416 * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or 417 * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB. 418 * 419 * Return: The created control element, or %NULL for errors (ENOMEM). 420 */ 421 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, 422 const unsigned int *tlv) 423 { 424 struct link_master *master; 425 struct snd_kcontrol *kctl; 426 struct snd_kcontrol_new knew; 427 428 memset(&knew, 0, sizeof(knew)); 429 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 430 knew.name = name; 431 knew.info = master_info; 432 433 master = kzalloc(sizeof(*master), GFP_KERNEL); 434 if (!master) 435 return NULL; 436 INIT_LIST_HEAD(&master->followers); 437 438 kctl = snd_ctl_new1(&knew, master); 439 if (!kctl) { 440 kfree(master); 441 return NULL; 442 } 443 /* override some callbacks */ 444 kctl->info = master_info; 445 kctl->get = master_get; 446 kctl->put = master_put; 447 kctl->private_free = master_free; 448 449 /* additional (constant) TLV read */ 450 if (tlv) { 451 unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; 452 if (type == SNDRV_CTL_TLVT_DB_SCALE || 453 type == SNDRV_CTL_TLVT_DB_MINMAX || 454 type == SNDRV_CTL_TLVT_DB_MINMAX_MUTE) { 455 kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 456 memcpy(master->tlv, tlv, sizeof(master->tlv)); 457 kctl->tlv.p = master->tlv; 458 } 459 } 460 461 return kctl; 462 } 463 EXPORT_SYMBOL(snd_ctl_make_virtual_master); 464 465 /** 466 * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control 467 * @kcontrol: vmaster kctl element 468 * @hook: the hook function 469 * @private_data: the private_data pointer to be saved 470 * 471 * Adds the given hook to the vmaster control element so that it's called 472 * at each time when the value is changed. 473 * 474 * Return: Zero. 475 */ 476 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, 477 void (*hook)(void *private_data, int), 478 void *private_data) 479 { 480 struct link_master *master = snd_kcontrol_chip(kcontrol); 481 master->hook = hook; 482 master->hook_private_data = private_data; 483 return 0; 484 } 485 EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook); 486 487 /** 488 * snd_ctl_sync_vmaster - Sync the vmaster followers and hook 489 * @kcontrol: vmaster kctl element 490 * @hook_only: sync only the hook 491 * 492 * Forcibly call the put callback of each follower and call the hook function 493 * to synchronize with the current value of the given vmaster element. 494 * NOP when NULL is passed to @kcontrol. 495 */ 496 void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only) 497 { 498 struct link_master *master; 499 bool first_init = false; 500 501 if (!kcontrol) 502 return; 503 master = snd_kcontrol_chip(kcontrol); 504 if (!hook_only) { 505 int err = master_init(master); 506 if (err < 0) 507 return; 508 first_init = err; 509 err = sync_followers(master, master->val, master->val); 510 if (err < 0) 511 return; 512 } 513 514 if (master->hook && !first_init) 515 master->hook(master->hook_private_data, master->val); 516 } 517 EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); 518 519 /** 520 * snd_ctl_apply_vmaster_followers - Apply function to each vmaster follower 521 * @kctl: vmaster kctl element 522 * @func: function to apply 523 * @arg: optional function argument 524 * 525 * Apply the function @func to each follower kctl of the given vmaster kctl. 526 * 527 * Return: 0 if successful, or a negative error code 528 */ 529 int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl, 530 int (*func)(struct snd_kcontrol *vfollower, 531 struct snd_kcontrol *follower, 532 void *arg), 533 void *arg) 534 { 535 struct link_master *master; 536 struct link_follower *follower; 537 int err; 538 539 master = snd_kcontrol_chip(kctl); 540 err = master_init(master); 541 if (err < 0) 542 return err; 543 list_for_each_entry(follower, &master->followers, list) { 544 err = func(follower->kctl, &follower->follower, arg); 545 if (err < 0) 546 return err; 547 } 548 549 return 0; 550 } 551 EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_followers); 552