aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-11-18 05:47:04 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-21 05:56:58 -0500
commit3360b84b8ed1f08bfb39743465b858a04492fcc3 (patch)
treefc05e8cf624adf9cd9e25fdca04793c830ff9365 /sound/usb
parent5aeee3424fa5926a53885b9defb593971e446d77 (diff)
ALSA: usb-audio: Allow quirks to handle own resume and proc dump
So far, we blindly assumed that the all usb-audio mixer elements follow the standard and apply the standard resume method for the registered elements in the id_elems[] list. However, some quirks really need the own resume and it's incomplete for now. This patch enhances the resume handling in two folds: - split some fields in struct usb_mixer_elem_info into a smaller header struct (usb_mixer_elem_list) for keeping the minimal information in the linked-list; the usb_mixer_elem_info embeds this header struct instead - add resume and dump callbacks to usb_mixer_elem_list struct to allow quirks providing the own methods For the standard mixer elements, these new callbacks are set to the standard ones as default, thus there is no functional change by this patch yet. The dump and resume callbacks are typedef'ed for ease of later patches using arrays of such function pointers. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/mixer.c156
-rw-r--r--sound/usb/mixer.h26
-rw-r--r--sound/usb/mixer_quirks.c12
-rw-r--r--sound/usb/mixer_scarlett.c8
4 files changed, 114 insertions, 88 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index a4fbfff63191..41650d5b93b7 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -138,7 +138,7 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
138 138
139/* ignore the error value if ignore_ctl_error flag is set */ 139/* ignore the error value if ignore_ctl_error flag is set */
140#define filter_error(cval, err) \ 140#define filter_error(cval, err) \
141 ((cval)->mixer->ignore_ctl_error ? 0 : (err)) 141 ((cval)->head.mixer->ignore_ctl_error ? 0 : (err))
142 142
143/* check whether the control should be ignored */ 143/* check whether the control should be ignored */
144static inline int 144static inline int
@@ -290,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
290static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, 290static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
291 int validx, int *value_ret) 291 int validx, int *value_ret)
292{ 292{
293 struct snd_usb_audio *chip = cval->mixer->chip; 293 struct snd_usb_audio *chip = cval->head.mixer->chip;
294 unsigned char buf[2]; 294 unsigned char buf[2];
295 int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; 295 int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
296 int timeout = 10; 296 int timeout = 10;
297 int idx = 0, err; 297 int idx = 0, err;
298 298
299 err = snd_usb_autoresume(cval->mixer->chip); 299 err = snd_usb_autoresume(chip);
300 if (err < 0) 300 if (err < 0)
301 return -EIO; 301 return -EIO;
302 302
@@ -304,7 +304,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
304 while (timeout-- > 0) { 304 while (timeout-- > 0) {
305 if (chip->shutdown) 305 if (chip->shutdown)
306 break; 306 break;
307 idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); 307 idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
308 if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, 308 if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
309 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 309 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
310 validx, idx, buf, val_len) >= val_len) { 310 validx, idx, buf, val_len) >= val_len) {
@@ -320,14 +320,14 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
320 320
321 out: 321 out:
322 up_read(&chip->shutdown_rwsem); 322 up_read(&chip->shutdown_rwsem);
323 snd_usb_autosuspend(cval->mixer->chip); 323 snd_usb_autosuspend(chip);
324 return err; 324 return err;
325} 325}
326 326
327static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, 327static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
328 int validx, int *value_ret) 328 int validx, int *value_ret)
329{ 329{
330 struct snd_usb_audio *chip = cval->mixer->chip; 330 struct snd_usb_audio *chip = cval->head.mixer->chip;
331 unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */ 331 unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */
332 unsigned char *val; 332 unsigned char *val;
333 int idx = 0, ret, size; 333 int idx = 0, ret, size;
@@ -351,7 +351,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
351 if (chip->shutdown) { 351 if (chip->shutdown) {
352 ret = -ENODEV; 352 ret = -ENODEV;
353 } else { 353 } else {
354 idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); 354 idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
355 ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, 355 ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
356 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, 356 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
357 validx, idx, buf, size); 357 validx, idx, buf, size);
@@ -396,7 +396,7 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request,
396{ 396{
397 validx += cval->idx_off; 397 validx += cval->idx_off;
398 398
399 return (cval->mixer->protocol == UAC_VERSION_1) ? 399 return (cval->head.mixer->protocol == UAC_VERSION_1) ?
400 get_ctl_value_v1(cval, request, validx, value_ret) : 400 get_ctl_value_v1(cval, request, validx, value_ret) :
401 get_ctl_value_v2(cval, request, validx, value_ret); 401 get_ctl_value_v2(cval, request, validx, value_ret);
402} 402}
@@ -427,8 +427,8 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
427 } 427 }
428 err = get_cur_mix_raw(cval, channel, value); 428 err = get_cur_mix_raw(cval, channel, value);
429 if (err < 0) { 429 if (err < 0) {
430 if (!cval->mixer->ignore_ctl_error) 430 if (!cval->head.mixer->ignore_ctl_error)
431 usb_audio_dbg(cval->mixer->chip, 431 usb_audio_dbg(cval->head.mixer->chip,
432 "cannot get current value for control %d ch %d: err = %d\n", 432 "cannot get current value for control %d ch %d: err = %d\n",
433 cval->control, channel, err); 433 cval->control, channel, err);
434 return err; 434 return err;
@@ -445,13 +445,13 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
445int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, 445int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
446 int request, int validx, int value_set) 446 int request, int validx, int value_set)
447{ 447{
448 struct snd_usb_audio *chip = cval->mixer->chip; 448 struct snd_usb_audio *chip = cval->head.mixer->chip;
449 unsigned char buf[2]; 449 unsigned char buf[2];
450 int idx = 0, val_len, err, timeout = 10; 450 int idx = 0, val_len, err, timeout = 10;
451 451
452 validx += cval->idx_off; 452 validx += cval->idx_off;
453 453
454 if (cval->mixer->protocol == UAC_VERSION_1) { 454 if (cval->head.mixer->protocol == UAC_VERSION_1) {
455 val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; 455 val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
456 } else { /* UAC_VERSION_2 */ 456 } else { /* UAC_VERSION_2 */
457 /* audio class v2 controls are always 2 bytes in size */ 457 /* audio class v2 controls are always 2 bytes in size */
@@ -476,7 +476,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
476 while (timeout-- > 0) { 476 while (timeout-- > 0) {
477 if (chip->shutdown) 477 if (chip->shutdown)
478 break; 478 break;
479 idx = snd_usb_ctrl_intf(chip) | (cval->id << 8); 479 idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
480 if (snd_usb_ctl_msg(chip->dev, 480 if (snd_usb_ctl_msg(chip->dev,
481 usb_sndctrlpipe(chip->dev, 0), request, 481 usb_sndctrlpipe(chip->dev, 0), request,
482 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 482 USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
@@ -510,7 +510,7 @@ int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
510 cval->ch_readonly & (1 << (channel - 1)); 510 cval->ch_readonly & (1 << (channel - 1));
511 511
512 if (read_only) { 512 if (read_only) {
513 usb_audio_dbg(cval->mixer->chip, 513 usb_audio_dbg(cval->head.mixer->chip,
514 "%s(): channel %d of control %d is read_only\n", 514 "%s(): channel %d of control %d is read_only\n",
515 __func__, channel, cval->control); 515 __func__, channel, cval->control);
516 return 0; 516 return 0;
@@ -569,10 +569,10 @@ static int check_matrix_bitmap(unsigned char *bmap,
569 * if failed, give up and free the control instance. 569 * if failed, give up and free the control instance.
570 */ 570 */
571 571
572int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, 572int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
573 struct snd_kcontrol *kctl) 573 struct snd_kcontrol *kctl)
574{ 574{
575 struct usb_mixer_elem_info *cval = kctl->private_data; 575 struct usb_mixer_interface *mixer = list->mixer;
576 int err; 576 int err;
577 577
578 while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) 578 while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
@@ -582,9 +582,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
582 err); 582 err);
583 return err; 583 return err;
584 } 584 }
585 cval->elem_id = &kctl->id; 585 list->kctl = kctl;
586 cval->next_id_elem = mixer->id_elems[cval->id]; 586 list->next_id_elem = mixer->id_elems[list->id];
587 mixer->id_elems[cval->id] = cval; 587 mixer->id_elems[list->id] = list;
588 return 0; 588 return 0;
589} 589}
590 590
@@ -833,7 +833,7 @@ void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl)
833static void volume_control_quirks(struct usb_mixer_elem_info *cval, 833static void volume_control_quirks(struct usb_mixer_elem_info *cval,
834 struct snd_kcontrol *kctl) 834 struct snd_kcontrol *kctl)
835{ 835{
836 struct snd_usb_audio *chip = cval->mixer->chip; 836 struct snd_usb_audio *chip = cval->head.mixer->chip;
837 switch (chip->usb_id) { 837 switch (chip->usb_id) {
838 case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 838 case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
839 case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ 839 case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
@@ -958,10 +958,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
958 } 958 }
959 if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || 959 if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
960 get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { 960 get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
961 usb_audio_err(cval->mixer->chip, 961 usb_audio_err(cval->head.mixer->chip,
962 "%d:%d: cannot get min/max values for control %d (id %d)\n", 962 "%d:%d: cannot get min/max values for control %d (id %d)\n",
963 cval->id, snd_usb_ctrl_intf(cval->mixer->chip), 963 cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip),
964 cval->control, cval->id); 964 cval->control, cval->head.id);
965 return -EINVAL; 965 return -EINVAL;
966 } 966 }
967 if (get_ctl_value(cval, UAC_GET_RES, 967 if (get_ctl_value(cval, UAC_GET_RES,
@@ -1065,7 +1065,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
1065 kcontrol->vd[0].access &= 1065 kcontrol->vd[0].access &=
1066 ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | 1066 ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
1067 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); 1067 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
1068 snd_ctl_notify(cval->mixer->chip->card, 1068 snd_ctl_notify(cval->head.mixer->chip->card,
1069 SNDRV_CTL_EVENT_MASK_INFO, 1069 SNDRV_CTL_EVENT_MASK_INFO,
1070 &kcontrol->id); 1070 &kcontrol->id);
1071 } 1071 }
@@ -1235,8 +1235,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
1235 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 1235 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1236 if (!cval) 1236 if (!cval)
1237 return; 1237 return;
1238 cval->mixer = state->mixer; 1238 snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
1239 cval->id = unitid;
1240 cval->control = control; 1239 cval->control = control;
1241 cval->cmask = ctl_mask; 1240 cval->cmask = ctl_mask;
1242 cval->val_type = audio_feature_info[control-1].type; 1241 cval->val_type = audio_feature_info[control-1].type;
@@ -1347,14 +1346,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
1347 range); 1346 range);
1348 usb_audio_warn(state->chip, 1347 usb_audio_warn(state->chip,
1349 "[%d] FU [%s] ch = %d, val = %d/%d/%d", 1348 "[%d] FU [%s] ch = %d, val = %d/%d/%d",
1350 cval->id, kctl->id.name, cval->channels, 1349 cval->head.id, kctl->id.name, cval->channels,
1351 cval->min, cval->max, cval->res); 1350 cval->min, cval->max, cval->res);
1352 } 1351 }
1353 1352
1354 usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", 1353 usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
1355 cval->id, kctl->id.name, cval->channels, 1354 cval->head.id, kctl->id.name, cval->channels,
1356 cval->min, cval->max, cval->res); 1355 cval->min, cval->max, cval->res);
1357 snd_usb_mixer_add_control(state->mixer, kctl); 1356 snd_usb_mixer_add_control(&cval->head, kctl);
1358} 1357}
1359 1358
1360/* 1359/*
@@ -1528,8 +1527,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
1528 if (!cval) 1527 if (!cval)
1529 return; 1528 return;
1530 1529
1531 cval->mixer = state->mixer; 1530 snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
1532 cval->id = unitid;
1533 cval->control = in_ch + 1; /* based on 1 */ 1531 cval->control = in_ch + 1; /* based on 1 */
1534 cval->val_type = USB_MIXER_S16; 1532 cval->val_type = USB_MIXER_S16;
1535 for (i = 0; i < num_outs; i++) { 1533 for (i = 0; i < num_outs; i++) {
@@ -1561,8 +1559,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
1561 append_ctl_name(kctl, " Volume"); 1559 append_ctl_name(kctl, " Volume");
1562 1560
1563 usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n", 1561 usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
1564 cval->id, kctl->id.name, cval->channels, cval->min, cval->max); 1562 cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max);
1565 snd_usb_mixer_add_control(state->mixer, kctl); 1563 snd_usb_mixer_add_control(&cval->head, kctl);
1566} 1564}
1567 1565
1568/* 1566/*
@@ -1812,8 +1810,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
1812 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 1810 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
1813 if (!cval) 1811 if (!cval)
1814 return -ENOMEM; 1812 return -ENOMEM;
1815 cval->mixer = state->mixer; 1813 snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
1816 cval->id = unitid;
1817 cval->control = valinfo->control; 1814 cval->control = valinfo->control;
1818 cval->val_type = valinfo->val_type; 1815 cval->val_type = valinfo->val_type;
1819 cval->channels = 1; 1816 cval->channels = 1;
@@ -1866,10 +1863,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
1866 1863
1867 usb_audio_dbg(state->chip, 1864 usb_audio_dbg(state->chip,
1868 "[%d] PU [%s] ch = %d, val = %d/%d\n", 1865 "[%d] PU [%s] ch = %d, val = %d/%d\n",
1869 cval->id, kctl->id.name, cval->channels, 1866 cval->head.id, kctl->id.name, cval->channels,
1870 cval->min, cval->max); 1867 cval->min, cval->max);
1871 1868
1872 err = snd_usb_mixer_add_control(state->mixer, kctl); 1869 err = snd_usb_mixer_add_control(&cval->head, kctl);
1873 if (err < 0) 1870 if (err < 0)
1874 return err; 1871 return err;
1875 } 1872 }
@@ -2016,8 +2013,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
2016 cval = kzalloc(sizeof(*cval), GFP_KERNEL); 2013 cval = kzalloc(sizeof(*cval), GFP_KERNEL);
2017 if (!cval) 2014 if (!cval)
2018 return -ENOMEM; 2015 return -ENOMEM;
2019 cval->mixer = state->mixer; 2016 snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
2020 cval->id = unitid;
2021 cval->val_type = USB_MIXER_U8; 2017 cval->val_type = USB_MIXER_U8;
2022 cval->channels = 1; 2018 cval->channels = 1;
2023 cval->min = 1; 2019 cval->min = 1;
@@ -2088,11 +2084,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
2088 } 2084 }
2089 2085
2090 usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n", 2086 usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
2091 cval->id, kctl->id.name, desc->bNrInPins); 2087 cval->head.id, kctl->id.name, desc->bNrInPins);
2092 if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0) 2088 return snd_usb_mixer_add_control(&cval->head, kctl);
2093 return err;
2094
2095 return 0;
2096} 2089}
2097 2090
2098/* 2091/*
@@ -2237,25 +2230,21 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
2237 2230
2238void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) 2231void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
2239{ 2232{
2240 struct usb_mixer_elem_info *info; 2233 struct usb_mixer_elem_list *list;
2241 2234
2242 for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) 2235 for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem)
2243 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 2236 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
2244 info->elem_id); 2237 &list->kctl->id);
2245} 2238}
2246 2239
2247static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, 2240static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
2248 int unitid, 2241 struct usb_mixer_elem_list *list)
2249 struct usb_mixer_elem_info *cval)
2250{ 2242{
2243 struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
2251 static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", 2244 static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
2252 "S8", "U8", "S16", "U16"}; 2245 "S8", "U8", "S16", "U16"};
2253 snd_iprintf(buffer, " Unit: %i\n", unitid);
2254 if (cval->elem_id)
2255 snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n",
2256 cval->elem_id->name, cval->elem_id->index);
2257 snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " 2246 snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, "
2258 "channels=%i, type=\"%s\"\n", cval->id, 2247 "channels=%i, type=\"%s\"\n", cval->head.id,
2259 cval->control, cval->cmask, cval->channels, 2248 cval->control, cval->cmask, cval->channels,
2260 val_types[cval->val_type]); 2249 val_types[cval->val_type]);
2261 snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n", 2250 snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
@@ -2267,7 +2256,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
2267{ 2256{
2268 struct snd_usb_audio *chip = entry->private_data; 2257 struct snd_usb_audio *chip = entry->private_data;
2269 struct usb_mixer_interface *mixer; 2258 struct usb_mixer_interface *mixer;
2270 struct usb_mixer_elem_info *cval; 2259 struct usb_mixer_elem_list *list;
2271 int unitid; 2260 int unitid;
2272 2261
2273 list_for_each_entry(mixer, &chip->mixer_list, list) { 2262 list_for_each_entry(mixer, &chip->mixer_list, list) {
@@ -2277,9 +2266,17 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
2277 mixer->ignore_ctl_error); 2266 mixer->ignore_ctl_error);
2278 snd_iprintf(buffer, "Card: %s\n", chip->card->longname); 2267 snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
2279 for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { 2268 for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
2280 for (cval = mixer->id_elems[unitid]; cval; 2269 for (list = mixer->id_elems[unitid]; list;
2281 cval = cval->next_id_elem) 2270 list = list->next_id_elem) {
2282 snd_usb_mixer_dump_cval(buffer, unitid, cval); 2271 snd_iprintf(buffer, " Unit: %i\n", list->id);
2272 if (list->kctl)
2273 snd_iprintf(buffer,
2274 " Control: name=\"%s\", index=%i\n",
2275 list->kctl->id.name,
2276 list->kctl->id.index);
2277 if (list->dump)
2278 list->dump(buffer, list);
2279 }
2283 } 2280 }
2284 } 2281 }
2285} 2282}
@@ -2287,7 +2284,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
2287static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, 2284static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
2288 int attribute, int value, int index) 2285 int attribute, int value, int index)
2289{ 2286{
2290 struct usb_mixer_elem_info *info; 2287 struct usb_mixer_elem_list *list;
2291 __u8 unitid = (index >> 8) & 0xff; 2288 __u8 unitid = (index >> 8) & 0xff;
2292 __u8 control = (value >> 8) & 0xff; 2289 __u8 control = (value >> 8) & 0xff;
2293 __u8 channel = value & 0xff; 2290 __u8 channel = value & 0xff;
@@ -2299,7 +2296,13 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
2299 return; 2296 return;
2300 } 2297 }
2301 2298
2302 for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) { 2299 for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) {
2300 struct usb_mixer_elem_info *info;
2301
2302 if (!list->kctl)
2303 continue;
2304
2305 info = (struct usb_mixer_elem_info *)list;
2303 if (info->control != control) 2306 if (info->control != control)
2304 continue; 2307 continue;
2305 2308
@@ -2312,7 +2315,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
2312 info->cached = 0; 2315 info->cached = 0;
2313 2316
2314 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, 2317 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
2315 info->elem_id); 2318 &info->head.kctl->id);
2316 break; 2319 break;
2317 2320
2318 case UAC2_CS_RANGE: 2321 case UAC2_CS_RANGE:
@@ -2510,8 +2513,9 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
2510 return 0; 2513 return 0;
2511} 2514}
2512 2515
2513static int restore_mixer_value(struct usb_mixer_elem_info *cval) 2516static int restore_mixer_value(struct usb_mixer_elem_list *list)
2514{ 2517{
2518 struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
2515 int c, err, idx; 2519 int c, err, idx;
2516 2520
2517 if (cval->cmask) { 2521 if (cval->cmask) {
@@ -2541,19 +2545,19 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
2541 2545
2542int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) 2546int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
2543{ 2547{
2544 struct usb_mixer_elem_info *cval; 2548 struct usb_mixer_elem_list *list;
2545 int id, err; 2549 int id, err;
2546 2550
2547 /* FIXME: any mixer quirks? */
2548
2549 if (reset_resume) { 2551 if (reset_resume) {
2550 /* restore cached mixer values */ 2552 /* restore cached mixer values */
2551 for (id = 0; id < MAX_ID_ELEMS; id++) { 2553 for (id = 0; id < MAX_ID_ELEMS; id++) {
2552 for (cval = mixer->id_elems[id]; cval; 2554 for (list = mixer->id_elems[id]; list;
2553 cval = cval->next_id_elem) { 2555 list = list->next_id_elem) {
2554 err = restore_mixer_value(cval); 2556 if (list->resume) {
2555 if (err < 0) 2557 err = list->resume(list);
2556 return err; 2558 if (err < 0)
2559 return err;
2560 }
2557 } 2561 }
2558 } 2562 }
2559 } 2563 }
@@ -2561,3 +2565,15 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
2561 return snd_usb_mixer_activate(mixer); 2565 return snd_usb_mixer_activate(mixer);
2562} 2566}
2563#endif 2567#endif
2568
2569void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
2570 struct usb_mixer_interface *mixer,
2571 int unitid)
2572{
2573 list->mixer = mixer;
2574 list->id = unitid;
2575 list->dump = snd_usb_mixer_dump_cval;
2576#ifdef CONFIG_PM
2577 list->resume = restore_mixer_value;
2578#endif
2579}
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 2478a844a322..0fe87b7c7f00 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -1,6 +1,8 @@
1#ifndef __USBMIXER_H 1#ifndef __USBMIXER_H
2#define __USBMIXER_H 2#define __USBMIXER_H
3 3
4#include <sound/info.h>
5
4struct usb_mixer_interface { 6struct usb_mixer_interface {
5 struct snd_usb_audio *chip; 7 struct snd_usb_audio *chip;
6 struct usb_host_interface *hostif; 8 struct usb_host_interface *hostif;
@@ -8,7 +10,7 @@ struct usb_mixer_interface {
8 unsigned int ignore_ctl_error; 10 unsigned int ignore_ctl_error;
9 struct urb *urb; 11 struct urb *urb;
10 /* array[MAX_ID_ELEMS], indexed by unit id */ 12 /* array[MAX_ID_ELEMS], indexed by unit id */
11 struct usb_mixer_elem_info **id_elems; 13 struct usb_mixer_elem_list **id_elems;
12 14
13 /* the usb audio specification version this interface complies to */ 15 /* the usb audio specification version this interface complies to */
14 int protocol; 16 int protocol;
@@ -36,11 +38,21 @@ enum {
36 USB_MIXER_U16, 38 USB_MIXER_U16,
37}; 39};
38 40
39struct usb_mixer_elem_info { 41typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
42 struct usb_mixer_elem_list *list);
43typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem);
44
45struct usb_mixer_elem_list {
40 struct usb_mixer_interface *mixer; 46 struct usb_mixer_interface *mixer;
41 struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */ 47 struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
42 struct snd_ctl_elem_id *elem_id; 48 struct snd_kcontrol *kctl;
43 unsigned int id; 49 unsigned int id;
50 usb_mixer_elem_dump_func_t dump;
51 usb_mixer_elem_resume_func_t resume;
52};
53
54struct usb_mixer_elem_info {
55 struct usb_mixer_elem_list head;
44 unsigned int control; /* CS or ICN (high byte) */ 56 unsigned int control; /* CS or ICN (high byte) */
45 unsigned int cmask; /* channel mask bitmap: 0 = master */ 57 unsigned int cmask; /* channel mask bitmap: 0 = master */
46 unsigned int idx_off; /* Control index offset */ 58 unsigned int idx_off; /* Control index offset */
@@ -65,9 +77,13 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
65int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, 77int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
66 int request, int validx, int value_set); 78 int request, int validx, int value_set);
67 79
68int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, 80int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
69 struct snd_kcontrol *kctl); 81 struct snd_kcontrol *kctl);
70 82
83void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
84 struct usb_mixer_interface *mixer,
85 int unitid);
86
71int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, 87int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
72 unsigned int size, unsigned int __user *_tlv); 88 unsigned int size, unsigned int __user *_tlv);
73 89
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 8b55c0667f60..88a408cdddbd 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -69,7 +69,6 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
69 const char *name, 69 const char *name,
70 snd_kcontrol_tlv_rw_t *tlv_callback) 70 snd_kcontrol_tlv_rw_t *tlv_callback)
71{ 71{
72 int err;
73 struct usb_mixer_elem_info *cval; 72 struct usb_mixer_elem_info *cval;
74 struct snd_kcontrol *kctl; 73 struct snd_kcontrol *kctl;
75 74
@@ -77,8 +76,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
77 if (!cval) 76 if (!cval)
78 return -ENOMEM; 77 return -ENOMEM;
79 78
80 cval->id = unitid; 79 snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid);
81 cval->mixer = mixer;
82 cval->val_type = val_type; 80 cval->val_type = val_type;
83 cval->channels = 1; 81 cval->channels = 1;
84 cval->control = control; 82 cval->control = control;
@@ -112,11 +110,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
112 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 110 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
113 } 111 }
114 /* Add control to mixer */ 112 /* Add control to mixer */
115 err = snd_usb_mixer_add_control(mixer, kctl); 113 return snd_usb_mixer_add_control(&cval->head, kctl);
116 if (err < 0)
117 return err;
118
119 return 0;
120} 114}
121 115
122static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, 116static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
@@ -1206,7 +1200,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
1206 int unitid = 12; /* SamleRate ExtensionUnit ID */ 1200 int unitid = 12; /* SamleRate ExtensionUnit ID */
1207 1201
1208 list_for_each_entry(mixer, &chip->mixer_list, list) { 1202 list_for_each_entry(mixer, &chip->mixer_list, list) {
1209 cval = mixer->id_elems[unitid]; 1203 cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid];
1210 if (cval) { 1204 if (cval) {
1211 snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, 1205 snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
1212 cval->control << 8, 1206 cval->control << 8,
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
index a0a874507de5..92dba35660b3 100644
--- a/sound/usb/mixer_scarlett.c
+++ b/sound/usb/mixer_scarlett.c
@@ -436,10 +436,10 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
436 struct snd_ctl_elem_value *ucontrol) 436 struct snd_ctl_elem_value *ucontrol)
437{ 437{
438 struct usb_mixer_elem_info *elem = kctl->private_data; 438 struct usb_mixer_elem_info *elem = kctl->private_data;
439 struct snd_usb_audio *chip = elem->mixer->chip; 439 struct snd_usb_audio *chip = elem->head.mixer->chip;
440 unsigned char buf[2 * MAX_CHANNELS] = {0, }; 440 unsigned char buf[2 * MAX_CHANNELS] = {0, };
441 int wValue = (elem->control << 8) | elem->idx_off; 441 int wValue = (elem->control << 8) | elem->idx_off;
442 int idx = snd_usb_ctrl_intf(chip) | (elem->id << 8); 442 int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
443 int err; 443 int err;
444 444
445 err = snd_usb_ctl_msg(chip->dev, 445 err = snd_usb_ctl_msg(chip->dev,
@@ -528,10 +528,10 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
528 if (!elem) 528 if (!elem)
529 return -ENOMEM; 529 return -ENOMEM;
530 530
531 elem->mixer = mixer; 531 elem->head.mixer = mixer;
532 elem->control = offset; 532 elem->control = offset;
533 elem->idx_off = num; 533 elem->idx_off = num;
534 elem->id = index; 534 elem->head.id = index;
535 elem->val_type = val_type; 535 elem->val_type = val_type;
536 536
537 elem->channels = channels; 537 elem->channels = channels;