aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/control.c
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2015-04-11 21:12:25 -0400
committerTakashi Iwai <tiwai@suse.de>2015-04-13 04:31:49 -0400
commite1c78df1da112f2644058af2425dd5ca3eb1a96a (patch)
treeab5df7d5a9e38ec5054820575a84a4dd6e5d35f4 /sound/core/control.c
parent9a4f35865ffcb2f4603375eadabe0d475fab1a0f (diff)
ALSA: ctl: fix to handle several elements added by one operation for userspace element
An element instance can have several elements with the same feature. Some userspace applications can add such an element instance by add operation with the number of elements. Then, the element instance gets a memory object to keep states of these elements. But the element instance has just one memory object for the elements. This causes the same result to each read/write operations to the different elements. This commit fixes this bug by allocating enough memory objects to the element instance for each of elements. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/control.c')
-rw-r--r--sound/core/control.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index be5b97cd8dc3..196a6fe100ca 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1029,7 +1029,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
1029struct user_element { 1029struct user_element {
1030 struct snd_ctl_elem_info info; 1030 struct snd_ctl_elem_info info;
1031 struct snd_card *card; 1031 struct snd_card *card;
1032 void *elem_data; /* element data */ 1032 char *elem_data; /* element data */
1033 unsigned long elem_data_size; /* size of element data in bytes */ 1033 unsigned long elem_data_size; /* size of element data in bytes */
1034 void *tlv_data; /* TLV data */ 1034 void *tlv_data; /* TLV data */
1035 unsigned long tlv_data_size; /* TLV data size */ 1035 unsigned long tlv_data_size; /* TLV data size */
@@ -1078,9 +1078,12 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
1078 struct snd_ctl_elem_value *ucontrol) 1078 struct snd_ctl_elem_value *ucontrol)
1079{ 1079{
1080 struct user_element *ue = kcontrol->private_data; 1080 struct user_element *ue = kcontrol->private_data;
1081 unsigned int size = ue->elem_data_size;
1082 char *src = ue->elem_data +
1083 snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
1081 1084
1082 mutex_lock(&ue->card->user_ctl_lock); 1085 mutex_lock(&ue->card->user_ctl_lock);
1083 memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); 1086 memcpy(&ucontrol->value, src, size);
1084 mutex_unlock(&ue->card->user_ctl_lock); 1087 mutex_unlock(&ue->card->user_ctl_lock);
1085 return 0; 1088 return 0;
1086} 1089}
@@ -1090,11 +1093,14 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
1090{ 1093{
1091 int change; 1094 int change;
1092 struct user_element *ue = kcontrol->private_data; 1095 struct user_element *ue = kcontrol->private_data;
1096 unsigned int size = ue->elem_data_size;
1097 char *dst = ue->elem_data +
1098 snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
1093 1099
1094 mutex_lock(&ue->card->user_ctl_lock); 1100 mutex_lock(&ue->card->user_ctl_lock);
1095 change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; 1101 change = memcmp(&ucontrol->value, dst, size) != 0;
1096 if (change) 1102 if (change)
1097 memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); 1103 memcpy(dst, &ucontrol->value, size);
1098 mutex_unlock(&ue->card->user_ctl_lock); 1104 mutex_unlock(&ue->card->user_ctl_lock);
1099 return change; 1105 return change;
1100} 1106}
@@ -1278,7 +1284,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1278 if (err < 0) 1284 if (err < 0)
1279 return err; 1285 return err;
1280 memcpy(&kctl->id, &info->id, sizeof(kctl->id)); 1286 memcpy(&kctl->id, &info->id, sizeof(kctl->id));
1281 kctl->private_data = kzalloc(sizeof(struct user_element) + private_size, 1287 kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count,
1282 GFP_KERNEL); 1288 GFP_KERNEL);
1283 if (kctl->private_data == NULL) { 1289 if (kctl->private_data == NULL) {
1284 kfree(kctl); 1290 kfree(kctl);