aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/control.c')
-rw-r--r--sound/core/control.c80
1 files changed, 45 insertions, 35 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 9aa15bfc7936..649d3217590e 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -348,6 +348,40 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
348 return 0; 348 return 0;
349} 349}
350 350
351/* add a new kcontrol object; call with card->controls_rwsem locked */
352static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
353{
354 struct snd_ctl_elem_id id;
355 unsigned int idx;
356 unsigned int count;
357
358 id = kcontrol->id;
359 if (id.index > UINT_MAX - kcontrol->count)
360 return -EINVAL;
361
362 if (snd_ctl_find_id(card, &id)) {
363 dev_err(card->dev,
364 "control %i:%i:%i:%s:%i is already present\n",
365 id.iface, id.device, id.subdevice, id.name, id.index);
366 return -EBUSY;
367 }
368
369 if (snd_ctl_find_hole(card, kcontrol->count) < 0)
370 return -ENOMEM;
371
372 list_add_tail(&kcontrol->list, &card->controls);
373 card->controls_count += kcontrol->count;
374 kcontrol->id.numid = card->last_numid + 1;
375 card->last_numid += kcontrol->count;
376
377 id = kcontrol->id;
378 count = kcontrol->count;
379 for (idx = 0; idx < count; idx++, id.index++, id.numid++)
380 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
381
382 return 0;
383}
384
351/** 385/**
352 * snd_ctl_add - add the control instance to the card 386 * snd_ctl_add - add the control instance to the card
353 * @card: the card instance 387 * @card: the card instance
@@ -364,45 +398,18 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
364 */ 398 */
365int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) 399int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
366{ 400{
367 struct snd_ctl_elem_id id;
368 unsigned int idx;
369 unsigned int count;
370 int err = -EINVAL; 401 int err = -EINVAL;
371 402
372 if (! kcontrol) 403 if (! kcontrol)
373 return err; 404 return err;
374 if (snd_BUG_ON(!card || !kcontrol->info)) 405 if (snd_BUG_ON(!card || !kcontrol->info))
375 goto error; 406 goto error;
376 id = kcontrol->id;
377 if (id.index > UINT_MAX - kcontrol->count)
378 goto error;
379 407
380 down_write(&card->controls_rwsem); 408 down_write(&card->controls_rwsem);
381 if (snd_ctl_find_id(card, &id)) { 409 err = __snd_ctl_add(card, kcontrol);
382 up_write(&card->controls_rwsem);
383 dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n",
384 id.iface,
385 id.device,
386 id.subdevice,
387 id.name,
388 id.index);
389 err = -EBUSY;
390 goto error;
391 }
392 if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
393 up_write(&card->controls_rwsem);
394 err = -ENOMEM;
395 goto error;
396 }
397 list_add_tail(&kcontrol->list, &card->controls);
398 card->controls_count += kcontrol->count;
399 kcontrol->id.numid = card->last_numid + 1;
400 card->last_numid += kcontrol->count;
401 id = kcontrol->id;
402 count = kcontrol->count;
403 up_write(&card->controls_rwsem); 410 up_write(&card->controls_rwsem);
404 for (idx = 0; idx < count; idx++, id.index++, id.numid++) 411 if (err < 0)
405 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); 412 goto error;
406 return 0; 413 return 0;
407 414
408 error: 415 error:
@@ -1361,9 +1368,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1361 kctl->tlv.c = snd_ctl_elem_user_tlv; 1368 kctl->tlv.c = snd_ctl_elem_user_tlv;
1362 1369
1363 /* This function manage to free the instance on failure. */ 1370 /* This function manage to free the instance on failure. */
1364 err = snd_ctl_add(card, kctl); 1371 down_write(&card->controls_rwsem);
1365 if (err < 0) 1372 err = __snd_ctl_add(card, kctl);
1366 return err; 1373 if (err < 0) {
1374 snd_ctl_free_one(kctl);
1375 goto unlock;
1376 }
1367 offset = snd_ctl_get_ioff(kctl, &info->id); 1377 offset = snd_ctl_get_ioff(kctl, &info->id);
1368 snd_ctl_build_ioff(&info->id, kctl, offset); 1378 snd_ctl_build_ioff(&info->id, kctl, offset);
1369 /* 1379 /*
@@ -1374,10 +1384,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1374 * which locks the element. 1384 * which locks the element.
1375 */ 1385 */
1376 1386
1377 down_write(&card->controls_rwsem);
1378 card->user_ctl_count++; 1387 card->user_ctl_count++;
1379 up_write(&card->controls_rwsem);
1380 1388
1389 unlock:
1390 up_write(&card->controls_rwsem);
1381 return 0; 1391 return 0;
1382} 1392}
1383 1393