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 (follower->vals[ch] != ucontrol->value.integer.value[ch]) { 203 changed = 1; 204 follower->vals[ch] = ucontrol->value.integer.value[ch]; 205 } 206 } 207 if (!changed) 208 return 0; 209 err = follower_put_val(follower, ucontrol); 210 if (err < 0) 211 return err; 212 return 1; 213 } 214 215 static int follower_tlv_cmd(struct snd_kcontrol *kcontrol, 216 int op_flag, unsigned int size, 217 unsigned int __user *tlv) 218 { 219 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 220 /* FIXME: this assumes that the max volume is 0 dB */ 221 return follower->follower.tlv.c(&follower->follower, op_flag, size, tlv); 222 } 223 224 static void follower_free(struct snd_kcontrol *kcontrol) 225 { 226 struct link_follower *follower = snd_kcontrol_chip(kcontrol); 227 if (follower->follower.private_free) 228 follower->follower.private_free(&follower->follower); 229 if (follower->master) 230 list_del(&follower->list); 231 kfree(follower); 232 } 233 234 /* 235 * Add a follower control to the group with the given master control 236 * 237 * All followers must be the same type (returning the same information 238 * via info callback). The function doesn't check it, so it's your 239 * responsibility. 240 * 241 * Also, some additional limitations: 242 * - at most two channels 243 * - logarithmic volume control (dB level), no linear volume 244 * - master can only attenuate the volume, no gain 245 */ 246 int _snd_ctl_add_follower(struct snd_kcontrol *master, 247 struct snd_kcontrol *follower, 248 unsigned int flags) 249 { 250 struct link_master *master_link = snd_kcontrol_chip(master); 251 struct link_follower *srec; 252 253 srec = kzalloc(struct_size(srec, follower.vd, follower->count), 254 GFP_KERNEL); 255 if (!srec) 256 return -ENOMEM; 257 srec->kctl = follower; 258 srec->follower = *follower; 259 memcpy(srec->follower.vd, follower->vd, follower->count * sizeof(*follower->vd)); 260 srec->master = master_link; 261 srec->flags = flags; 262 263 /* override callbacks */ 264 follower->info = follower_info; 265 follower->get = follower_get; 266 follower->put = follower_put; 267 if (follower->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) 268 follower->tlv.c = follower_tlv_cmd; 269 follower->private_data = srec; 270 follower->private_free = follower_free; 271 272 list_add_tail(&srec->list, &master_link->followers); 273 return 0; 274 } 275 EXPORT_SYMBOL(_snd_ctl_add_follower); 276 277 /** 278 * snd_ctl_add_followers - add multiple followers to vmaster 279 * @card: card instance 280 * @master: the target vmaster kcontrol object 281 * @list: NULL-terminated list of name strings of followers to be added 282 * 283 * Adds the multiple follower kcontrols with the given names. 284 * Returns 0 for success or a negative error code. 285 */ 286 int snd_ctl_add_followers(struct snd_card *card, struct snd_kcontrol *master, 287 const char * const *list) 288 { 289 struct snd_kcontrol *follower; 290 int err; 291 292 for (; *list; list++) { 293 follower = snd_ctl_find_id_mixer(card, *list); 294 if (follower) { 295 err = snd_ctl_add_follower(master, follower); 296 if (err < 0) 297 return err; 298 } 299 } 300 301 return 0; 302 } 303 EXPORT_SYMBOL_GPL(snd_ctl_add_followers); 304 305 /* 306 * ctl callbacks for master controls 307 */ 308 static int master_info(struct snd_kcontrol *kcontrol, 309 struct snd_ctl_elem_info *uinfo) 310 { 311 struct link_master *master = snd_kcontrol_chip(kcontrol); 312 int ret; 313 314 ret = master_init(master); 315 if (ret < 0) 316 return ret; 317 uinfo->type = master->info.type; 318 uinfo->count = master->info.count; 319 uinfo->value.integer.min = master->info.min_val; 320 uinfo->value.integer.max = master->info.max_val; 321 return 0; 322 } 323 324 static int master_get(struct snd_kcontrol *kcontrol, 325 struct snd_ctl_elem_value *ucontrol) 326 { 327 struct link_master *master = snd_kcontrol_chip(kcontrol); 328 int err = master_init(master); 329 if (err < 0) 330 return err; 331 ucontrol->value.integer.value[0] = master->val; 332 return 0; 333 } 334 335 static int sync_followers(struct link_master *master, int old_val, int new_val) 336 { 337 struct link_follower *follower; 338 struct snd_ctl_elem_value *uval __free(kfree) = NULL; 339 340 uval = kmalloc(sizeof(*uval), GFP_KERNEL); 341 if (!uval) 342 return -ENOMEM; 343 list_for_each_entry(follower, &master->followers, list) { 344 master->val = old_val; 345 uval->id = follower->follower.id; 346 follower_get_val(follower, uval); 347 master->val = new_val; 348 follower_put_val(follower, uval); 349 } 350 return 0; 351 } 352 353 static int master_put(struct snd_kcontrol *kcontrol, 354 struct snd_ctl_elem_value *ucontrol) 355 { 356 struct link_master *master = snd_kcontrol_chip(kcontrol); 357 int err, new_val, old_val; 358 bool first_init; 359 360 err = master_init(master); 361 if (err < 0) 362 return err; 363 first_init = err; 364 old_val = master->val; 365 new_val = ucontrol->value.integer.value[0]; 366 if (new_val == old_val) 367 return 0; 368 369 err = sync_followers(master, old_val, new_val); 370 if (err < 0) 371 return err; 372 if (master->hook && !first_init) 373 master->hook(master->hook_private_data, master->val); 374 return 1; 375 } 376 377 static void master_free(struct snd_kcontrol *kcontrol) 378 { 379 struct link_master *master = snd_kcontrol_chip(kcontrol); 380 struct link_follower *follower, *n; 381 382 /* free all follower links and retore the original follower kctls */ 383 list_for_each_entry_safe(follower, n, &master->followers, list) { 384 struct snd_kcontrol *sctl = follower->kctl; 385 struct list_head olist = sctl->list; 386 memcpy(sctl, &follower->follower, sizeof(*sctl)); 387 memcpy(sctl->vd, follower->follower.vd, 388 sctl->count * sizeof(*sctl->vd)); 389 sctl->list = olist; /* keep the current linked-list */ 390 kfree(follower); 391 } 392 kfree(master); 393 } 394 395 396 /** 397 * snd_ctl_make_virtual_master - Create a virtual master control 398 * @name: name string of the control element to create 399 * @tlv: optional TLV int array for dB information 400 * 401 * Creates a virtual master control with the given name string. 402 * 403 * After creating a vmaster element, you can add the follower controls 404 * via snd_ctl_add_follower() or snd_ctl_add_follower_uncached(). 405 * 406 * The optional argument @tlv can be used to specify the TLV information 407 * for dB scale of the master control. It should be a single element 408 * with #SNDRV_CTL_TLVT_DB_SCALE, #SNDRV_CTL_TLV_DB_MINMAX or 409 * #SNDRV_CTL_TLVT_DB_MINMAX_MUTE type, and should be the max 0dB. 410 * 411 * Return: The created control element, or %NULL for errors (ENOMEM). 412 */ 413 struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, 414 const unsigned int *tlv) 415 { 416 struct link_master *master; 417 struct snd_kcontrol *kctl; 418 struct snd_kcontrol_new knew; 419 420 memset(&knew, 0, sizeof(knew)); 421 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 422 knew.name = name; 423 knew.info = master_info; 424 425 master = kzalloc(sizeof(*master), GFP_KERNEL); 426 if (!master) 427 return NULL; 428 INIT_LIST_HEAD(&master->followers); 429 430 kctl = snd_ctl_new1(&knew, master); 431 if (!kctl) { 432 kfree(master); 433 return NULL; 434 } 435 /* override some callbacks */ 436 kctl->info = master_info; 437 kctl->get = master_get; 438 kctl->put = master_put; 439 kctl->private_free = master_free; 440 441 /* additional (constant) TLV read */ 442 if (tlv) { 443 unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; 444 if (type == SNDRV_CTL_TLVT_DB_SCALE || 445 type == SNDRV_CTL_TLVT_DB_MINMAX || 446 type == SNDRV_CTL_TLVT_DB_MINMAX_MUTE) { 447 kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; 448 memcpy(master->tlv, tlv, sizeof(master->tlv)); 449 kctl->tlv.p = master->tlv; 450 } 451 } 452 453 return kctl; 454 } 455 EXPORT_SYMBOL(snd_ctl_make_virtual_master); 456 457 /** 458 * snd_ctl_add_vmaster_hook - Add a hook to a vmaster control 459 * @kcontrol: vmaster kctl element 460 * @hook: the hook function 461 * @private_data: the private_data pointer to be saved 462 * 463 * Adds the given hook to the vmaster control element so that it's called 464 * at each time when the value is changed. 465 * 466 * Return: Zero. 467 */ 468 int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol, 469 void (*hook)(void *private_data, int), 470 void *private_data) 471 { 472 struct link_master *master = snd_kcontrol_chip(kcontrol); 473 master->hook = hook; 474 master->hook_private_data = private_data; 475 return 0; 476 } 477 EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook); 478 479 /** 480 * snd_ctl_sync_vmaster - Sync the vmaster followers and hook 481 * @kcontrol: vmaster kctl element 482 * @hook_only: sync only the hook 483 * 484 * Forcibly call the put callback of each follower and call the hook function 485 * to synchronize with the current value of the given vmaster element. 486 * NOP when NULL is passed to @kcontrol. 487 */ 488 void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only) 489 { 490 struct link_master *master; 491 bool first_init = false; 492 493 if (!kcontrol) 494 return; 495 master = snd_kcontrol_chip(kcontrol); 496 if (!hook_only) { 497 int err = master_init(master); 498 if (err < 0) 499 return; 500 first_init = err; 501 err = sync_followers(master, master->val, master->val); 502 if (err < 0) 503 return; 504 } 505 506 if (master->hook && !first_init) 507 master->hook(master->hook_private_data, master->val); 508 } 509 EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster); 510 511 /** 512 * snd_ctl_apply_vmaster_followers - Apply function to each vmaster follower 513 * @kctl: vmaster kctl element 514 * @func: function to apply 515 * @arg: optional function argument 516 * 517 * Apply the function @func to each follower kctl of the given vmaster kctl. 518 * 519 * Return: 0 if successful, or a negative error code 520 */ 521 int snd_ctl_apply_vmaster_followers(struct snd_kcontrol *kctl, 522 int (*func)(struct snd_kcontrol *vfollower, 523 struct snd_kcontrol *follower, 524 void *arg), 525 void *arg) 526 { 527 struct link_master *master; 528 struct link_follower *follower; 529 int err; 530 531 master = snd_kcontrol_chip(kctl); 532 err = master_init(master); 533 if (err < 0) 534 return err; 535 list_for_each_entry(follower, &master->followers, list) { 536 err = func(follower->kctl, &follower->follower, arg); 537 if (err < 0) 538 return err; 539 } 540 541 return 0; 542 } 543 EXPORT_SYMBOL_GPL(snd_ctl_apply_vmaster_followers); 544