diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 71 |
1 files changed, 53 insertions, 18 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 696de5ac69be..c5447ff078b3 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -203,6 +203,10 @@ static int snd_usb_copy_string_desc(struct mixer_build *state, | |||
203 | int index, char *buf, int maxlen) | 203 | int index, char *buf, int maxlen) |
204 | { | 204 | { |
205 | int len = usb_string(state->chip->dev, index, buf, maxlen - 1); | 205 | int len = usb_string(state->chip->dev, index, buf, maxlen - 1); |
206 | |||
207 | if (len < 0) | ||
208 | return 0; | ||
209 | |||
206 | buf[len] = 0; | 210 | buf[len] = 0; |
207 | return len; | 211 | return len; |
208 | } | 212 | } |
@@ -339,17 +343,20 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, | |||
339 | int validx, int *value_ret) | 343 | int validx, int *value_ret) |
340 | { | 344 | { |
341 | struct snd_usb_audio *chip = cval->head.mixer->chip; | 345 | struct snd_usb_audio *chip = cval->head.mixer->chip; |
342 | unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */ | 346 | /* enough space for one range */ |
347 | unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)]; | ||
343 | unsigned char *val; | 348 | unsigned char *val; |
344 | int idx = 0, ret, size; | 349 | int idx = 0, ret, val_size, size; |
345 | __u8 bRequest; | 350 | __u8 bRequest; |
346 | 351 | ||
352 | val_size = uac2_ctl_value_size(cval->val_type); | ||
353 | |||
347 | if (request == UAC_GET_CUR) { | 354 | if (request == UAC_GET_CUR) { |
348 | bRequest = UAC2_CS_CUR; | 355 | bRequest = UAC2_CS_CUR; |
349 | size = uac2_ctl_value_size(cval->val_type); | 356 | size = val_size; |
350 | } else { | 357 | } else { |
351 | bRequest = UAC2_CS_RANGE; | 358 | bRequest = UAC2_CS_RANGE; |
352 | size = sizeof(buf); | 359 | size = sizeof(__u16) + 3 * val_size; |
353 | } | 360 | } |
354 | 361 | ||
355 | memset(buf, 0, sizeof(buf)); | 362 | memset(buf, 0, sizeof(buf)); |
@@ -382,16 +389,17 @@ error: | |||
382 | val = buf + sizeof(__u16); | 389 | val = buf + sizeof(__u16); |
383 | break; | 390 | break; |
384 | case UAC_GET_MAX: | 391 | case UAC_GET_MAX: |
385 | val = buf + sizeof(__u16) * 2; | 392 | val = buf + sizeof(__u16) + val_size; |
386 | break; | 393 | break; |
387 | case UAC_GET_RES: | 394 | case UAC_GET_RES: |
388 | val = buf + sizeof(__u16) * 3; | 395 | val = buf + sizeof(__u16) + val_size * 2; |
389 | break; | 396 | break; |
390 | default: | 397 | default: |
391 | return -EINVAL; | 398 | return -EINVAL; |
392 | } | 399 | } |
393 | 400 | ||
394 | *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16))); | 401 | *value_ret = convert_signed_value(cval, |
402 | snd_usb_combine_bytes(val, val_size)); | ||
395 | 403 | ||
396 | return 0; | 404 | return 0; |
397 | } | 405 | } |
@@ -1397,6 +1405,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1397 | __u8 *bmaControls; | 1405 | __u8 *bmaControls; |
1398 | 1406 | ||
1399 | if (state->mixer->protocol == UAC_VERSION_1) { | 1407 | if (state->mixer->protocol == UAC_VERSION_1) { |
1408 | if (hdr->bLength < 7) { | ||
1409 | usb_audio_err(state->chip, | ||
1410 | "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", | ||
1411 | unitid); | ||
1412 | return -EINVAL; | ||
1413 | } | ||
1400 | csize = hdr->bControlSize; | 1414 | csize = hdr->bControlSize; |
1401 | if (!csize) { | 1415 | if (!csize) { |
1402 | usb_audio_dbg(state->chip, | 1416 | usb_audio_dbg(state->chip, |
@@ -1414,6 +1428,12 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1414 | } | 1428 | } |
1415 | } else { | 1429 | } else { |
1416 | struct uac2_feature_unit_descriptor *ftr = _ftr; | 1430 | struct uac2_feature_unit_descriptor *ftr = _ftr; |
1431 | if (hdr->bLength < 6) { | ||
1432 | usb_audio_err(state->chip, | ||
1433 | "unit %u: invalid UAC_FEATURE_UNIT descriptor\n", | ||
1434 | unitid); | ||
1435 | return -EINVAL; | ||
1436 | } | ||
1417 | csize = 4; | 1437 | csize = 4; |
1418 | channels = (hdr->bLength - 6) / 4 - 1; | 1438 | channels = (hdr->bLength - 6) / 4 - 1; |
1419 | bmaControls = ftr->bmaControls; | 1439 | bmaControls = ftr->bmaControls; |
@@ -2014,7 +2034,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2014 | const struct usbmix_name_map *map; | 2034 | const struct usbmix_name_map *map; |
2015 | char **namelist; | 2035 | char **namelist; |
2016 | 2036 | ||
2017 | if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) { | 2037 | if (desc->bLength < 5 || !desc->bNrInPins || |
2038 | desc->bLength < 5 + desc->bNrInPins) { | ||
2018 | usb_audio_err(state->chip, | 2039 | usb_audio_err(state->chip, |
2019 | "invalid SELECTOR UNIT descriptor %d\n", unitid); | 2040 | "invalid SELECTOR UNIT descriptor %d\n", unitid); |
2020 | return -EINVAL; | 2041 | return -EINVAL; |
@@ -2084,19 +2105,25 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2084 | kctl->private_value = (unsigned long)namelist; | 2105 | kctl->private_value = (unsigned long)namelist; |
2085 | kctl->private_free = usb_mixer_selector_elem_free; | 2106 | kctl->private_free = usb_mixer_selector_elem_free; |
2086 | 2107 | ||
2087 | nameid = uac_selector_unit_iSelector(desc); | 2108 | /* check the static mapping table at first */ |
2088 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 2109 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
2089 | if (len) | 2110 | if (!len) { |
2090 | ; | 2111 | /* no mapping ? */ |
2091 | else if (nameid) | 2112 | /* if iSelector is given, use it */ |
2092 | snd_usb_copy_string_desc(state, nameid, kctl->id.name, | 2113 | nameid = uac_selector_unit_iSelector(desc); |
2093 | sizeof(kctl->id.name)); | 2114 | if (nameid) |
2094 | else { | 2115 | len = snd_usb_copy_string_desc(state, nameid, |
2095 | len = get_term_name(state, &state->oterm, | 2116 | kctl->id.name, |
2117 | sizeof(kctl->id.name)); | ||
2118 | /* ... or pick up the terminal name at next */ | ||
2119 | if (!len) | ||
2120 | len = get_term_name(state, &state->oterm, | ||
2096 | kctl->id.name, sizeof(kctl->id.name), 0); | 2121 | kctl->id.name, sizeof(kctl->id.name), 0); |
2122 | /* ... or use the fixed string "USB" as the last resort */ | ||
2097 | if (!len) | 2123 | if (!len) |
2098 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 2124 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
2099 | 2125 | ||
2126 | /* and add the proper suffix */ | ||
2100 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | 2127 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) |
2101 | append_ctl_name(kctl, " Clock Source"); | 2128 | append_ctl_name(kctl, " Clock Source"); |
2102 | else if ((state->oterm.type & 0xff00) == 0x0100) | 2129 | else if ((state->oterm.type & 0xff00) == 0x0100) |
@@ -2161,6 +2188,9 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
2161 | 2188 | ||
2162 | static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) | 2189 | static void snd_usb_mixer_free(struct usb_mixer_interface *mixer) |
2163 | { | 2190 | { |
2191 | /* kill pending URBs */ | ||
2192 | snd_usb_mixer_disconnect(mixer); | ||
2193 | |||
2164 | kfree(mixer->id_elems); | 2194 | kfree(mixer->id_elems); |
2165 | if (mixer->urb) { | 2195 | if (mixer->urb) { |
2166 | kfree(mixer->urb->transfer_buffer); | 2196 | kfree(mixer->urb->transfer_buffer); |
@@ -2504,8 +2534,13 @@ _error: | |||
2504 | 2534 | ||
2505 | void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) | 2535 | void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer) |
2506 | { | 2536 | { |
2507 | usb_kill_urb(mixer->urb); | 2537 | if (mixer->disconnected) |
2508 | usb_kill_urb(mixer->rc_urb); | 2538 | return; |
2539 | if (mixer->urb) | ||
2540 | usb_kill_urb(mixer->urb); | ||
2541 | if (mixer->rc_urb) | ||
2542 | usb_kill_urb(mixer->rc_urb); | ||
2543 | mixer->disconnected = true; | ||
2509 | } | 2544 | } |
2510 | 2545 | ||
2511 | #ifdef CONFIG_PM | 2546 | #ifdef CONFIG_PM |