diff options
Diffstat (limited to 'sound/core/control.c')
-rw-r--r-- | sound/core/control.c | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index a08ad57c49b6..5d98194bcad5 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -366,6 +366,70 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
366 | EXPORT_SYMBOL(snd_ctl_add); | 366 | EXPORT_SYMBOL(snd_ctl_add); |
367 | 367 | ||
368 | /** | 368 | /** |
369 | * snd_ctl_replace - replace the control instance of the card | ||
370 | * @card: the card instance | ||
371 | * @kcontrol: the control instance to replace | ||
372 | * @add_on_replace: add the control if not already added | ||
373 | * | ||
374 | * Replaces the given control. If the given control does not exist | ||
375 | * and the add_on_replace flag is set, the control is added. If the | ||
376 | * control exists, it is destroyed first. | ||
377 | * | ||
378 | * Returns zero if successful, or a negative error code on failure. | ||
379 | * | ||
380 | * It frees automatically the control which cannot be added or replaced. | ||
381 | */ | ||
382 | int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, | ||
383 | bool add_on_replace) | ||
384 | { | ||
385 | struct snd_ctl_elem_id id; | ||
386 | unsigned int idx; | ||
387 | struct snd_kcontrol *old; | ||
388 | int ret; | ||
389 | |||
390 | if (!kcontrol) | ||
391 | return -EINVAL; | ||
392 | if (snd_BUG_ON(!card || !kcontrol->info)) { | ||
393 | ret = -EINVAL; | ||
394 | goto error; | ||
395 | } | ||
396 | id = kcontrol->id; | ||
397 | down_write(&card->controls_rwsem); | ||
398 | old = snd_ctl_find_id(card, &id); | ||
399 | if (!old) { | ||
400 | if (add_on_replace) | ||
401 | goto add; | ||
402 | up_write(&card->controls_rwsem); | ||
403 | ret = -EINVAL; | ||
404 | goto error; | ||
405 | } | ||
406 | ret = snd_ctl_remove(card, old); | ||
407 | if (ret < 0) { | ||
408 | up_write(&card->controls_rwsem); | ||
409 | goto error; | ||
410 | } | ||
411 | add: | ||
412 | if (snd_ctl_find_hole(card, kcontrol->count) < 0) { | ||
413 | up_write(&card->controls_rwsem); | ||
414 | ret = -ENOMEM; | ||
415 | goto error; | ||
416 | } | ||
417 | list_add_tail(&kcontrol->list, &card->controls); | ||
418 | card->controls_count += kcontrol->count; | ||
419 | kcontrol->id.numid = card->last_numid + 1; | ||
420 | card->last_numid += kcontrol->count; | ||
421 | up_write(&card->controls_rwsem); | ||
422 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | ||
423 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | ||
424 | return 0; | ||
425 | |||
426 | error: | ||
427 | snd_ctl_free_one(kcontrol); | ||
428 | return ret; | ||
429 | } | ||
430 | EXPORT_SYMBOL(snd_ctl_replace); | ||
431 | |||
432 | /** | ||
369 | * snd_ctl_remove - remove the control from the card and release it | 433 | * snd_ctl_remove - remove the control from the card and release it |
370 | * @card: the card instance | 434 | * @card: the card instance |
371 | * @kcontrol: the control instance to remove | 435 | * @kcontrol: the control instance to remove |