diff options
-rw-r--r-- | sound/usb/mixer.c | 156 | ||||
-rw-r--r-- | sound/usb/mixer.h | 26 | ||||
-rw-r--r-- | sound/usb/mixer_quirks.c | 12 | ||||
-rw-r--r-- | sound/usb/mixer_scarlett.c | 8 |
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 */ |
144 | static inline int | 144 | static inline int |
@@ -290,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) | |||
290 | static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, | 290 | static 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 | ||
327 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, | 327 | static 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, | |||
445 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | 445 | int 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 | ||
572 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, | 572 | int 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) | |||
833 | static void volume_control_quirks(struct usb_mixer_elem_info *cval, | 833 | static 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 | ||
2238 | void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) | 2231 | void 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 | ||
2247 | static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, | 2240 | static 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, | |||
2287 | static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, | 2284 | static 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 | ||
2513 | static int restore_mixer_value(struct usb_mixer_elem_info *cval) | 2516 | static 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 | ||
2542 | int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) | 2546 | int 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 | |||
2569 | void 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 | |||
4 | struct usb_mixer_interface { | 6 | struct 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 | ||
39 | struct usb_mixer_elem_info { | 41 | typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer, |
42 | struct usb_mixer_elem_list *list); | ||
43 | typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem); | ||
44 | |||
45 | struct 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 | |||
54 | struct 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); | |||
65 | int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | 77 | int 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 | ||
68 | int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, | 80 | int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, |
69 | struct snd_kcontrol *kctl); | 81 | struct snd_kcontrol *kctl); |
70 | 82 | ||
83 | void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list, | ||
84 | struct usb_mixer_interface *mixer, | ||
85 | int unitid); | ||
86 | |||
71 | int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | 87 | int 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 | ||
122 | static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, | 116 | static 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; |