diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 156 |
1 files changed, 86 insertions, 70 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 | } | ||