diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 245 |
1 files changed, 143 insertions, 102 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 03ce971e0027..736d134cc03c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -78,39 +78,6 @@ enum { | |||
78 | USB_MIXER_U16, | 78 | USB_MIXER_U16, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | enum { | ||
82 | USB_PROC_UPDOWN = 1, | ||
83 | USB_PROC_UPDOWN_SWITCH = 1, | ||
84 | USB_PROC_UPDOWN_MODE_SEL = 2, | ||
85 | |||
86 | USB_PROC_PROLOGIC = 2, | ||
87 | USB_PROC_PROLOGIC_SWITCH = 1, | ||
88 | USB_PROC_PROLOGIC_MODE_SEL = 2, | ||
89 | |||
90 | USB_PROC_3DENH = 3, | ||
91 | USB_PROC_3DENH_SWITCH = 1, | ||
92 | USB_PROC_3DENH_SPACE = 2, | ||
93 | |||
94 | USB_PROC_REVERB = 4, | ||
95 | USB_PROC_REVERB_SWITCH = 1, | ||
96 | USB_PROC_REVERB_LEVEL = 2, | ||
97 | USB_PROC_REVERB_TIME = 3, | ||
98 | USB_PROC_REVERB_DELAY = 4, | ||
99 | |||
100 | USB_PROC_CHORUS = 5, | ||
101 | USB_PROC_CHORUS_SWITCH = 1, | ||
102 | USB_PROC_CHORUS_LEVEL = 2, | ||
103 | USB_PROC_CHORUS_RATE = 3, | ||
104 | USB_PROC_CHORUS_DEPTH = 4, | ||
105 | |||
106 | USB_PROC_DCR = 6, | ||
107 | USB_PROC_DCR_SWITCH = 1, | ||
108 | USB_PROC_DCR_RATIO = 2, | ||
109 | USB_PROC_DCR_MAX_AMP = 3, | ||
110 | USB_PROC_DCR_THRESHOLD = 4, | ||
111 | USB_PROC_DCR_ATTACK = 5, | ||
112 | USB_PROC_DCR_RELEASE = 6, | ||
113 | }; | ||
114 | 81 | ||
115 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | 82 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ |
116 | enum { | 83 | enum { |
@@ -198,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid, | |||
198 | 165 | ||
199 | /* | 166 | /* |
200 | * find an audio control unit with the given unit id | 167 | * 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 | ||
202 | */ | 168 | */ |
203 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) | 169 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) |
204 | { | 170 | { |
205 | unsigned char *p; | 171 | /* we just parse the header */ |
172 | struct uac_feature_unit_descriptor *hdr = NULL; | ||
206 | 173 | ||
207 | p = NULL; | 174 | while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr, |
208 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 175 | USB_DT_CS_INTERFACE)) != NULL) { |
209 | USB_DT_CS_INTERFACE)) != NULL) { | 176 | if (hdr->bLength >= 4 && |
210 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit) | 177 | hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL && |
211 | return p; | 178 | hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER && |
179 | hdr->bUnitID == unit) | ||
180 | return hdr; | ||
212 | } | 181 | } |
182 | |||
213 | return NULL; | 183 | return NULL; |
214 | } | 184 | } |
215 | 185 | ||
216 | |||
217 | /* | 186 | /* |
218 | * copy a string with the given id | 187 | * copy a string with the given id |
219 | */ | 188 | */ |
@@ -328,27 +297,36 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v | |||
328 | 297 | ||
329 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 298 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
330 | { | 299 | { |
331 | unsigned char buf[14]; /* enough space for one range of 4 bytes */ | 300 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ |
332 | unsigned char *val; | 301 | unsigned char *val; |
333 | int ret; | 302 | int ret, size; |
334 | __u8 bRequest; | 303 | __u8 bRequest; |
335 | 304 | ||
336 | bRequest = (request == UAC_GET_CUR) ? | 305 | if (request == UAC_GET_CUR) { |
337 | UAC2_CS_CUR : UAC2_CS_RANGE; | 306 | bRequest = UAC2_CS_CUR; |
307 | size = sizeof(__u16); | ||
308 | } else { | ||
309 | bRequest = UAC2_CS_RANGE; | ||
310 | size = sizeof(buf); | ||
311 | } | ||
312 | |||
313 | memset(buf, 0, sizeof(buf)); | ||
338 | 314 | ||
339 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, | 315 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, |
340 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | 316 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), |
341 | bRequest, | 317 | bRequest, |
342 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 318 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
343 | validx, cval->mixer->ctrlif | (cval->id << 8), | 319 | validx, cval->mixer->ctrlif | (cval->id << 8), |
344 | buf, sizeof(buf), 1000); | 320 | buf, size, 1000); |
345 | 321 | ||
346 | if (ret < 0) { | 322 | if (ret < 0) { |
347 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 323 | snd_printk(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); | 324 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); |
349 | return ret; | 325 | return ret; |
350 | } | 326 | } |
351 | 327 | ||
328 | /* FIXME: how should we handle multiple triplets here? */ | ||
329 | |||
352 | switch (request) { | 330 | switch (request) { |
353 | case UAC_GET_CUR: | 331 | case UAC_GET_CUR: |
354 | val = buf; | 332 | val = buf; |
@@ -462,6 +440,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | |||
462 | int index, int value) | 440 | int index, int value) |
463 | { | 441 | { |
464 | int err; | 442 | int err; |
443 | unsigned int read_only = (channel == 0) ? | ||
444 | cval->master_readonly : | ||
445 | cval->ch_readonly & (1 << (channel - 1)); | ||
446 | |||
447 | if (read_only) { | ||
448 | snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", | ||
449 | __func__, channel, cval->control); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
465 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, | 453 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
466 | value); | 454 | value); |
467 | if (err < 0) | 455 | if (err < 0) |
@@ -631,6 +619,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
631 | */ | 619 | */ |
632 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) | 620 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) |
633 | { | 621 | { |
622 | int err; | ||
634 | void *p1; | 623 | void *p1; |
635 | 624 | ||
636 | memset(term, 0, sizeof(*term)); | 625 | memset(term, 0, sizeof(*term)); |
@@ -651,6 +640,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
651 | term->channels = d->bNrChannels; | 640 | term->channels = d->bNrChannels; |
652 | term->chconfig = le32_to_cpu(d->bmChannelConfig); | 641 | term->chconfig = le32_to_cpu(d->bmChannelConfig); |
653 | term->name = d->iTerminal; | 642 | term->name = d->iTerminal; |
643 | |||
644 | /* call recursively to get the clock selectors */ | ||
645 | err = check_input_term(state, d->bCSourceID, term); | ||
646 | if (err < 0) | ||
647 | return err; | ||
654 | } | 648 | } |
655 | return 0; | 649 | return 0; |
656 | case UAC_FEATURE_UNIT: { | 650 | case UAC_FEATURE_UNIT: { |
@@ -667,7 +661,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
667 | term->name = uac_mixer_unit_iMixer(d); | 661 | term->name = uac_mixer_unit_iMixer(d); |
668 | return 0; | 662 | return 0; |
669 | } | 663 | } |
670 | case UAC_SELECTOR_UNIT: { | 664 | case UAC_SELECTOR_UNIT: |
665 | case UAC2_CLOCK_SELECTOR: { | ||
671 | struct uac_selector_unit_descriptor *d = p1; | 666 | struct uac_selector_unit_descriptor *d = p1; |
672 | /* call recursively to retrieve the channel info */ | 667 | /* call recursively to retrieve the channel info */ |
673 | if (check_input_term(state, d->baSourceID[0], term) < 0) | 668 | if (check_input_term(state, d->baSourceID[0], term) < 0) |
@@ -690,6 +685,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
690 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); | 685 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); |
691 | return 0; | 686 | return 0; |
692 | } | 687 | } |
688 | case UAC2_CLOCK_SOURCE: { | ||
689 | struct uac_clock_source_descriptor *d = p1; | ||
690 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
691 | term->id = id; | ||
692 | term->name = d->iClockSource; | ||
693 | return 0; | ||
694 | } | ||
693 | default: | 695 | default: |
694 | return -ENODEV; | 696 | return -ENODEV; |
695 | } | 697 | } |
@@ -709,16 +711,20 @@ struct usb_feature_control_info { | |||
709 | }; | 711 | }; |
710 | 712 | ||
711 | static struct usb_feature_control_info audio_feature_info[] = { | 713 | static struct usb_feature_control_info audio_feature_info[] = { |
712 | { "Mute", USB_MIXER_INV_BOOLEAN }, | 714 | { "Mute", USB_MIXER_INV_BOOLEAN }, |
713 | { "Volume", USB_MIXER_S16 }, | 715 | { "Volume", USB_MIXER_S16 }, |
714 | { "Tone Control - Bass", USB_MIXER_S8 }, | 716 | { "Tone Control - Bass", USB_MIXER_S8 }, |
715 | { "Tone Control - Mid", USB_MIXER_S8 }, | 717 | { "Tone Control - Mid", USB_MIXER_S8 }, |
716 | { "Tone Control - Treble", USB_MIXER_S8 }, | 718 | { "Tone Control - Treble", USB_MIXER_S8 }, |
717 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ | 719 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ |
718 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, | 720 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, |
719 | { "Delay Control", USB_MIXER_U16 }, | 721 | { "Delay Control", USB_MIXER_U16 }, |
720 | { "Bass Boost", USB_MIXER_BOOLEAN }, | 722 | { "Bass Boost", USB_MIXER_BOOLEAN }, |
721 | { "Loudness", USB_MIXER_BOOLEAN }, | 723 | { "Loudness", USB_MIXER_BOOLEAN }, |
724 | /* UAC2 specific */ | ||
725 | { "Input Gain Control", USB_MIXER_U16 }, | ||
726 | { "Input Gain Pad Control", USB_MIXER_BOOLEAN }, | ||
727 | { "Phase Inverter Control", USB_MIXER_BOOLEAN }, | ||
722 | }; | 728 | }; |
723 | 729 | ||
724 | 730 | ||
@@ -958,7 +964,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
958 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 964 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
959 | unsigned int ctl_mask, int control, | 965 | unsigned int ctl_mask, int control, |
960 | struct usb_audio_term *iterm, int unitid, | 966 | struct usb_audio_term *iterm, int unitid, |
961 | int read_only) | 967 | int readonly_mask) |
962 | { | 968 | { |
963 | struct uac_feature_unit_descriptor *desc = raw_desc; | 969 | struct uac_feature_unit_descriptor *desc = raw_desc; |
964 | unsigned int len = 0; | 970 | unsigned int len = 0; |
@@ -970,7 +976,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
970 | 976 | ||
971 | control++; /* change from zero-based to 1-based value */ | 977 | control++; /* change from zero-based to 1-based value */ |
972 | 978 | ||
973 | if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) { | 979 | if (control == UAC_FU_GRAPHIC_EQUALIZER) { |
974 | /* FIXME: not supported yet */ | 980 | /* FIXME: not supported yet */ |
975 | return; | 981 | return; |
976 | } | 982 | } |
@@ -989,20 +995,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
989 | cval->control = control; | 995 | cval->control = control; |
990 | cval->cmask = ctl_mask; | 996 | cval->cmask = ctl_mask; |
991 | cval->val_type = audio_feature_info[control-1].type; | 997 | cval->val_type = audio_feature_info[control-1].type; |
992 | if (ctl_mask == 0) | 998 | if (ctl_mask == 0) { |
993 | cval->channels = 1; /* master channel */ | 999 | cval->channels = 1; /* master channel */ |
994 | else { | 1000 | cval->master_readonly = readonly_mask; |
1001 | } else { | ||
995 | int i, c = 0; | 1002 | int i, c = 0; |
996 | for (i = 0; i < 16; i++) | 1003 | for (i = 0; i < 16; i++) |
997 | if (ctl_mask & (1 << i)) | 1004 | if (ctl_mask & (1 << i)) |
998 | c++; | 1005 | c++; |
999 | cval->channels = c; | 1006 | cval->channels = c; |
1007 | cval->ch_readonly = readonly_mask; | ||
1000 | } | 1008 | } |
1001 | 1009 | ||
1002 | /* get min/max values */ | 1010 | /* get min/max values */ |
1003 | get_min_max(cval, 0); | 1011 | get_min_max(cval, 0); |
1004 | 1012 | ||
1005 | if (read_only) | 1013 | /* if all channels in the mask are marked read-only, make the control |
1014 | * read-only. set_cur_mix_value() will check the mask again and won't | ||
1015 | * issue write commands to read-only channels. */ | ||
1016 | if (cval->channels == readonly_mask) | ||
1006 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); | 1017 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); |
1007 | else | 1018 | else |
1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1019 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
@@ -1021,8 +1032,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1021 | kctl->id.name, sizeof(kctl->id.name)); | 1032 | kctl->id.name, sizeof(kctl->id.name)); |
1022 | 1033 | ||
1023 | switch (control) { | 1034 | switch (control) { |
1024 | case UAC_MUTE_CONTROL: | 1035 | case UAC_FU_MUTE: |
1025 | case UAC_VOLUME_CONTROL: | 1036 | case UAC_FU_VOLUME: |
1026 | /* determine the control name. the rule is: | 1037 | /* determine the control name. the rule is: |
1027 | * - if a name id is given in descriptor, use it. | 1038 | * - if a name id is given in descriptor, use it. |
1028 | * - if the connected input can be determined, then use the name | 1039 | * - if the connected input can be determined, then use the name |
@@ -1049,9 +1060,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1049 | len = append_ctl_name(kctl, " Playback"); | 1060 | len = append_ctl_name(kctl, " Playback"); |
1050 | } | 1061 | } |
1051 | } | 1062 | } |
1052 | append_ctl_name(kctl, control == UAC_MUTE_CONTROL ? | 1063 | append_ctl_name(kctl, control == UAC_FU_MUTE ? |
1053 | " Switch" : " Volume"); | 1064 | " Switch" : " Volume"); |
1054 | if (control == UAC_VOLUME_CONTROL) { | 1065 | if (control == UAC_FU_VOLUME) { |
1055 | kctl->tlv.c = mixer_vol_tlv; | 1066 | kctl->tlv.c = mixer_vol_tlv; |
1056 | kctl->vd[0].access |= | 1067 | kctl->vd[0].access |= |
1057 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1068 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
@@ -1096,6 +1107,19 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1096 | } | 1107 | } |
1097 | break; | 1108 | break; |
1098 | 1109 | ||
1110 | case USB_ID(0x046d, 0x0809): | ||
1111 | case USB_ID(0x046d, 0x0991): | ||
1112 | /* Most audio usb devices lie about volume resolution. | ||
1113 | * Most Logitech webcams have res = 384. | ||
1114 | * Proboly there is some logitech magic behind this number --fishor | ||
1115 | */ | ||
1116 | if (!strcmp(kctl->id.name, "Mic Capture Volume")) { | ||
1117 | snd_printk(KERN_INFO | ||
1118 | "set resolution quirk: cval->res = 384\n"); | ||
1119 | cval->res = 384; | ||
1120 | } | ||
1121 | break; | ||
1122 | |||
1099 | } | 1123 | } |
1100 | 1124 | ||
1101 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 1125 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
@@ -1150,7 +1174,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1150 | snd_printk(KERN_INFO | 1174 | snd_printk(KERN_INFO |
1151 | "usbmixer: master volume quirk for PCM2702 chip\n"); | 1175 | "usbmixer: master volume quirk for PCM2702 chip\n"); |
1152 | /* disable non-functional volume control */ | 1176 | /* disable non-functional volume control */ |
1153 | master_bits &= ~UAC_FU_VOLUME; | 1177 | master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); |
1154 | break; | 1178 | break; |
1155 | } | 1179 | } |
1156 | if (channels > 0) | 1180 | if (channels > 0) |
@@ -1188,19 +1212,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1188 | 1212 | ||
1189 | for (j = 0; j < channels; j++) { | 1213 | for (j = 0; j < channels; j++) { |
1190 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); | 1214 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); |
1191 | if (mask & (1 << (i * 2))) { | 1215 | if (uac2_control_is_readable(mask, i)) { |
1192 | ch_bits |= (1 << j); | 1216 | ch_bits |= (1 << j); |
1193 | if (~mask & (1 << ((i * 2) + 1))) | 1217 | if (!uac2_control_is_writeable(mask, i)) |
1194 | ch_read_only |= (1 << j); | 1218 | ch_read_only |= (1 << j); |
1195 | } | 1219 | } |
1196 | } | 1220 | } |
1197 | 1221 | ||
1198 | /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ | 1222 | /* NOTE: build_feature_ctl() will mark the control read-only if all channels |
1223 | * are marked read-only in the descriptors. Otherwise, the control will be | ||
1224 | * reported as writeable, but the driver will not actually issue a write | ||
1225 | * command for read-only channels */ | ||
1199 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1226 | 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); | 1227 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); |
1201 | if (master_bits & (1 << i * 2)) | 1228 | if (uac2_control_is_readable(master_bits, i)) |
1202 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | 1229 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, |
1203 | ~master_bits & (1 << ((i * 2) + 1))); | 1230 | !uac2_control_is_writeable(master_bits, i)); |
1204 | } | 1231 | } |
1205 | } | 1232 | } |
1206 | 1233 | ||
@@ -1392,51 +1419,51 @@ struct procunit_info { | |||
1392 | }; | 1419 | }; |
1393 | 1420 | ||
1394 | static struct procunit_value_info updown_proc_info[] = { | 1421 | static struct procunit_value_info updown_proc_info[] = { |
1395 | { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1422 | { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1396 | { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1423 | { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
1397 | { 0 } | 1424 | { 0 } |
1398 | }; | 1425 | }; |
1399 | static struct procunit_value_info prologic_proc_info[] = { | 1426 | static struct procunit_value_info prologic_proc_info[] = { |
1400 | { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1427 | { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1401 | { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1428 | { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
1402 | { 0 } | 1429 | { 0 } |
1403 | }; | 1430 | }; |
1404 | static struct procunit_value_info threed_enh_proc_info[] = { | 1431 | static struct procunit_value_info threed_enh_proc_info[] = { |
1405 | { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1432 | { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1406 | { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 }, | 1433 | { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 }, |
1407 | { 0 } | 1434 | { 0 } |
1408 | }; | 1435 | }; |
1409 | static struct procunit_value_info reverb_proc_info[] = { | 1436 | static struct procunit_value_info reverb_proc_info[] = { |
1410 | { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1437 | { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1411 | { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, | 1438 | { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, |
1412 | { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 }, | 1439 | { UAC_REVERB_TIME, "Time", USB_MIXER_U16 }, |
1413 | { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 }, | 1440 | { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 }, |
1414 | { 0 } | 1441 | { 0 } |
1415 | }; | 1442 | }; |
1416 | static struct procunit_value_info chorus_proc_info[] = { | 1443 | static struct procunit_value_info chorus_proc_info[] = { |
1417 | { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1444 | { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1418 | { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, | 1445 | { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, |
1419 | { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, | 1446 | { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, |
1420 | { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, | 1447 | { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, |
1421 | { 0 } | 1448 | { 0 } |
1422 | }; | 1449 | }; |
1423 | static struct procunit_value_info dcr_proc_info[] = { | 1450 | static struct procunit_value_info dcr_proc_info[] = { |
1424 | { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1451 | { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1425 | { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 }, | 1452 | { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 }, |
1426 | { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 }, | 1453 | { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 }, |
1427 | { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, | 1454 | { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, |
1428 | { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 }, | 1455 | { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 }, |
1429 | { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 }, | 1456 | { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 }, |
1430 | { 0 } | 1457 | { 0 } |
1431 | }; | 1458 | }; |
1432 | 1459 | ||
1433 | static struct procunit_info procunits[] = { | 1460 | static struct procunit_info procunits[] = { |
1434 | { USB_PROC_UPDOWN, "Up Down", updown_proc_info }, | 1461 | { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info }, |
1435 | { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info }, | 1462 | { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info }, |
1436 | { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info }, | 1463 | { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info }, |
1437 | { USB_PROC_REVERB, "Reverb", reverb_proc_info }, | 1464 | { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info }, |
1438 | { USB_PROC_CHORUS, "Chorus", chorus_proc_info }, | 1465 | { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info }, |
1439 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1466 | { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, |
1440 | { 0 }, | 1467 | { 0 }, |
1441 | }; | 1468 | }; |
1442 | /* | 1469 | /* |
@@ -1524,7 +1551,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1524 | cval->channels = 1; | 1551 | cval->channels = 1; |
1525 | 1552 | ||
1526 | /* get min/max values */ | 1553 | /* get min/max values */ |
1527 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { | 1554 | if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { |
1528 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); | 1555 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); |
1529 | /* FIXME: hard-coded */ | 1556 | /* FIXME: hard-coded */ |
1530 | cval->min = 1; | 1557 | cval->min = 1; |
@@ -1619,7 +1646,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1619 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1646 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1620 | int val, err; | 1647 | int val, err; |
1621 | 1648 | ||
1622 | err = get_cur_ctl_value(cval, 0, &val); | 1649 | err = get_cur_ctl_value(cval, cval->control << 8, &val); |
1623 | if (err < 0) { | 1650 | if (err < 0) { |
1624 | if (cval->mixer->ignore_ctl_error) { | 1651 | if (cval->mixer->ignore_ctl_error) { |
1625 | ucontrol->value.enumerated.item[0] = 0; | 1652 | ucontrol->value.enumerated.item[0] = 0; |
@@ -1638,7 +1665,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1638 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1665 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1639 | int val, oval, err; | 1666 | int val, oval, err; |
1640 | 1667 | ||
1641 | err = get_cur_ctl_value(cval, 0, &oval); | 1668 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); |
1642 | if (err < 0) { | 1669 | if (err < 0) { |
1643 | if (cval->mixer->ignore_ctl_error) | 1670 | if (cval->mixer->ignore_ctl_error) |
1644 | return 0; | 1671 | return 0; |
@@ -1647,7 +1674,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1647 | val = ucontrol->value.enumerated.item[0]; | 1674 | val = ucontrol->value.enumerated.item[0]; |
1648 | val = get_abs_value(cval, val); | 1675 | val = get_abs_value(cval, val); |
1649 | if (val != oval) { | 1676 | if (val != oval) { |
1650 | set_cur_ctl_value(cval, 0, val); | 1677 | set_cur_ctl_value(cval, cval->control << 8, val); |
1651 | return 1; | 1678 | return 1; |
1652 | } | 1679 | } |
1653 | return 0; | 1680 | return 0; |
@@ -1729,6 +1756,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1729 | cval->res = 1; | 1756 | cval->res = 1; |
1730 | cval->initialized = 1; | 1757 | cval->initialized = 1; |
1731 | 1758 | ||
1759 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | ||
1760 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
1761 | else | ||
1762 | cval->control = 0; | ||
1763 | |||
1732 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); | 1764 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
1733 | if (! namelist) { | 1765 | if (! namelist) { |
1734 | snd_printk(KERN_ERR "cannot malloc\n"); | 1766 | snd_printk(KERN_ERR "cannot malloc\n"); |
@@ -1778,7 +1810,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1778 | if (! len) | 1810 | if (! len) |
1779 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 1811 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
1780 | 1812 | ||
1781 | if ((state->oterm.type & 0xff00) == 0x0100) | 1813 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) |
1814 | append_ctl_name(kctl, " Clock Source"); | ||
1815 | else if ((state->oterm.type & 0xff00) == 0x0100) | ||
1782 | append_ctl_name(kctl, " Capture Source"); | 1816 | append_ctl_name(kctl, " Capture Source"); |
1783 | else | 1817 | else |
1784 | append_ctl_name(kctl, " Playback Source"); | 1818 | append_ctl_name(kctl, " Playback Source"); |
@@ -1812,10 +1846,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1812 | 1846 | ||
1813 | switch (p1[2]) { | 1847 | switch (p1[2]) { |
1814 | case UAC_INPUT_TERMINAL: | 1848 | case UAC_INPUT_TERMINAL: |
1849 | case UAC2_CLOCK_SOURCE: | ||
1815 | return 0; /* NOP */ | 1850 | return 0; /* NOP */ |
1816 | case UAC_MIXER_UNIT: | 1851 | case UAC_MIXER_UNIT: |
1817 | return parse_audio_mixer_unit(state, unitid, p1); | 1852 | return parse_audio_mixer_unit(state, unitid, p1); |
1818 | case UAC_SELECTOR_UNIT: | 1853 | case UAC_SELECTOR_UNIT: |
1854 | case UAC2_CLOCK_SELECTOR: | ||
1819 | return parse_audio_selector_unit(state, unitid, p1); | 1855 | return parse_audio_selector_unit(state, unitid, p1); |
1820 | case UAC_FEATURE_UNIT: | 1856 | case UAC_FEATURE_UNIT: |
1821 | return parse_audio_feature_unit(state, unitid, p1); | 1857 | return parse_audio_feature_unit(state, unitid, p1); |
@@ -1912,6 +1948,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1912 | err = parse_audio_unit(&state, desc->bSourceID); | 1948 | err = parse_audio_unit(&state, desc->bSourceID); |
1913 | if (err < 0) | 1949 | if (err < 0) |
1914 | return err; | 1950 | return err; |
1951 | |||
1952 | /* for UAC2, use the same approach to also add the clock selectors */ | ||
1953 | err = parse_audio_unit(&state, desc->bCSourceID); | ||
1954 | if (err < 0) | ||
1955 | return err; | ||
1915 | } | 1956 | } |
1916 | } | 1957 | } |
1917 | 1958 | ||