Skip to content

Commit d043e1d

Browse files
marcanjannau
authored andcommitted
ALSA: control: Add kcontrol callbacks for lock/unlock
This allows drivers to implement policy around locking/unlocking controls, such as enforcing that a group of controls may only be locked by the same process/file, and taking actions when the controls lock/unlock (such as granting special access on lock and resetting values on unlock). This is, in particular, useful to implement volume safety controls, such that only a particular process (that locks controls and completes a handshake) may increase volumes above a given safe limit. It also allows the volume to be automatically lowered if that process dies (which will trigger an implicit unlock). Signed-off-by: Hector Martin <marcan@marcan.st>
1 parent 349da35 commit d043e1d

2 files changed

Lines changed: 21 additions & 2 deletions

File tree

include/sound/control.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
#define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data)
1515

1616
struct snd_kcontrol;
17+
struct snd_ctl_file;
1718
typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
1819
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
1920
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
21+
typedef int (snd_kcontrol_lock_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_file *owner);
22+
typedef void (snd_kcontrol_unlock_t) (struct snd_kcontrol * kcontrol);
2023
typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
2124
int op_flag, /* SNDRV_CTL_TLV_OP_XXX */
2225
unsigned int size,
@@ -55,6 +58,8 @@ struct snd_kcontrol_new {
5558
snd_kcontrol_info_t *info;
5659
snd_kcontrol_get_t *get;
5760
snd_kcontrol_put_t *put;
61+
snd_kcontrol_lock_t *lock;
62+
snd_kcontrol_unlock_t *unlock;
5863
union {
5964
snd_kcontrol_tlv_rw_t *c;
6065
const unsigned int *p;
@@ -74,6 +79,8 @@ struct snd_kcontrol {
7479
snd_kcontrol_info_t *info;
7580
snd_kcontrol_get_t *get;
7681
snd_kcontrol_put_t *put;
82+
snd_kcontrol_lock_t *lock;
83+
snd_kcontrol_unlock_t *unlock;
7784
union {
7885
snd_kcontrol_tlv_rw_t *c;
7986
const unsigned int *p;

sound/core/control.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,12 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
123123
scoped_guard(rwsem_write, &card->controls_rwsem) {
124124
list_for_each_entry(control, &card->controls, list)
125125
for (idx = 0; idx < control->count; idx++)
126-
if (control->vd[idx].owner == ctl)
126+
if (control->vd[idx].owner == ctl) {
127127
control->vd[idx].owner = NULL;
128+
if (control->unlock)
129+
control->unlock(control);
130+
}
128131
}
129-
130132
snd_fasync_free(ctl->fasync);
131133
snd_ctl_empty_read_queue(ctl);
132134
put_pid(ctl->pid);
@@ -303,6 +305,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
303305
kctl->info = ncontrol->info;
304306
kctl->get = ncontrol->get;
305307
kctl->put = ncontrol->put;
308+
kctl->lock = ncontrol->lock;
309+
kctl->unlock = ncontrol->unlock;
306310
kctl->tlv.p = ncontrol->tlv.p;
307311

308312
kctl->private_value = ncontrol->private_value;
@@ -1359,6 +1363,12 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
13591363
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
13601364
if (vd->owner)
13611365
return -EBUSY;
1366+
1367+
if (kctl->lock) {
1368+
int err = kctl->lock(kctl, file);
1369+
if (err < 0)
1370+
return err;
1371+
}
13621372
vd->owner = file;
13631373
return 0;
13641374
}
@@ -1383,6 +1393,8 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
13831393
if (vd->owner != file)
13841394
return -EPERM;
13851395
vd->owner = NULL;
1396+
if (kctl->unlock)
1397+
kctl->unlock(kctl);
13861398
return 0;
13871399
}
13881400

0 commit comments

Comments
 (0)