diff options
-rw-r--r-- | include/linux/usb/audio.h | 129 | ||||
-rw-r--r-- | sound/usb/mixer.c | 87 |
2 files changed, 166 insertions, 50 deletions
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index cdad728543ae..bc78a83d0f48 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h | |||
@@ -181,6 +181,125 @@ struct uac_feature_unit_descriptor_##ch { \ | |||
181 | __u8 iFeature; \ | 181 | __u8 iFeature; \ |
182 | } __attribute__ ((packed)) | 182 | } __attribute__ ((packed)) |
183 | 183 | ||
184 | /* 4.3.2.3 Mixer Unit Descriptor */ | ||
185 | struct uac_mixer_unit_descriptor { | ||
186 | __u8 bLength; | ||
187 | __u8 bDescriptorType; | ||
188 | __u8 bDescriptorSubtype; | ||
189 | __u8 bUnitID; | ||
190 | __u8 bNrInPins; | ||
191 | __u8 baSourceID[]; | ||
192 | } __attribute__ ((packed)); | ||
193 | |||
194 | static inline __u8 uac_mixer_unit_bNrChannels(struct uac_mixer_unit_descriptor *desc) | ||
195 | { | ||
196 | return desc->baSourceID[desc->bNrInPins]; | ||
197 | } | ||
198 | |||
199 | static inline __u16 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc) | ||
200 | { | ||
201 | return (desc->baSourceID[desc->bNrInPins + 2] << 8) | | ||
202 | desc->baSourceID[desc->bNrInPins + 1]; | ||
203 | } | ||
204 | |||
205 | static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc) | ||
206 | { | ||
207 | return desc->baSourceID[desc->bNrInPins + 3]; | ||
208 | } | ||
209 | |||
210 | static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc) | ||
211 | { | ||
212 | return &desc->baSourceID[desc->bNrInPins + 4]; | ||
213 | } | ||
214 | |||
215 | static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc) | ||
216 | { | ||
217 | __u8 *raw = (__u8 *) desc; | ||
218 | return raw[desc->bLength - 1]; | ||
219 | } | ||
220 | |||
221 | /* 4.3.2.4 Selector Unit Descriptor */ | ||
222 | struct uac_selector_unit_descriptor { | ||
223 | __u8 bLength; | ||
224 | __u8 bDescriptorType; | ||
225 | __u8 bDescriptorSubtype; | ||
226 | __u8 bUintID; | ||
227 | __u8 bNrInPins; | ||
228 | __u8 baSourceID[]; | ||
229 | } __attribute__ ((packed)); | ||
230 | |||
231 | static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) | ||
232 | { | ||
233 | __u8 *raw = (__u8 *) desc; | ||
234 | return raw[desc->bLength - 1]; | ||
235 | } | ||
236 | |||
237 | /* 4.3.2.5 Feature Unit Descriptor */ | ||
238 | struct uac_feature_unit_descriptor { | ||
239 | __u8 bLength; | ||
240 | __u8 bDescriptorType; | ||
241 | __u8 bDescriptorSubtype; | ||
242 | __u8 bUnitID; | ||
243 | __u8 bSourceID; | ||
244 | __u8 bControlSize; | ||
245 | __u8 bmaControls[0]; /* variable length */ | ||
246 | } __attribute__((packed)); | ||
247 | |||
248 | static inline __u8 uac_feature_unit_iFeature(struct uac_feature_unit_descriptor *desc) | ||
249 | { | ||
250 | __u8 *raw = (__u8 *) desc; | ||
251 | return raw[desc->bLength - 1]; | ||
252 | } | ||
253 | |||
254 | /* 4.3.2.6 Processing Unit Descriptors */ | ||
255 | struct uac_processing_unit_descriptor { | ||
256 | __u8 bLength; | ||
257 | __u8 bDescriptorType; | ||
258 | __u8 bDescriptorSubtype; | ||
259 | __u8 bUnitID; | ||
260 | __u16 wProcessType; | ||
261 | __u8 bNrInPins; | ||
262 | __u8 baSourceID[]; | ||
263 | } __attribute__ ((packed)); | ||
264 | |||
265 | static inline __u8 uac_processing_unit_bNrChannels(struct uac_processing_unit_descriptor *desc) | ||
266 | { | ||
267 | return desc->baSourceID[desc->bNrInPins]; | ||
268 | } | ||
269 | |||
270 | static inline __u16 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc) | ||
271 | { | ||
272 | return (desc->baSourceID[desc->bNrInPins + 2] << 8) | | ||
273 | desc->baSourceID[desc->bNrInPins + 1]; | ||
274 | } | ||
275 | |||
276 | static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc) | ||
277 | { | ||
278 | return desc->baSourceID[desc->bNrInPins + 3]; | ||
279 | } | ||
280 | |||
281 | static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc) | ||
282 | { | ||
283 | return desc->baSourceID[desc->bNrInPins + 4]; | ||
284 | } | ||
285 | |||
286 | static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc) | ||
287 | { | ||
288 | return &desc->baSourceID[desc->bNrInPins + 5]; | ||
289 | } | ||
290 | |||
291 | static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc) | ||
292 | { | ||
293 | __u8 control_size = uac_processing_unit_bControlSize(desc); | ||
294 | return desc->baSourceID[desc->bNrInPins + control_size]; | ||
295 | } | ||
296 | |||
297 | static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc) | ||
298 | { | ||
299 | __u8 control_size = uac_processing_unit_bControlSize(desc); | ||
300 | return &desc->baSourceID[desc->bNrInPins + control_size + 1]; | ||
301 | } | ||
302 | |||
184 | /* 4.5.2 Class-Specific AS Interface Descriptor */ | 303 | /* 4.5.2 Class-Specific AS Interface Descriptor */ |
185 | struct uac_as_header_descriptor_v1 { | 304 | struct uac_as_header_descriptor_v1 { |
186 | __u8 bLength; /* in bytes: 7 */ | 305 | __u8 bLength; /* in bytes: 7 */ |
@@ -315,16 +434,6 @@ struct uac_iso_endpoint_descriptor { | |||
315 | 434 | ||
316 | /* A.10.2 Feature Unit Control Selectors */ | 435 | /* A.10.2 Feature Unit Control Selectors */ |
317 | 436 | ||
318 | struct uac_feature_unit_descriptor { | ||
319 | __u8 bLength; | ||
320 | __u8 bDescriptorType; | ||
321 | __u8 bDescriptorSubtype; | ||
322 | __u8 bUnitID; | ||
323 | __u8 bSourceID; | ||
324 | __u8 bControlSize; | ||
325 | __u8 controls[0]; /* variable length */ | ||
326 | } __attribute__((packed)); | ||
327 | |||
328 | #define UAC_FU_CONTROL_UNDEFINED 0x00 | 437 | #define UAC_FU_CONTROL_UNDEFINED 0x00 |
329 | #define UAC_MUTE_CONTROL 0x01 | 438 | #define UAC_MUTE_CONTROL 0x01 |
330 | #define UAC_VOLUME_CONTROL 0x02 | 439 | #define UAC_VOLUME_CONTROL 0x02 |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 4e7c2fd9e3b4..994b0385235c 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -860,13 +860,14 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
860 | return strlcat(kctl->id.name, str, sizeof(kctl->id.name)); | 860 | return strlcat(kctl->id.name, str, sizeof(kctl->id.name)); |
861 | } | 861 | } |
862 | 862 | ||
863 | static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | 863 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
864 | unsigned int ctl_mask, int control, | 864 | unsigned int ctl_mask, int control, |
865 | struct usb_audio_term *iterm, int unitid) | 865 | struct usb_audio_term *iterm, int unitid) |
866 | { | 866 | { |
867 | struct uac_feature_unit_descriptor *desc = raw_desc; | ||
867 | unsigned int len = 0; | 868 | unsigned int len = 0; |
868 | int mapped_name = 0; | 869 | int mapped_name = 0; |
869 | int nameid = desc[desc[0] - 1]; | 870 | int nameid = uac_feature_unit_iFeature(desc); |
870 | struct snd_kcontrol *kctl; | 871 | struct snd_kcontrol *kctl; |
871 | struct usb_mixer_elem_info *cval; | 872 | struct usb_mixer_elem_info *cval; |
872 | const struct usbmix_name_map *map; | 873 | const struct usbmix_name_map *map; |
@@ -1032,7 +1033,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1032 | 1033 | ||
1033 | channels = (ftr->bLength - 7) / csize - 1; | 1034 | channels = (ftr->bLength - 7) / csize - 1; |
1034 | 1035 | ||
1035 | master_bits = snd_usb_combine_bytes(ftr->controls, csize); | 1036 | master_bits = snd_usb_combine_bytes(ftr->bmaControls, csize); |
1036 | /* master configuration quirks */ | 1037 | /* master configuration quirks */ |
1037 | switch (state->chip->usb_id) { | 1038 | switch (state->chip->usb_id) { |
1038 | case USB_ID(0x08bb, 0x2702): | 1039 | case USB_ID(0x08bb, 0x2702): |
@@ -1043,14 +1044,14 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1043 | break; | 1044 | break; |
1044 | } | 1045 | } |
1045 | if (channels > 0) | 1046 | if (channels > 0) |
1046 | first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize); | 1047 | first_ch_bits = snd_usb_combine_bytes(ftr->bmaControls + csize, csize); |
1047 | else | 1048 | else |
1048 | first_ch_bits = 0; | 1049 | first_ch_bits = 0; |
1049 | /* check all control types */ | 1050 | /* check all control types */ |
1050 | for (i = 0; i < 10; i++) { | 1051 | for (i = 0; i < 10; i++) { |
1051 | unsigned int ch_bits = 0; | 1052 | unsigned int ch_bits = 0; |
1052 | for (j = 0; j < channels; j++) { | 1053 | for (j = 0; j < channels; j++) { |
1053 | unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize); | 1054 | unsigned int mask = snd_usb_combine_bytes(ftr->bmaControls + csize * (j+1), csize); |
1054 | if (mask & (1 << i)) | 1055 | if (mask & (1 << i)) |
1055 | ch_bits |= (1 << j); | 1056 | ch_bits |= (1 << j); |
1056 | } | 1057 | } |
@@ -1075,13 +1076,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1075 | * input channel number (zero based) is given in control field instead. | 1076 | * input channel number (zero based) is given in control field instead. |
1076 | */ | 1077 | */ |
1077 | 1078 | ||
1078 | static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | 1079 | static void build_mixer_unit_ctl(struct mixer_build *state, |
1080 | struct uac_mixer_unit_descriptor *desc, | ||
1079 | int in_pin, int in_ch, int unitid, | 1081 | int in_pin, int in_ch, int unitid, |
1080 | struct usb_audio_term *iterm) | 1082 | struct usb_audio_term *iterm) |
1081 | { | 1083 | { |
1082 | struct usb_mixer_elem_info *cval; | 1084 | struct usb_mixer_elem_info *cval; |
1083 | unsigned int input_pins = desc[4]; | 1085 | unsigned int num_outs = uac_mixer_unit_bNrChannels(desc); |
1084 | unsigned int num_outs = desc[5 + input_pins]; | ||
1085 | unsigned int i, len; | 1086 | unsigned int i, len; |
1086 | struct snd_kcontrol *kctl; | 1087 | struct snd_kcontrol *kctl; |
1087 | const struct usbmix_name_map *map; | 1088 | const struct usbmix_name_map *map; |
@@ -1099,7 +1100,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1099 | cval->control = in_ch + 1; /* based on 1 */ | 1100 | cval->control = in_ch + 1; /* based on 1 */ |
1100 | cval->val_type = USB_MIXER_S16; | 1101 | cval->val_type = USB_MIXER_S16; |
1101 | for (i = 0; i < num_outs; i++) { | 1102 | for (i = 0; i < num_outs; i++) { |
1102 | if (check_matrix_bitmap(desc + 9 + input_pins, in_ch, i, num_outs)) { | 1103 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc), in_ch, i, num_outs)) { |
1103 | cval->cmask |= (1 << i); | 1104 | cval->cmask |= (1 << i); |
1104 | cval->channels++; | 1105 | cval->channels++; |
1105 | } | 1106 | } |
@@ -1132,18 +1133,19 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
1132 | /* | 1133 | /* |
1133 | * parse a mixer unit | 1134 | * parse a mixer unit |
1134 | */ | 1135 | */ |
1135 | static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1136 | static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *raw_desc) |
1136 | { | 1137 | { |
1138 | struct uac_mixer_unit_descriptor *desc = raw_desc; | ||
1137 | struct usb_audio_term iterm; | 1139 | struct usb_audio_term iterm; |
1138 | int input_pins, num_ins, num_outs; | 1140 | int input_pins, num_ins, num_outs; |
1139 | int pin, ich, err; | 1141 | int pin, ich, err; |
1140 | 1142 | ||
1141 | if (desc[0] < 11 || ! (input_pins = desc[4]) || ! (num_outs = desc[5 + input_pins])) { | 1143 | if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) { |
1142 | snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid); | 1144 | snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid); |
1143 | return -EINVAL; | 1145 | return -EINVAL; |
1144 | } | 1146 | } |
1145 | /* no bmControls field (e.g. Maya44) -> ignore */ | 1147 | /* no bmControls field (e.g. Maya44) -> ignore */ |
1146 | if (desc[0] <= 10 + input_pins) { | 1148 | if (desc->bLength <= 10 + input_pins) { |
1147 | snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid); | 1149 | snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid); |
1148 | return 0; | 1150 | return 0; |
1149 | } | 1151 | } |
@@ -1151,10 +1153,10 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigne | |||
1151 | num_ins = 0; | 1153 | num_ins = 0; |
1152 | ich = 0; | 1154 | ich = 0; |
1153 | for (pin = 0; pin < input_pins; pin++) { | 1155 | for (pin = 0; pin < input_pins; pin++) { |
1154 | err = parse_audio_unit(state, desc[5 + pin]); | 1156 | err = parse_audio_unit(state, desc->baSourceID[pin]); |
1155 | if (err < 0) | 1157 | if (err < 0) |
1156 | return err; | 1158 | return err; |
1157 | err = check_input_term(state, desc[5 + pin], &iterm); | 1159 | err = check_input_term(state, desc->baSourceID[pin], &iterm); |
1158 | if (err < 0) | 1160 | if (err < 0) |
1159 | return err; | 1161 | return err; |
1160 | num_ins += iterm.channels; | 1162 | num_ins += iterm.channels; |
@@ -1162,7 +1164,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigne | |||
1162 | int och, ich_has_controls = 0; | 1164 | int och, ich_has_controls = 0; |
1163 | 1165 | ||
1164 | for (och = 0; och < num_outs; ++och) { | 1166 | for (och = 0; och < num_outs; ++och) { |
1165 | if (check_matrix_bitmap(desc + 9 + input_pins, | 1167 | if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc), |
1166 | ich, och, num_outs)) { | 1168 | ich, och, num_outs)) { |
1167 | ich_has_controls = 1; | 1169 | ich_has_controls = 1; |
1168 | break; | 1170 | break; |
@@ -1323,9 +1325,10 @@ static struct procunit_info extunits[] = { | |||
1323 | /* | 1325 | /* |
1324 | * build a processing/extension unit | 1326 | * build a processing/extension unit |
1325 | */ | 1327 | */ |
1326 | static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name) | 1328 | static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw_desc, struct procunit_info *list, char *name) |
1327 | { | 1329 | { |
1328 | int num_ins = dsc[6]; | 1330 | struct uac_processing_unit_descriptor *desc = raw_desc; |
1331 | int num_ins = desc->bNrInPins; | ||
1329 | struct usb_mixer_elem_info *cval; | 1332 | struct usb_mixer_elem_info *cval; |
1330 | struct snd_kcontrol *kctl; | 1333 | struct snd_kcontrol *kctl; |
1331 | int i, err, nameid, type, len; | 1334 | int i, err, nameid, type, len; |
@@ -1340,17 +1343,17 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1340 | 0, NULL, default_value_info | 1343 | 0, NULL, default_value_info |
1341 | }; | 1344 | }; |
1342 | 1345 | ||
1343 | if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) { | 1346 | if (desc->bLength < 13 || desc->bLength < 13 + num_ins || desc->bLength < num_ins + uac_processing_unit_bControlSize(desc)) { |
1344 | snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid); | 1347 | snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid); |
1345 | return -EINVAL; | 1348 | return -EINVAL; |
1346 | } | 1349 | } |
1347 | 1350 | ||
1348 | for (i = 0; i < num_ins; i++) { | 1351 | for (i = 0; i < num_ins; i++) { |
1349 | if ((err = parse_audio_unit(state, dsc[7 + i])) < 0) | 1352 | if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) |
1350 | return err; | 1353 | return err; |
1351 | } | 1354 | } |
1352 | 1355 | ||
1353 | type = combine_word(&dsc[4]); | 1356 | type = le16_to_cpu(desc->wProcessType); |
1354 | for (info = list; info && info->type; info++) | 1357 | for (info = list; info && info->type; info++) |
1355 | if (info->type == type) | 1358 | if (info->type == type) |
1356 | break; | 1359 | break; |
@@ -1358,8 +1361,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1358 | info = &default_info; | 1361 | info = &default_info; |
1359 | 1362 | ||
1360 | for (valinfo = info->values; valinfo->control; valinfo++) { | 1363 | for (valinfo = info->values; valinfo->control; valinfo++) { |
1361 | /* FIXME: bitmap might be longer than 8bit */ | 1364 | __u8 *controls = uac_processing_unit_bmControls(desc); |
1362 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) | 1365 | |
1366 | if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) | ||
1363 | continue; | 1367 | continue; |
1364 | map = find_map(state, unitid, valinfo->control); | 1368 | map = find_map(state, unitid, valinfo->control); |
1365 | if (check_ignored_ctl(map)) | 1369 | if (check_ignored_ctl(map)) |
@@ -1377,9 +1381,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1377 | 1381 | ||
1378 | /* get min/max values */ | 1382 | /* get min/max values */ |
1379 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { | 1383 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { |
1384 | __u8 *control_spec = uac_processing_unit_specific(desc); | ||
1380 | /* FIXME: hard-coded */ | 1385 | /* FIXME: hard-coded */ |
1381 | cval->min = 1; | 1386 | cval->min = 1; |
1382 | cval->max = dsc[15]; | 1387 | cval->max = control_spec[0]; |
1383 | cval->res = 1; | 1388 | cval->res = 1; |
1384 | cval->initialized = 1; | 1389 | cval->initialized = 1; |
1385 | } else { | 1390 | } else { |
@@ -1409,7 +1414,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1409 | else if (info->name) | 1414 | else if (info->name) |
1410 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); | 1415 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); |
1411 | else { | 1416 | else { |
1412 | nameid = dsc[12 + num_ins + dsc[11 + num_ins]]; | 1417 | nameid = uac_processing_unit_iProcessing(desc); |
1413 | len = 0; | 1418 | len = 0; |
1414 | if (nameid) | 1419 | if (nameid) |
1415 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); | 1420 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); |
@@ -1428,14 +1433,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
1428 | } | 1433 | } |
1429 | 1434 | ||
1430 | 1435 | ||
1431 | static int parse_audio_processing_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1436 | static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc) |
1432 | { | 1437 | { |
1433 | return build_audio_procunit(state, unitid, desc, procunits, "Processing Unit"); | 1438 | return build_audio_procunit(state, unitid, raw_desc, procunits, "Processing Unit"); |
1434 | } | 1439 | } |
1435 | 1440 | ||
1436 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1441 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, void *raw_desc) |
1437 | { | 1442 | { |
1438 | return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); | 1443 | /* Note that we parse extension units with processing unit descriptors. |
1444 | * That's ok as the layout is the same */ | ||
1445 | return build_audio_procunit(state, unitid, raw_desc, extunits, "Extension Unit"); | ||
1439 | } | 1446 | } |
1440 | 1447 | ||
1441 | 1448 | ||
@@ -1537,9 +1544,9 @@ static void usb_mixer_selector_elem_free(struct snd_kcontrol *kctl) | |||
1537 | /* | 1544 | /* |
1538 | * parse a selector unit | 1545 | * parse a selector unit |
1539 | */ | 1546 | */ |
1540 | static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1547 | static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void *raw_desc) |
1541 | { | 1548 | { |
1542 | unsigned int num_ins = desc[4]; | 1549 | struct uac_selector_unit_descriptor *desc = raw_desc; |
1543 | unsigned int i, nameid, len; | 1550 | unsigned int i, nameid, len; |
1544 | int err; | 1551 | int err; |
1545 | struct usb_mixer_elem_info *cval; | 1552 | struct usb_mixer_elem_info *cval; |
@@ -1547,17 +1554,17 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1547 | const struct usbmix_name_map *map; | 1554 | const struct usbmix_name_map *map; |
1548 | char **namelist; | 1555 | char **namelist; |
1549 | 1556 | ||
1550 | if (! num_ins || desc[0] < 5 + num_ins) { | 1557 | if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) { |
1551 | snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); | 1558 | snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); |
1552 | return -EINVAL; | 1559 | return -EINVAL; |
1553 | } | 1560 | } |
1554 | 1561 | ||
1555 | for (i = 0; i < num_ins; i++) { | 1562 | for (i = 0; i < desc->bNrInPins; i++) { |
1556 | if ((err = parse_audio_unit(state, desc[5 + i])) < 0) | 1563 | if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) |
1557 | return err; | 1564 | return err; |
1558 | } | 1565 | } |
1559 | 1566 | ||
1560 | if (num_ins == 1) /* only one ? nonsense! */ | 1567 | if (desc->bNrInPins == 1) /* only one ? nonsense! */ |
1561 | return 0; | 1568 | return 0; |
1562 | 1569 | ||
1563 | map = find_map(state, unitid, 0); | 1570 | map = find_map(state, unitid, 0); |
@@ -1574,18 +1581,18 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1574 | cval->val_type = USB_MIXER_U8; | 1581 | cval->val_type = USB_MIXER_U8; |
1575 | cval->channels = 1; | 1582 | cval->channels = 1; |
1576 | cval->min = 1; | 1583 | cval->min = 1; |
1577 | cval->max = num_ins; | 1584 | cval->max = desc->bNrInPins; |
1578 | cval->res = 1; | 1585 | cval->res = 1; |
1579 | cval->initialized = 1; | 1586 | cval->initialized = 1; |
1580 | 1587 | ||
1581 | namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL); | 1588 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
1582 | if (! namelist) { | 1589 | if (! namelist) { |
1583 | snd_printk(KERN_ERR "cannot malloc\n"); | 1590 | snd_printk(KERN_ERR "cannot malloc\n"); |
1584 | kfree(cval); | 1591 | kfree(cval); |
1585 | return -ENOMEM; | 1592 | return -ENOMEM; |
1586 | } | 1593 | } |
1587 | #define MAX_ITEM_NAME_LEN 64 | 1594 | #define MAX_ITEM_NAME_LEN 64 |
1588 | for (i = 0; i < num_ins; i++) { | 1595 | for (i = 0; i < desc->bNrInPins; i++) { |
1589 | struct usb_audio_term iterm; | 1596 | struct usb_audio_term iterm; |
1590 | len = 0; | 1597 | len = 0; |
1591 | namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); | 1598 | namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL); |
@@ -1599,7 +1606,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1599 | } | 1606 | } |
1600 | len = check_mapped_selector_name(state, unitid, i, namelist[i], | 1607 | len = check_mapped_selector_name(state, unitid, i, namelist[i], |
1601 | MAX_ITEM_NAME_LEN); | 1608 | MAX_ITEM_NAME_LEN); |
1602 | if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0) | 1609 | if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0) |
1603 | len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); | 1610 | len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); |
1604 | if (! len) | 1611 | if (! len) |
1605 | sprintf(namelist[i], "Input %d", i); | 1612 | sprintf(namelist[i], "Input %d", i); |
@@ -1615,7 +1622,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1615 | kctl->private_value = (unsigned long)namelist; | 1622 | kctl->private_value = (unsigned long)namelist; |
1616 | kctl->private_free = usb_mixer_selector_elem_free; | 1623 | kctl->private_free = usb_mixer_selector_elem_free; |
1617 | 1624 | ||
1618 | nameid = desc[desc[0] - 1]; | 1625 | nameid = uac_selector_unit_iSelector(desc); |
1619 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 1626 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1620 | if (len) | 1627 | if (len) |
1621 | ; | 1628 | ; |
@@ -1634,7 +1641,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
1634 | } | 1641 | } |
1635 | 1642 | ||
1636 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", | 1643 | snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n", |
1637 | cval->id, kctl->id.name, num_ins); | 1644 | cval->id, kctl->id.name, desc->bNrInPins); |
1638 | if ((err = add_control_to_empty(state, kctl)) < 0) | 1645 | if ((err = add_control_to_empty(state, kctl)) < 0) |
1639 | return err; | 1646 | return err; |
1640 | 1647 | ||