diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-03-11 15:13:25 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-03-12 06:21:26 -0500 |
commit | 23caaf19b11eda7054348452e1618d4512a86907 (patch) | |
tree | de0f69f74931fb033f3291c27691a3c2ac6367a2 /sound/usb | |
parent | 99fc86450c439039d2ef88d06b222fd51a779176 (diff) |
ALSA: usb-mixer: Add support for Audio Class v2.0
USB Audio Class v2.0 compliant devices have different descriptors and a
different way of setting/getting min/max/res/cur properties. This patch
adds support for them.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/mixer.c | 322 | ||||
-rw-r--r-- | sound/usb/mixer.h | 3 |
2 files changed, 245 insertions, 80 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 994b0385235c..1deef623c081 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
35 | #include <linux/usb/audio.h> | 35 | #include <linux/usb/audio.h> |
36 | #include <linux/usb/audio-v2.h> | ||
36 | 37 | ||
37 | #include <sound/core.h> | 38 | #include <sound/core.h> |
38 | #include <sound/control.h> | 39 | #include <sound/control.h> |
@@ -197,6 +198,7 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid, | |||
197 | 198 | ||
198 | /* | 199 | /* |
199 | * find an audio control unit with the given unit id | 200 | * find an audio control unit with the given unit id |
201 | * this doesn't return any clock related units, so they need to be handled elsewhere | ||
200 | */ | 202 | */ |
201 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) | 203 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) |
202 | { | 204 | { |
@@ -205,7 +207,7 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un | |||
205 | p = NULL; | 207 | p = NULL; |
206 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 208 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, |
207 | USB_DT_CS_INTERFACE)) != NULL) { | 209 | USB_DT_CS_INTERFACE)) != NULL) { |
208 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit) | 210 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit) |
209 | return p; | 211 | return p; |
210 | } | 212 | } |
211 | return NULL; | 213 | return NULL; |
@@ -302,7 +304,7 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val) | |||
302 | * retrieve a mixer value | 304 | * retrieve a mixer value |
303 | */ | 305 | */ |
304 | 306 | ||
305 | static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 307 | static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
306 | { | 308 | { |
307 | unsigned char buf[2]; | 309 | unsigned char buf[2]; |
308 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | 310 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; |
@@ -324,6 +326,58 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali | |||
324 | return -EINVAL; | 326 | return -EINVAL; |
325 | } | 327 | } |
326 | 328 | ||
329 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | ||
330 | { | ||
331 | unsigned char buf[14]; /* enough space for one range of 4 bytes */ | ||
332 | unsigned char *val; | ||
333 | int ret; | ||
334 | __u8 bRequest; | ||
335 | |||
336 | bRequest = (request == UAC_GET_CUR) ? | ||
337 | UAC2_CS_CUR : UAC2_CS_RANGE; | ||
338 | |||
339 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, | ||
340 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | ||
341 | bRequest, | ||
342 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
343 | validx, cval->mixer->ctrlif | (cval->id << 8), | ||
344 | buf, sizeof(buf), 1000); | ||
345 | |||
346 | if (ret < 0) { | ||
347 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | ||
348 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | switch (request) { | ||
353 | case UAC_GET_CUR: | ||
354 | val = buf; | ||
355 | break; | ||
356 | case UAC_GET_MIN: | ||
357 | val = buf + sizeof(__u16); | ||
358 | break; | ||
359 | case UAC_GET_MAX: | ||
360 | val = buf + sizeof(__u16) * 2; | ||
361 | break; | ||
362 | case UAC_GET_RES: | ||
363 | val = buf + sizeof(__u16) * 3; | ||
364 | break; | ||
365 | default: | ||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
369 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16))); | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | ||
375 | { | ||
376 | return (cval->mixer->protocol == UAC_VERSION_1) ? | ||
377 | get_ctl_value_v1(cval, request, validx, value_ret) : | ||
378 | get_ctl_value_v2(cval, request, validx, value_ret); | ||
379 | } | ||
380 | |||
327 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) | 381 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) |
328 | { | 382 | { |
329 | return get_ctl_value(cval, UAC_GET_CUR, validx, value); | 383 | return get_ctl_value(cval, UAC_GET_CUR, validx, value); |
@@ -348,8 +402,7 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval, | |||
348 | err = get_cur_mix_raw(cval, channel, value); | 402 | err = get_cur_mix_raw(cval, channel, value); |
349 | if (err < 0) { | 403 | if (err < 0) { |
350 | if (!cval->mixer->ignore_ctl_error) | 404 | if (!cval->mixer->ignore_ctl_error) |
351 | snd_printd(KERN_ERR "cannot get current value for " | 405 | snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", |
352 | "control %d ch %d: err = %d\n", | ||
353 | cval->control, channel, err); | 406 | cval->control, channel, err); |
354 | return err; | 407 | return err; |
355 | } | 408 | } |
@@ -367,8 +420,22 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, | |||
367 | int request, int validx, int value_set) | 420 | int request, int validx, int value_set) |
368 | { | 421 | { |
369 | unsigned char buf[2]; | 422 | unsigned char buf[2]; |
370 | int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | 423 | int val_len, timeout = 10; |
371 | int timeout = 10; | 424 | |
425 | if (cval->mixer->protocol == UAC_VERSION_1) { | ||
426 | val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; | ||
427 | } else { /* UAC_VERSION_2 */ | ||
428 | /* audio class v2 controls are always 2 bytes in size */ | ||
429 | val_len = sizeof(__u16); | ||
430 | |||
431 | /* FIXME */ | ||
432 | if (request != UAC_SET_CUR) { | ||
433 | snd_printdd(KERN_WARNING "RANGE setting not yet supported\n"); | ||
434 | return -EINVAL; | ||
435 | } | ||
436 | |||
437 | request = UAC2_CS_CUR; | ||
438 | } | ||
372 | 439 | ||
373 | value_set = convert_bytes_value(cval, value_set); | 440 | value_set = convert_bytes_value(cval, value_set); |
374 | buf[0] = value_set & 0xff; | 441 | buf[0] = value_set & 0xff; |
@@ -564,46 +631,65 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
564 | */ | 631 | */ |
565 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) | 632 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) |
566 | { | 633 | { |
567 | unsigned char *p1; | 634 | void *p1; |
568 | 635 | ||
569 | memset(term, 0, sizeof(*term)); | 636 | memset(term, 0, sizeof(*term)); |
570 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { | 637 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { |
638 | unsigned char *hdr = p1; | ||
571 | term->id = id; | 639 | term->id = id; |
572 | switch (p1[2]) { | 640 | switch (hdr[2]) { |
573 | case UAC_INPUT_TERMINAL: | 641 | case UAC_INPUT_TERMINAL: |
574 | term->type = combine_word(p1 + 4); | 642 | if (state->mixer->protocol == UAC_VERSION_1) { |
575 | term->channels = p1[7]; | 643 | struct uac_input_terminal_descriptor *d = p1; |
576 | term->chconfig = combine_word(p1 + 8); | 644 | term->type = le16_to_cpu(d->wTerminalType); |
577 | term->name = p1[11]; | 645 | term->channels = d->bNrChannels; |
646 | term->chconfig = le16_to_cpu(d->wChannelConfig); | ||
647 | term->name = d->iTerminal; | ||
648 | } else { /* UAC_VERSION_2 */ | ||
649 | struct uac2_input_terminal_descriptor *d = p1; | ||
650 | term->type = le16_to_cpu(d->wTerminalType); | ||
651 | term->channels = d->bNrChannels; | ||
652 | term->chconfig = le32_to_cpu(d->bmChannelConfig); | ||
653 | term->name = d->iTerminal; | ||
654 | } | ||
578 | return 0; | 655 | return 0; |
579 | case UAC_FEATURE_UNIT: | 656 | case UAC_FEATURE_UNIT: { |
580 | id = p1[4]; | 657 | /* the header is the same for v1 and v2 */ |
658 | struct uac_feature_unit_descriptor *d = p1; | ||
659 | id = d->bUnitID; | ||
581 | break; /* continue to parse */ | 660 | break; /* continue to parse */ |
582 | case UAC_MIXER_UNIT: | 661 | } |
583 | term->type = p1[2] << 16; /* virtual type */ | 662 | case UAC_MIXER_UNIT: { |
584 | term->channels = p1[5 + p1[4]]; | 663 | struct uac_mixer_unit_descriptor *d = p1; |
585 | term->chconfig = combine_word(p1 + 6 + p1[4]); | 664 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ |
586 | term->name = p1[p1[0] - 1]; | 665 | term->channels = uac_mixer_unit_bNrChannels(d); |
666 | term->chconfig = uac_mixer_unit_wChannelConfig(d, state->mixer->protocol); | ||
667 | term->name = uac_mixer_unit_iMixer(d); | ||
587 | return 0; | 668 | return 0; |
588 | case UAC_SELECTOR_UNIT: | 669 | } |
670 | case UAC_SELECTOR_UNIT: { | ||
671 | struct uac_selector_unit_descriptor *d = p1; | ||
589 | /* call recursively to retrieve the channel info */ | 672 | /* call recursively to retrieve the channel info */ |
590 | if (check_input_term(state, p1[5], term) < 0) | 673 | if (check_input_term(state, d->baSourceID[0], term) < 0) |
591 | return -ENODEV; | 674 | return -ENODEV; |
592 | term->type = p1[2] << 16; /* virtual type */ | 675 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ |
593 | term->id = id; | 676 | term->id = id; |
594 | term->name = p1[9 + p1[0] - 1]; | 677 | term->name = uac_selector_unit_iSelector(d); |
595 | return 0; | 678 | return 0; |
679 | } | ||
596 | case UAC_PROCESSING_UNIT_V1: | 680 | case UAC_PROCESSING_UNIT_V1: |
597 | case UAC_EXTENSION_UNIT_V1: | 681 | case UAC_EXTENSION_UNIT_V1: { |
598 | if (p1[6] == 1) { | 682 | struct uac_processing_unit_descriptor *d = p1; |
599 | id = p1[7]; | 683 | if (d->bNrInPins) { |
684 | id = d->baSourceID[0]; | ||
600 | break; /* continue to parse */ | 685 | break; /* continue to parse */ |
601 | } | 686 | } |
602 | term->type = p1[2] << 16; /* virtual type */ | 687 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ |
603 | term->channels = p1[7 + p1[6]]; | 688 | term->channels = uac_processing_unit_bNrChannels(d); |
604 | term->chconfig = combine_word(p1 + 8 + p1[6]); | 689 | term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol); |
605 | term->name = p1[12 + p1[6] + p1[11 + p1[6]]]; | 690 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); |
606 | return 0; | 691 | return 0; |
692 | } | ||
607 | default: | 693 | default: |
608 | return -ENODEV; | 694 | return -ENODEV; |
609 | } | 695 | } |
@@ -850,6 +936,15 @@ static struct snd_kcontrol_new usb_feature_unit_ctl = { | |||
850 | .put = mixer_ctl_feature_put, | 936 | .put = mixer_ctl_feature_put, |
851 | }; | 937 | }; |
852 | 938 | ||
939 | /* the read-only variant */ | ||
940 | static struct snd_kcontrol_new usb_feature_unit_ctl_ro = { | ||
941 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
942 | .name = "", /* will be filled later manually */ | ||
943 | .info = mixer_ctl_feature_info, | ||
944 | .get = mixer_ctl_feature_get, | ||
945 | .put = NULL, | ||
946 | }; | ||
947 | |||
853 | 948 | ||
854 | /* | 949 | /* |
855 | * build a feature control | 950 | * build a feature control |
@@ -862,7 +957,8 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
862 | 957 | ||
863 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 958 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
864 | unsigned int ctl_mask, int control, | 959 | unsigned int ctl_mask, int control, |
865 | struct usb_audio_term *iterm, int unitid) | 960 | struct usb_audio_term *iterm, int unitid, |
961 | int read_only) | ||
866 | { | 962 | { |
867 | struct uac_feature_unit_descriptor *desc = raw_desc; | 963 | struct uac_feature_unit_descriptor *desc = raw_desc; |
868 | unsigned int len = 0; | 964 | unsigned int len = 0; |
@@ -906,7 +1002,11 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
906 | /* get min/max values */ | 1002 | /* get min/max values */ |
907 | get_min_max(cval, 0); | 1003 | get_min_max(cval, 0); |
908 | 1004 | ||
909 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1005 | if (read_only) |
1006 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); | ||
1007 | else | ||
1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | ||
1009 | |||
910 | if (! kctl) { | 1010 | if (! kctl) { |
911 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); | 1011 | snd_printk(KERN_ERR "cannot malloc kcontrol\n"); |
912 | kfree(cval); | 1012 | kfree(cval); |
@@ -1016,24 +1116,34 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1016 | struct usb_audio_term iterm; | 1116 | struct usb_audio_term iterm; |
1017 | unsigned int master_bits, first_ch_bits; | 1117 | unsigned int master_bits, first_ch_bits; |
1018 | int err, csize; | 1118 | int err, csize; |
1019 | struct uac_feature_unit_descriptor *ftr = _ftr; | 1119 | struct uac_feature_unit_descriptor *hdr = _ftr; |
1120 | __u8 *bmaControls; | ||
1121 | |||
1122 | if (state->mixer->protocol == UAC_VERSION_1) { | ||
1123 | csize = hdr->bControlSize; | ||
1124 | channels = (hdr->bLength - 7) / csize - 1; | ||
1125 | bmaControls = hdr->bmaControls; | ||
1126 | } else { | ||
1127 | struct uac2_feature_unit_descriptor *ftr = _ftr; | ||
1128 | csize = 4; | ||
1129 | channels = (hdr->bLength - 6) / 4; | ||
1130 | bmaControls = ftr->bmaControls; | ||
1131 | } | ||
1020 | 1132 | ||
1021 | if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) { | 1133 | if (hdr->bLength < 7 || !csize || hdr->bLength < 7 + csize) { |
1022 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); | 1134 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); |
1023 | return -EINVAL; | 1135 | return -EINVAL; |
1024 | } | 1136 | } |
1025 | 1137 | ||
1026 | /* parse the source unit */ | 1138 | /* parse the source unit */ |
1027 | if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0) | 1139 | if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0) |
1028 | return err; | 1140 | return err; |
1029 | 1141 | ||
1030 | /* determine the input source type and name */ | 1142 | /* determine the input source type and name */ |
1031 | if (check_input_term(state, ftr->bSourceID, &iterm) < 0) | 1143 | if (check_input_term(state, hdr->bSourceID, &iterm) < 0) |
1032 | return -EINVAL; | 1144 | return -EINVAL; |
1033 | 1145 | ||
1034 | channels = (ftr->bLength - 7) / csize - 1; | 1146 | master_bits = snd_usb_combine_bytes(bmaControls, csize); |
1035 | |||
1036 | master_bits = snd_usb_combine_bytes(ftr->bmaControls, csize); | ||
1037 | /* master configuration quirks */ | 1147 | /* master configuration quirks */ |
1038 | switch (state->chip->usb_id) { | 1148 | switch (state->chip->usb_id) { |
1039 | case USB_ID(0x08bb, 0x2702): | 1149 | case USB_ID(0x08bb, 0x2702): |
@@ -1044,21 +1154,54 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1044 | break; | 1154 | break; |
1045 | } | 1155 | } |
1046 | if (channels > 0) | 1156 | if (channels > 0) |
1047 | first_ch_bits = snd_usb_combine_bytes(ftr->bmaControls + csize, csize); | 1157 | first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); |
1048 | else | 1158 | else |
1049 | first_ch_bits = 0; | 1159 | first_ch_bits = 0; |
1050 | /* check all control types */ | 1160 | |
1051 | for (i = 0; i < 10; i++) { | 1161 | if (state->mixer->protocol == UAC_VERSION_1) { |
1052 | unsigned int ch_bits = 0; | 1162 | /* check all control types */ |
1053 | for (j = 0; j < channels; j++) { | 1163 | for (i = 0; i < 10; i++) { |
1054 | unsigned int mask = snd_usb_combine_bytes(ftr->bmaControls + csize * (j+1), csize); | 1164 | unsigned int ch_bits = 0; |
1055 | if (mask & (1 << i)) | 1165 | for (j = 0; j < channels; j++) { |
1056 | ch_bits |= (1 << j); | 1166 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); |
1167 | if (mask & (1 << i)) | ||
1168 | ch_bits |= (1 << j); | ||
1169 | } | ||
1170 | /* audio class v1 controls are never read-only */ | ||
1171 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | ||
1172 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, 0); | ||
1173 | if (master_bits & (1 << i)) | ||
1174 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, 0); | ||
1175 | } | ||
1176 | } else { /* UAC_VERSION_2 */ | ||
1177 | for (i = 0; i < 30/2; i++) { | ||
1178 | /* From the USB Audio spec v2.0: | ||
1179 | bmaControls() is a (ch+1)-element array of 4-byte bitmaps, | ||
1180 | each containing a set of bit pairs. If a Control is present, | ||
1181 | it must be Host readable. If a certain Control is not | ||
1182 | present then the bit pair must be set to 0b00. | ||
1183 | If a Control is present but read-only, the bit pair must be | ||
1184 | set to 0b01. If a Control is also Host programmable, the bit | ||
1185 | pair must be set to 0b11. The value 0b10 is not allowed. */ | ||
1186 | unsigned int ch_bits = 0; | ||
1187 | unsigned int ch_read_only = 0; | ||
1188 | |||
1189 | for (j = 0; j < channels; j++) { | ||
1190 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); | ||
1191 | if (mask & (1 << (i * 2))) { | ||
1192 | ch_bits |= (1 << j); | ||
1193 | if (~mask & (1 << ((i * 2) + 1))) | ||
1194 | ch_read_only |= (1 << j); | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ | ||
1199 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | ||
1200 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); | ||
1201 | if (master_bits & (1 << i * 2)) | ||
1202 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | ||
1203 | ~master_bits & (1 << ((i * 2) + 1))); | ||
1057 | } | 1204 | } |
1058 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | ||
1059 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid); | ||
1060 | if (master_bits & (1 << i)) | ||
1061 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid); | ||
1062 | } | 1205 | } |
1063 | 1206 | ||
1064 | return 0; | 1207 | return 0; |
@@ -1100,7 +1243,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, | |||
1100 | cval->control = in_ch + 1; /* based on 1 */ | 1243 | cval->control = in_ch + 1; /* based on 1 */ |
1101 | cval->val_type = USB_MIXER_S16; | 1244 | cval->val_type = USB_MIXER_S16; |
1102 | for (i = 0; i < num_outs; i++) { | 1245 | for (i = 0; i < num_outs; i++) { |
1103 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc), in_ch, i, num_outs)) { | 1246 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol), in_ch, i, num_outs)) { |
1104 | cval->cmask |= (1 << i); | 1247 | cval->cmask |= (1 << i); |
1105 | cval->channels++; | 1248 | cval->channels++; |
1106 | } | 1249 | } |
@@ -1164,7 +1307,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r | |||
1164 | int och, ich_has_controls = 0; | 1307 | int och, ich_has_controls = 0; |
1165 | 1308 | ||
1166 | for (och = 0; och < num_outs; ++och) { | 1309 | for (och = 0; och < num_outs; ++och) { |
1167 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc), | 1310 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc, state->mixer->protocol), |
1168 | ich, och, num_outs)) { | 1311 | ich, och, num_outs)) { |
1169 | ich_has_controls = 1; | 1312 | ich_has_controls = 1; |
1170 | break; | 1313 | break; |
@@ -1343,7 +1486,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1343 | 0, NULL, default_value_info | 1486 | 0, NULL, default_value_info |
1344 | }; | 1487 | }; |
1345 | 1488 | ||
1346 | if (desc->bLength < 13 || desc->bLength < 13 + num_ins || desc->bLength < num_ins + uac_processing_unit_bControlSize(desc)) { | 1489 | if (desc->bLength < 13 || desc->bLength < 13 + num_ins || |
1490 | desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) { | ||
1347 | snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid); | 1491 | snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid); |
1348 | return -EINVAL; | 1492 | return -EINVAL; |
1349 | } | 1493 | } |
@@ -1361,7 +1505,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1361 | info = &default_info; | 1505 | info = &default_info; |
1362 | 1506 | ||
1363 | for (valinfo = info->values; valinfo->control; valinfo++) { | 1507 | for (valinfo = info->values; valinfo->control; valinfo++) { |
1364 | __u8 *controls = uac_processing_unit_bmControls(desc); | 1508 | __u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol); |
1365 | 1509 | ||
1366 | if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) | 1510 | if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) |
1367 | continue; | 1511 | continue; |
@@ -1381,7 +1525,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1381 | 1525 | ||
1382 | /* get min/max values */ | 1526 | /* get min/max values */ |
1383 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { | 1527 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { |
1384 | __u8 *control_spec = uac_processing_unit_specific(desc); | 1528 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); |
1385 | /* FIXME: hard-coded */ | 1529 | /* FIXME: hard-coded */ |
1386 | cval->min = 1; | 1530 | cval->min = 1; |
1387 | cval->max = control_spec[0]; | 1531 | cval->max = control_spec[0]; |
@@ -1414,7 +1558,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1414 | else if (info->name) | 1558 | else if (info->name) |
1415 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); | 1559 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); |
1416 | else { | 1560 | else { |
1417 | nameid = uac_processing_unit_iProcessing(desc); | 1561 | nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol); |
1418 | len = 0; | 1562 | len = 0; |
1419 | if (nameid) | 1563 | if (nameid) |
1420 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); | 1564 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); |
@@ -1676,9 +1820,17 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1676 | case UAC_FEATURE_UNIT: | 1820 | case UAC_FEATURE_UNIT: |
1677 | return parse_audio_feature_unit(state, unitid, p1); | 1821 | return parse_audio_feature_unit(state, unitid, p1); |
1678 | case UAC_PROCESSING_UNIT_V1: | 1822 | case UAC_PROCESSING_UNIT_V1: |
1679 | return parse_audio_processing_unit(state, unitid, p1); | 1823 | /* UAC2_EFFECT_UNIT has the same value */ |
1824 | if (state->mixer->protocol == UAC_VERSION_1) | ||
1825 | return parse_audio_processing_unit(state, unitid, p1); | ||
1826 | else | ||
1827 | return 0; /* FIXME - effect units not implemented yet */ | ||
1680 | case UAC_EXTENSION_UNIT_V1: | 1828 | case UAC_EXTENSION_UNIT_V1: |
1681 | return parse_audio_extension_unit(state, unitid, p1); | 1829 | /* UAC2_PROCESSING_UNIT_V2 has the same value */ |
1830 | if (state->mixer->protocol == UAC_VERSION_1) | ||
1831 | return parse_audio_extension_unit(state, unitid, p1); | ||
1832 | else /* UAC_VERSION_2 */ | ||
1833 | return parse_audio_processing_unit(state, unitid, p1); | ||
1682 | default: | 1834 | default: |
1683 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); | 1835 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); |
1684 | return -EINVAL; | 1836 | return -EINVAL; |
@@ -1711,11 +1863,11 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
1711 | */ | 1863 | */ |
1712 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | 1864 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) |
1713 | { | 1865 | { |
1714 | struct uac_output_terminal_descriptor_v1 *desc; | ||
1715 | struct mixer_build state; | 1866 | struct mixer_build state; |
1716 | int err; | 1867 | int err; |
1717 | const struct usbmix_ctl_map *map; | 1868 | const struct usbmix_ctl_map *map; |
1718 | struct usb_host_interface *hostif; | 1869 | struct usb_host_interface *hostif; |
1870 | void *p; | ||
1719 | 1871 | ||
1720 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; | 1872 | hostif = &usb_ifnum_to_if(mixer->chip->dev, mixer->ctrlif)->altsetting[0]; |
1721 | memset(&state, 0, sizeof(state)); | 1873 | memset(&state, 0, sizeof(state)); |
@@ -1734,18 +1886,35 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1734 | } | 1886 | } |
1735 | } | 1887 | } |
1736 | 1888 | ||
1737 | desc = NULL; | 1889 | p = NULL; |
1738 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) { | 1890 | while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) { |
1739 | if (desc->bLength < 9) | 1891 | if (mixer->protocol == UAC_VERSION_1) { |
1740 | continue; /* invalid descriptor? */ | 1892 | struct uac_output_terminal_descriptor_v1 *desc = p; |
1741 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ | 1893 | |
1742 | state.oterm.id = desc->bTerminalID; | 1894 | if (desc->bLength < sizeof(*desc)) |
1743 | state.oterm.type = le16_to_cpu(desc->wTerminalType); | 1895 | continue; /* invalid descriptor? */ |
1744 | state.oterm.name = desc->iTerminal; | 1896 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ |
1745 | err = parse_audio_unit(&state, desc->bSourceID); | 1897 | state.oterm.id = desc->bTerminalID; |
1746 | if (err < 0) | 1898 | state.oterm.type = le16_to_cpu(desc->wTerminalType); |
1747 | return err; | 1899 | state.oterm.name = desc->iTerminal; |
1900 | err = parse_audio_unit(&state, desc->bSourceID); | ||
1901 | if (err < 0) | ||
1902 | return err; | ||
1903 | } else { /* UAC_VERSION_2 */ | ||
1904 | struct uac2_output_terminal_descriptor *desc = p; | ||
1905 | |||
1906 | if (desc->bLength < sizeof(*desc)) | ||
1907 | continue; /* invalid descriptor? */ | ||
1908 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ | ||
1909 | state.oterm.id = desc->bTerminalID; | ||
1910 | state.oterm.type = le16_to_cpu(desc->wTerminalType); | ||
1911 | state.oterm.name = desc->iTerminal; | ||
1912 | err = parse_audio_unit(&state, desc->bSourceID); | ||
1913 | if (err < 0) | ||
1914 | return err; | ||
1915 | } | ||
1748 | } | 1916 | } |
1917 | |||
1749 | return 0; | 1918 | return 0; |
1750 | } | 1919 | } |
1751 | 1920 | ||
@@ -1868,7 +2037,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
1868 | struct usb_mixer_interface *mixer; | 2037 | struct usb_mixer_interface *mixer; |
1869 | struct snd_info_entry *entry; | 2038 | struct snd_info_entry *entry; |
1870 | struct usb_host_interface *host_iface; | 2039 | struct usb_host_interface *host_iface; |
1871 | int err, protocol; | 2040 | int err; |
1872 | 2041 | ||
1873 | strcpy(chip->card->mixername, "USB Mixer"); | 2042 | strcpy(chip->card->mixername, "USB Mixer"); |
1874 | 2043 | ||
@@ -1886,14 +2055,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
1886 | } | 2055 | } |
1887 | 2056 | ||
1888 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; | 2057 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; |
1889 | protocol = host_iface->desc.bInterfaceProtocol; | 2058 | mixer->protocol = host_iface->desc.bInterfaceProtocol; |
1890 | |||
1891 | /* FIXME! */ | ||
1892 | if (protocol != UAC_VERSION_1) { | ||
1893 | snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n", | ||
1894 | protocol); | ||
1895 | return 0; | ||
1896 | } | ||
1897 | 2059 | ||
1898 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 2060 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || |
1899 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 2061 | (err = snd_usb_mixer_status_create(mixer)) < 0) |
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 63101ae201cc..130123854a6c 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -10,6 +10,9 @@ struct usb_mixer_interface { | |||
10 | /* array[MAX_ID_ELEMS], indexed by unit id */ | 10 | /* array[MAX_ID_ELEMS], indexed by unit id */ |
11 | struct usb_mixer_elem_info **id_elems; | 11 | struct usb_mixer_elem_info **id_elems; |
12 | 12 | ||
13 | /* the usb audio specification version this interface complies to */ | ||
14 | int protocol; | ||
15 | |||
13 | /* Sound Blaster remote control stuff */ | 16 | /* Sound Blaster remote control stuff */ |
14 | const struct rc_config *rc_cfg; | 17 | const struct rc_config *rc_cfg; |
15 | u32 rc_code; | 18 | u32 rc_code; |