diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-11-10 06:34:24 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-11-10 06:34:24 -0500 |
commit | 9e226b4b7e77215ca70461edc33800f6c1ba63d3 (patch) | |
tree | 386ce06a62a0ad58240fed3e8e023848c6a26925 /sound/core | |
parent | aeb4b88ec0a948efce8e3a23a8f964d3560a7308 (diff) |
ALSA: vmaster - Free slave-links when freeing the master element
When freeing the vmaster master element, we should release slave-links
properly, not only assumig that slaves will be freed soon later.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/vmaster.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 5dbab38d04af..130cfe677d60 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c | |||
@@ -52,6 +52,7 @@ struct link_slave { | |||
52 | struct link_ctl_info info; | 52 | struct link_ctl_info info; |
53 | int vals[2]; /* current values */ | 53 | int vals[2]; /* current values */ |
54 | unsigned int flags; | 54 | unsigned int flags; |
55 | struct snd_kcontrol *kctl; /* original kcontrol pointer */ | ||
55 | struct snd_kcontrol slave; /* the copy of original control entry */ | 56 | struct snd_kcontrol slave; /* the copy of original control entry */ |
56 | }; | 57 | }; |
57 | 58 | ||
@@ -252,6 +253,7 @@ int _snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave, | |||
252 | slave->count * sizeof(*slave->vd), GFP_KERNEL); | 253 | slave->count * sizeof(*slave->vd), GFP_KERNEL); |
253 | if (!srec) | 254 | if (!srec) |
254 | return -ENOMEM; | 255 | return -ENOMEM; |
256 | srec->kctl = slave; | ||
255 | srec->slave = *slave; | 257 | srec->slave = *slave; |
256 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); | 258 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); |
257 | srec->master = master_link; | 259 | srec->master = master_link; |
@@ -333,10 +335,18 @@ static int master_put(struct snd_kcontrol *kcontrol, | |||
333 | static void master_free(struct snd_kcontrol *kcontrol) | 335 | static void master_free(struct snd_kcontrol *kcontrol) |
334 | { | 336 | { |
335 | struct link_master *master = snd_kcontrol_chip(kcontrol); | 337 | struct link_master *master = snd_kcontrol_chip(kcontrol); |
336 | struct link_slave *slave; | 338 | struct link_slave *slave, *n; |
337 | 339 | ||
338 | list_for_each_entry(slave, &master->slaves, list) | 340 | /* free all slave links and retore the original slave kctls */ |
339 | slave->master = NULL; | 341 | list_for_each_entry_safe(slave, n, &master->slaves, list) { |
342 | struct snd_kcontrol *sctl = slave->kctl; | ||
343 | struct list_head olist = sctl->list; | ||
344 | memcpy(sctl, &slave->slave, sizeof(*sctl)); | ||
345 | memcpy(sctl->vd, slave->slave.vd, | ||
346 | sctl->count * sizeof(*sctl->vd)); | ||
347 | sctl->list = olist; /* keep the current linked-list */ | ||
348 | kfree(slave); | ||
349 | } | ||
340 | kfree(master); | 350 | kfree(master); |
341 | } | 351 | } |
342 | 352 | ||