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.c78
1 files changed, 51 insertions, 27 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index f038f5afafe2..f0b0e14497a5 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
288{ 288{
289 struct snd_kcontrol *kctl; 289 struct snd_kcontrol *kctl;
290 290
291 /* Make sure that the ids assigned to the control do not wrap around */
292 if (card->last_numid >= UINT_MAX - count)
293 card->last_numid = 0;
294
291 list_for_each_entry(kctl, &card->controls, list) { 295 list_for_each_entry(kctl, &card->controls, list) {
292 if (kctl->id.numid < card->last_numid + 1 + count && 296 if (kctl->id.numid < card->last_numid + 1 + count &&
293 kctl->id.numid + kctl->count > card->last_numid + 1) { 297 kctl->id.numid + kctl->count > card->last_numid + 1) {
@@ -330,6 +334,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
330{ 334{
331 struct snd_ctl_elem_id id; 335 struct snd_ctl_elem_id id;
332 unsigned int idx; 336 unsigned int idx;
337 unsigned int count;
333 int err = -EINVAL; 338 int err = -EINVAL;
334 339
335 if (! kcontrol) 340 if (! kcontrol)
@@ -337,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
337 if (snd_BUG_ON(!card || !kcontrol->info)) 342 if (snd_BUG_ON(!card || !kcontrol->info))
338 goto error; 343 goto error;
339 id = kcontrol->id; 344 id = kcontrol->id;
345 if (id.index > UINT_MAX - kcontrol->count)
346 goto error;
347
340 down_write(&card->controls_rwsem); 348 down_write(&card->controls_rwsem);
341 if (snd_ctl_find_id(card, &id)) { 349 if (snd_ctl_find_id(card, &id)) {
342 up_write(&card->controls_rwsem); 350 up_write(&card->controls_rwsem);
@@ -358,8 +366,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
358 card->controls_count += kcontrol->count; 366 card->controls_count += kcontrol->count;
359 kcontrol->id.numid = card->last_numid + 1; 367 kcontrol->id.numid = card->last_numid + 1;
360 card->last_numid += kcontrol->count; 368 card->last_numid += kcontrol->count;
369 count = kcontrol->count;
361 up_write(&card->controls_rwsem); 370 up_write(&card->controls_rwsem);
362 for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) 371 for (idx = 0; idx < count; idx++, id.index++, id.numid++)
363 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); 372 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
364 return 0; 373 return 0;
365 374
@@ -388,6 +397,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
388 bool add_on_replace) 397 bool add_on_replace)
389{ 398{
390 struct snd_ctl_elem_id id; 399 struct snd_ctl_elem_id id;
400 unsigned int count;
391 unsigned int idx; 401 unsigned int idx;
392 struct snd_kcontrol *old; 402 struct snd_kcontrol *old;
393 int ret; 403 int ret;
@@ -423,8 +433,9 @@ add:
423 card->controls_count += kcontrol->count; 433 card->controls_count += kcontrol->count;
424 kcontrol->id.numid = card->last_numid + 1; 434 kcontrol->id.numid = card->last_numid + 1;
425 card->last_numid += kcontrol->count; 435 card->last_numid += kcontrol->count;
436 count = kcontrol->count;
426 up_write(&card->controls_rwsem); 437 up_write(&card->controls_rwsem);
427 for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) 438 for (idx = 0; idx < count; idx++, id.index++, id.numid++)
428 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); 439 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
429 return 0; 440 return 0;
430 441
@@ -897,9 +908,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
897 result = kctl->put(kctl, control); 908 result = kctl->put(kctl, control);
898 } 909 }
899 if (result > 0) { 910 if (result > 0) {
911 struct snd_ctl_elem_id id = control->id;
900 up_read(&card->controls_rwsem); 912 up_read(&card->controls_rwsem);
901 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, 913 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
902 &control->id);
903 return 0; 914 return 0;
904 } 915 }
905 } 916 }
@@ -991,6 +1002,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
991 1002
992struct user_element { 1003struct user_element {
993 struct snd_ctl_elem_info info; 1004 struct snd_ctl_elem_info info;
1005 struct snd_card *card;
994 void *elem_data; /* element data */ 1006 void *elem_data; /* element data */
995 unsigned long elem_data_size; /* size of element data in bytes */ 1007 unsigned long elem_data_size; /* size of element data in bytes */
996 void *tlv_data; /* TLV data */ 1008 void *tlv_data; /* TLV data */
@@ -1034,7 +1046,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
1034{ 1046{
1035 struct user_element *ue = kcontrol->private_data; 1047 struct user_element *ue = kcontrol->private_data;
1036 1048
1049 mutex_lock(&ue->card->user_ctl_lock);
1037 memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); 1050 memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
1051 mutex_unlock(&ue->card->user_ctl_lock);
1038 return 0; 1052 return 0;
1039} 1053}
1040 1054
@@ -1043,10 +1057,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
1043{ 1057{
1044 int change; 1058 int change;
1045 struct user_element *ue = kcontrol->private_data; 1059 struct user_element *ue = kcontrol->private_data;
1046 1060
1061 mutex_lock(&ue->card->user_ctl_lock);
1047 change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0; 1062 change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
1048 if (change) 1063 if (change)
1049 memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); 1064 memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
1065 mutex_unlock(&ue->card->user_ctl_lock);
1050 return change; 1066 return change;
1051} 1067}
1052 1068
@@ -1066,19 +1082,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
1066 new_data = memdup_user(tlv, size); 1082 new_data = memdup_user(tlv, size);
1067 if (IS_ERR(new_data)) 1083 if (IS_ERR(new_data))
1068 return PTR_ERR(new_data); 1084 return PTR_ERR(new_data);
1085 mutex_lock(&ue->card->user_ctl_lock);
1069 change = ue->tlv_data_size != size; 1086 change = ue->tlv_data_size != size;
1070 if (!change) 1087 if (!change)
1071 change = memcmp(ue->tlv_data, new_data, size); 1088 change = memcmp(ue->tlv_data, new_data, size);
1072 kfree(ue->tlv_data); 1089 kfree(ue->tlv_data);
1073 ue->tlv_data = new_data; 1090 ue->tlv_data = new_data;
1074 ue->tlv_data_size = size; 1091 ue->tlv_data_size = size;
1092 mutex_unlock(&ue->card->user_ctl_lock);
1075 } else { 1093 } else {
1076 if (! ue->tlv_data_size || ! ue->tlv_data) 1094 int ret = 0;
1077 return -ENXIO; 1095
1078 if (size < ue->tlv_data_size) 1096 mutex_lock(&ue->card->user_ctl_lock);
1079 return -ENOSPC; 1097 if (!ue->tlv_data_size || !ue->tlv_data) {
1098 ret = -ENXIO;
1099 goto err_unlock;
1100 }
1101 if (size < ue->tlv_data_size) {
1102 ret = -ENOSPC;
1103 goto err_unlock;
1104 }
1080 if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size)) 1105 if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
1081 return -EFAULT; 1106 ret = -EFAULT;
1107err_unlock:
1108 mutex_unlock(&ue->card->user_ctl_lock);
1109 if (ret)
1110 return ret;
1082 } 1111 }
1083 return change; 1112 return change;
1084} 1113}
@@ -1136,8 +1165,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1136 struct user_element *ue; 1165 struct user_element *ue;
1137 int idx, err; 1166 int idx, err;
1138 1167
1139 if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
1140 return -ENOMEM;
1141 if (info->count < 1) 1168 if (info->count < 1)
1142 return -EINVAL; 1169 return -EINVAL;
1143 access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : 1170 access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
@@ -1146,21 +1173,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1146 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)); 1173 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
1147 info->id.numid = 0; 1174 info->id.numid = 0;
1148 memset(&kctl, 0, sizeof(kctl)); 1175 memset(&kctl, 0, sizeof(kctl));
1149 down_write(&card->controls_rwsem); 1176
1150 _kctl = snd_ctl_find_id(card, &info->id); 1177 if (replace) {
1151 err = 0; 1178 err = snd_ctl_remove_user_ctl(file, &info->id);
1152 if (_kctl) { 1179 if (err)
1153 if (replace) 1180 return err;
1154 err = snd_ctl_remove(card, _kctl);
1155 else
1156 err = -EBUSY;
1157 } else {
1158 if (replace)
1159 err = -ENOENT;
1160 } 1181 }
1161 up_write(&card->controls_rwsem); 1182
1162 if (err < 0) 1183 if (card->user_ctl_count >= MAX_USER_CONTROLS)
1163 return err; 1184 return -ENOMEM;
1185
1164 memcpy(&kctl.id, &info->id, sizeof(info->id)); 1186 memcpy(&kctl.id, &info->id, sizeof(info->id));
1165 kctl.count = info->owner ? info->owner : 1; 1187 kctl.count = info->owner ? info->owner : 1;
1166 access |= SNDRV_CTL_ELEM_ACCESS_USER; 1188 access |= SNDRV_CTL_ELEM_ACCESS_USER;
@@ -1210,6 +1232,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1210 ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); 1232 ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
1211 if (ue == NULL) 1233 if (ue == NULL)
1212 return -ENOMEM; 1234 return -ENOMEM;
1235 ue->card = card;
1213 ue->info = *info; 1236 ue->info = *info;
1214 ue->info.access = 0; 1237 ue->info.access = 0;
1215 ue->elem_data = (char *)ue + sizeof(*ue); 1238 ue->elem_data = (char *)ue + sizeof(*ue);
@@ -1321,8 +1344,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
1321 } 1344 }
1322 err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); 1345 err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
1323 if (err > 0) { 1346 if (err > 0) {
1347 struct snd_ctl_elem_id id = kctl->id;
1324 up_read(&card->controls_rwsem); 1348 up_read(&card->controls_rwsem);
1325 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); 1349 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
1326 return 0; 1350 return 0;
1327 } 1351 }
1328 } else { 1352 } else {