diff options
-rw-r--r-- | sound/usb/card.c | 14 | ||||
-rw-r--r-- | sound/usb/clock.c | 9 | ||||
-rw-r--r-- | sound/usb/mixer.c | 327 | ||||
-rw-r--r-- | sound/usb/mixer_maps.c | 65 | ||||
-rw-r--r-- | sound/usb/stream.c | 83 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 2 |
6 files changed, 459 insertions, 41 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index 0d7a5d70634e..f6c3c1cd591e 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -307,6 +307,20 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
307 | return -EINVAL; | 307 | return -EINVAL; |
308 | } | 308 | } |
309 | 309 | ||
310 | if (protocol == UAC_VERSION_3) { | ||
311 | int badd = assoc->bFunctionSubClass; | ||
312 | |||
313 | if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 && | ||
314 | (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO || | ||
315 | badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) { | ||
316 | dev_err(&dev->dev, | ||
317 | "Unsupported UAC3 BADD profile\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | chip->badd_profile = badd; | ||
322 | } | ||
323 | |||
310 | for (i = 0; i < assoc->bInterfaceCount; i++) { | 324 | for (i = 0; i < assoc->bInterfaceCount; i++) { |
311 | int intf = assoc->bFirstInterface + i; | 325 | int intf = assoc->bFirstInterface + i; |
312 | 326 | ||
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 0b030d8fe3fa..17673f37fcc8 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c | |||
@@ -587,8 +587,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |||
587 | default: | 587 | default: |
588 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | 588 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
589 | 589 | ||
590 | case UAC_VERSION_2: | ||
591 | case UAC_VERSION_3: | 590 | case UAC_VERSION_3: |
591 | if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { | ||
592 | if (rate != UAC3_BADD_SAMPLING_RATE) | ||
593 | return -ENXIO; | ||
594 | else | ||
595 | return 0; | ||
596 | } | ||
597 | /* fall through */ | ||
598 | case UAC_VERSION_2: | ||
592 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); | 599 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); |
593 | } | 600 | } |
594 | } | 601 | } |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 76417943ff85..4987982250d5 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -112,14 +112,12 @@ enum { | |||
112 | #include "mixer_maps.c" | 112 | #include "mixer_maps.c" |
113 | 113 | ||
114 | static const struct usbmix_name_map * | 114 | static const struct usbmix_name_map * |
115 | find_map(struct mixer_build *state, int unitid, int control) | 115 | find_map(const struct usbmix_name_map *p, int unitid, int control) |
116 | { | 116 | { |
117 | const struct usbmix_name_map *p = state->map; | ||
118 | |||
119 | if (!p) | 117 | if (!p) |
120 | return NULL; | 118 | return NULL; |
121 | 119 | ||
122 | for (p = state->map; p->id; p++) { | 120 | for (; p->id; p++) { |
123 | if (p->id == unitid && | 121 | if (p->id == unitid && |
124 | (!control || !p->control || control == p->control)) | 122 | (!control || !p->control || control == p->control)) |
125 | return p; | 123 | return p; |
@@ -1333,16 +1331,16 @@ static struct usb_feature_control_info *get_feature_control_info(int control) | |||
1333 | return NULL; | 1331 | return NULL; |
1334 | } | 1332 | } |
1335 | 1333 | ||
1336 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 1334 | static void __build_feature_ctl(struct usb_mixer_interface *mixer, |
1337 | unsigned int ctl_mask, int control, | 1335 | const struct usbmix_name_map *imap, |
1338 | struct usb_audio_term *iterm, int unitid, | 1336 | unsigned int ctl_mask, int control, |
1339 | int readonly_mask) | 1337 | struct usb_audio_term *iterm, |
1338 | struct usb_audio_term *oterm, | ||
1339 | int unitid, int nameid, int readonly_mask) | ||
1340 | { | 1340 | { |
1341 | struct uac_feature_unit_descriptor *desc = raw_desc; | ||
1342 | struct usb_feature_control_info *ctl_info; | 1341 | struct usb_feature_control_info *ctl_info; |
1343 | unsigned int len = 0; | 1342 | unsigned int len = 0; |
1344 | int mapped_name = 0; | 1343 | int mapped_name = 0; |
1345 | int nameid = uac_feature_unit_iFeature(desc); | ||
1346 | struct snd_kcontrol *kctl; | 1344 | struct snd_kcontrol *kctl; |
1347 | struct usb_mixer_elem_info *cval; | 1345 | struct usb_mixer_elem_info *cval; |
1348 | const struct usbmix_name_map *map; | 1346 | const struct usbmix_name_map *map; |
@@ -1353,14 +1351,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1353 | return; | 1351 | return; |
1354 | } | 1352 | } |
1355 | 1353 | ||
1356 | map = find_map(state, unitid, control); | 1354 | map = find_map(imap, unitid, control); |
1357 | if (check_ignored_ctl(map)) | 1355 | if (check_ignored_ctl(map)) |
1358 | return; | 1356 | return; |
1359 | 1357 | ||
1360 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1358 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
1361 | if (!cval) | 1359 | if (!cval) |
1362 | return; | 1360 | return; |
1363 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); | 1361 | snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); |
1364 | cval->control = control; | 1362 | cval->control = control; |
1365 | cval->cmask = ctl_mask; | 1363 | cval->cmask = ctl_mask; |
1366 | 1364 | ||
@@ -1369,7 +1367,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1369 | kfree(cval); | 1367 | kfree(cval); |
1370 | return; | 1368 | return; |
1371 | } | 1369 | } |
1372 | if (state->mixer->protocol == UAC_VERSION_1) | 1370 | if (mixer->protocol == UAC_VERSION_1) |
1373 | cval->val_type = ctl_info->type; | 1371 | cval->val_type = ctl_info->type; |
1374 | else /* UAC_VERSION_2 */ | 1372 | else /* UAC_VERSION_2 */ |
1375 | cval->val_type = ctl_info->type_uac2 >= 0 ? | 1373 | cval->val_type = ctl_info->type_uac2 >= 0 ? |
@@ -1398,7 +1396,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1398 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1396 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
1399 | 1397 | ||
1400 | if (!kctl) { | 1398 | if (!kctl) { |
1401 | usb_audio_err(state->chip, "cannot malloc kcontrol\n"); | 1399 | usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); |
1402 | kfree(cval); | 1400 | kfree(cval); |
1403 | return; | 1401 | return; |
1404 | } | 1402 | } |
@@ -1407,7 +1405,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1407 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 1405 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1408 | mapped_name = len != 0; | 1406 | mapped_name = len != 0; |
1409 | if (!len && nameid) | 1407 | if (!len && nameid) |
1410 | len = snd_usb_copy_string_desc(state->chip, nameid, | 1408 | len = snd_usb_copy_string_desc(mixer->chip, nameid, |
1411 | kctl->id.name, sizeof(kctl->id.name)); | 1409 | kctl->id.name, sizeof(kctl->id.name)); |
1412 | 1410 | ||
1413 | switch (control) { | 1411 | switch (control) { |
@@ -1422,10 +1420,12 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1422 | * - otherwise, anonymous name. | 1420 | * - otherwise, anonymous name. |
1423 | */ | 1421 | */ |
1424 | if (!len) { | 1422 | if (!len) { |
1425 | len = get_term_name(state->chip, iterm, kctl->id.name, | 1423 | if (iterm) |
1426 | sizeof(kctl->id.name), 1); | 1424 | len = get_term_name(mixer->chip, iterm, |
1427 | if (!len) | 1425 | kctl->id.name, |
1428 | len = get_term_name(state->chip, &state->oterm, | 1426 | sizeof(kctl->id.name), 1); |
1427 | if (!len && oterm) | ||
1428 | len = get_term_name(mixer->chip, oterm, | ||
1429 | kctl->id.name, | 1429 | kctl->id.name, |
1430 | sizeof(kctl->id.name), 1); | 1430 | sizeof(kctl->id.name), 1); |
1431 | if (!len) | 1431 | if (!len) |
@@ -1434,15 +1434,15 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1434 | } | 1434 | } |
1435 | 1435 | ||
1436 | if (!mapped_name) | 1436 | if (!mapped_name) |
1437 | check_no_speaker_on_headset(kctl, state->mixer->chip->card); | 1437 | check_no_speaker_on_headset(kctl, mixer->chip->card); |
1438 | 1438 | ||
1439 | /* | 1439 | /* |
1440 | * determine the stream direction: | 1440 | * determine the stream direction: |
1441 | * if the connected output is USB stream, then it's likely a | 1441 | * if the connected output is USB stream, then it's likely a |
1442 | * capture stream. otherwise it should be playback (hopefully :) | 1442 | * capture stream. otherwise it should be playback (hopefully :) |
1443 | */ | 1443 | */ |
1444 | if (!mapped_name && !(state->oterm.type >> 16)) { | 1444 | if (!mapped_name && oterm && !(oterm->type >> 16)) { |
1445 | if ((state->oterm.type & 0xff00) == 0x0100) | 1445 | if ((oterm->type & 0xff00) == 0x0100) |
1446 | append_ctl_name(kctl, " Capture"); | 1446 | append_ctl_name(kctl, " Capture"); |
1447 | else | 1447 | else |
1448 | append_ctl_name(kctl, " Playback"); | 1448 | append_ctl_name(kctl, " Playback"); |
@@ -1470,7 +1470,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1470 | } | 1470 | } |
1471 | } | 1471 | } |
1472 | 1472 | ||
1473 | snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl); | 1473 | snd_usb_mixer_fu_apply_quirk(mixer, cval, unitid, kctl); |
1474 | 1474 | ||
1475 | range = (cval->max - cval->min) / cval->res; | 1475 | range = (cval->max - cval->min) / cval->res; |
1476 | /* | 1476 | /* |
@@ -1479,21 +1479,41 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1479 | * devices. It will definitively catch all buggy Logitech devices. | 1479 | * devices. It will definitively catch all buggy Logitech devices. |
1480 | */ | 1480 | */ |
1481 | if (range > 384) { | 1481 | if (range > 384) { |
1482 | usb_audio_warn(state->chip, | 1482 | usb_audio_warn(mixer->chip, |
1483 | "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", | 1483 | "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", |
1484 | range); | 1484 | range); |
1485 | usb_audio_warn(state->chip, | 1485 | usb_audio_warn(mixer->chip, |
1486 | "[%d] FU [%s] ch = %d, val = %d/%d/%d", | 1486 | "[%d] FU [%s] ch = %d, val = %d/%d/%d", |
1487 | cval->head.id, kctl->id.name, cval->channels, | 1487 | cval->head.id, kctl->id.name, cval->channels, |
1488 | cval->min, cval->max, cval->res); | 1488 | cval->min, cval->max, cval->res); |
1489 | } | 1489 | } |
1490 | 1490 | ||
1491 | usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 1491 | usb_audio_dbg(mixer->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
1492 | cval->head.id, kctl->id.name, cval->channels, | 1492 | cval->head.id, kctl->id.name, cval->channels, |
1493 | cval->min, cval->max, cval->res); | 1493 | cval->min, cval->max, cval->res); |
1494 | snd_usb_mixer_add_control(&cval->head, kctl); | 1494 | snd_usb_mixer_add_control(&cval->head, kctl); |
1495 | } | 1495 | } |
1496 | 1496 | ||
1497 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | ||
1498 | unsigned int ctl_mask, int control, | ||
1499 | struct usb_audio_term *iterm, int unitid, | ||
1500 | int readonly_mask) | ||
1501 | { | ||
1502 | struct uac_feature_unit_descriptor *desc = raw_desc; | ||
1503 | int nameid = uac_feature_unit_iFeature(desc); | ||
1504 | |||
1505 | __build_feature_ctl(state->mixer, state->map, ctl_mask, control, | ||
1506 | iterm, &state->oterm, unitid, nameid, readonly_mask); | ||
1507 | } | ||
1508 | |||
1509 | static void build_feature_ctl_badd(struct usb_mixer_interface *mixer, | ||
1510 | unsigned int ctl_mask, int control, int unitid, | ||
1511 | const struct usbmix_name_map *badd_map) | ||
1512 | { | ||
1513 | __build_feature_ctl(mixer, badd_map, ctl_mask, control, | ||
1514 | NULL, NULL, unitid, 0, 0); | ||
1515 | } | ||
1516 | |||
1497 | static void get_connector_control_name(struct mixer_build *state, | 1517 | static void get_connector_control_name(struct mixer_build *state, |
1498 | struct usb_audio_term *term, | 1518 | struct usb_audio_term *term, |
1499 | bool is_input, char *name, int name_size) | 1519 | bool is_input, char *name, int name_size) |
@@ -1807,7 +1827,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, | |||
1807 | struct snd_kcontrol *kctl; | 1827 | struct snd_kcontrol *kctl; |
1808 | const struct usbmix_name_map *map; | 1828 | const struct usbmix_name_map *map; |
1809 | 1829 | ||
1810 | map = find_map(state, unitid, 0); | 1830 | map = find_map(state->map, unitid, 0); |
1811 | if (check_ignored_ctl(map)) | 1831 | if (check_ignored_ctl(map)) |
1812 | return; | 1832 | return; |
1813 | 1833 | ||
@@ -2106,7 +2126,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, | |||
2106 | 2126 | ||
2107 | if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) | 2127 | if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) |
2108 | continue; | 2128 | continue; |
2109 | map = find_map(state, unitid, valinfo->control); | 2129 | map = find_map(state->map, unitid, valinfo->control); |
2110 | if (check_ignored_ctl(map)) | 2130 | if (check_ignored_ctl(map)) |
2111 | continue; | 2131 | continue; |
2112 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 2132 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -2310,7 +2330,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2310 | if (desc->bNrInPins == 1) /* only one ? nonsense! */ | 2330 | if (desc->bNrInPins == 1) /* only one ? nonsense! */ |
2311 | return 0; | 2331 | return 0; |
2312 | 2332 | ||
2313 | map = find_map(state, unitid, 0); | 2333 | map = find_map(state->map, unitid, 0); |
2314 | if (check_ignored_ctl(map)) | 2334 | if (check_ignored_ctl(map)) |
2315 | return 0; | 2335 | return 0; |
2316 | 2336 | ||
@@ -2497,6 +2517,246 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
2497 | return 0; | 2517 | return 0; |
2498 | } | 2518 | } |
2499 | 2519 | ||
2520 | /* UAC3 predefined channels configuration */ | ||
2521 | struct uac3_badd_profile { | ||
2522 | int subclass; | ||
2523 | const char *name; | ||
2524 | int c_chmask; /* capture channels mask */ | ||
2525 | int p_chmask; /* playback channels mask */ | ||
2526 | int st_chmask; /* side tone mixing channel mask */ | ||
2527 | }; | ||
2528 | |||
2529 | static struct uac3_badd_profile uac3_badd_profiles[] = { | ||
2530 | { | ||
2531 | /* | ||
2532 | * BAIF, BAOF or combination of both | ||
2533 | * IN: Mono or Stereo cfg, Mono alt possible | ||
2534 | * OUT: Mono or Stereo cfg, Mono alt possible | ||
2535 | */ | ||
2536 | .subclass = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, | ||
2537 | .name = "GENERIC IO", | ||
2538 | .c_chmask = -1, /* dynamic channels */ | ||
2539 | .p_chmask = -1, /* dynamic channels */ | ||
2540 | }, | ||
2541 | { | ||
2542 | /* BAOF; Stereo only cfg, Mono alt possible */ | ||
2543 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADPHONE, | ||
2544 | .name = "HEADPHONE", | ||
2545 | .p_chmask = 3, | ||
2546 | }, | ||
2547 | { | ||
2548 | /* BAOF; Mono or Stereo cfg, Mono alt possible */ | ||
2549 | .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKER, | ||
2550 | .name = "SPEAKER", | ||
2551 | .p_chmask = -1, /* dynamic channels */ | ||
2552 | }, | ||
2553 | { | ||
2554 | /* BAIF; Mono or Stereo cfg, Mono alt possible */ | ||
2555 | .subclass = UAC3_FUNCTION_SUBCLASS_MICROPHONE, | ||
2556 | .name = "MICROPHONE", | ||
2557 | .c_chmask = -1, /* dynamic channels */ | ||
2558 | }, | ||
2559 | { | ||
2560 | /* | ||
2561 | * BAIOF topology | ||
2562 | * IN: Mono only | ||
2563 | * OUT: Mono or Stereo cfg, Mono alt possible | ||
2564 | */ | ||
2565 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET, | ||
2566 | .name = "HEADSET", | ||
2567 | .c_chmask = 1, | ||
2568 | .p_chmask = -1, /* dynamic channels */ | ||
2569 | .st_chmask = 1, | ||
2570 | }, | ||
2571 | { | ||
2572 | /* BAIOF; IN: Mono only; OUT: Stereo only, Mono alt possible */ | ||
2573 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, | ||
2574 | .name = "HEADSET ADAPTER", | ||
2575 | .c_chmask = 1, | ||
2576 | .p_chmask = 3, | ||
2577 | .st_chmask = 1, | ||
2578 | }, | ||
2579 | { | ||
2580 | /* BAIF + BAOF; IN: Mono only; OUT: Mono only */ | ||
2581 | .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, | ||
2582 | .name = "SPEAKERPHONE", | ||
2583 | .c_chmask = 1, | ||
2584 | .p_chmask = 1, | ||
2585 | }, | ||
2586 | { 0 } /* terminator */ | ||
2587 | }; | ||
2588 | |||
2589 | static bool uac3_badd_func_has_valid_channels(struct usb_mixer_interface *mixer, | ||
2590 | struct uac3_badd_profile *f, | ||
2591 | int c_chmask, int p_chmask) | ||
2592 | { | ||
2593 | /* | ||
2594 | * If both playback/capture channels are dynamic, make sure | ||
2595 | * at least one channel is present | ||
2596 | */ | ||
2597 | if (f->c_chmask < 0 && f->p_chmask < 0) { | ||
2598 | if (!c_chmask && !p_chmask) { | ||
2599 | usb_audio_warn(mixer->chip, "BAAD %s: no channels?", | ||
2600 | f->name); | ||
2601 | return false; | ||
2602 | } | ||
2603 | return true; | ||
2604 | } | ||
2605 | |||
2606 | if ((f->c_chmask < 0 && !c_chmask) || | ||
2607 | (f->c_chmask >= 0 && f->c_chmask != c_chmask)) { | ||
2608 | usb_audio_warn(mixer->chip, "BAAD %s c_chmask mismatch", | ||
2609 | f->name); | ||
2610 | return false; | ||
2611 | } | ||
2612 | if ((f->p_chmask < 0 && !p_chmask) || | ||
2613 | (f->p_chmask >= 0 && f->p_chmask != p_chmask)) { | ||
2614 | usb_audio_warn(mixer->chip, "BAAD %s p_chmask mismatch", | ||
2615 | f->name); | ||
2616 | return false; | ||
2617 | } | ||
2618 | return true; | ||
2619 | } | ||
2620 | |||
2621 | /* | ||
2622 | * create mixer controls for UAC3 BADD profiles | ||
2623 | * | ||
2624 | * UAC3 BADD device doesn't contain CS descriptors thus we will guess everything | ||
2625 | * | ||
2626 | * BADD device may contain Mixer Unit, which doesn't have any controls, skip it | ||
2627 | */ | ||
2628 | static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, | ||
2629 | int ctrlif) | ||
2630 | { | ||
2631 | struct usb_device *dev = mixer->chip->dev; | ||
2632 | struct usb_interface_assoc_descriptor *assoc; | ||
2633 | int badd_profile = mixer->chip->badd_profile; | ||
2634 | struct uac3_badd_profile *f; | ||
2635 | const struct usbmix_ctl_map *map; | ||
2636 | int p_chmask = 0, c_chmask = 0, st_chmask = 0; | ||
2637 | int i; | ||
2638 | |||
2639 | assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | ||
2640 | |||
2641 | /* Detect BADD capture/playback channels from AS EP descriptors */ | ||
2642 | for (i = 0; i < assoc->bInterfaceCount; i++) { | ||
2643 | int intf = assoc->bFirstInterface + i; | ||
2644 | |||
2645 | struct usb_interface *iface; | ||
2646 | struct usb_host_interface *alts; | ||
2647 | struct usb_interface_descriptor *altsd; | ||
2648 | unsigned int maxpacksize; | ||
2649 | char dir_in; | ||
2650 | int chmask, num; | ||
2651 | |||
2652 | if (intf == ctrlif) | ||
2653 | continue; | ||
2654 | |||
2655 | iface = usb_ifnum_to_if(dev, intf); | ||
2656 | num = iface->num_altsetting; | ||
2657 | |||
2658 | if (num < 2) | ||
2659 | return -EINVAL; | ||
2660 | |||
2661 | /* | ||
2662 | * The number of Channels in an AudioStreaming interface | ||
2663 | * and the audio sample bit resolution (16 bits or 24 | ||
2664 | * bits) can be derived from the wMaxPacketSize field in | ||
2665 | * the Standard AS Audio Data Endpoint descriptor in | ||
2666 | * Alternate Setting 1 | ||
2667 | */ | ||
2668 | alts = &iface->altsetting[1]; | ||
2669 | altsd = get_iface_desc(alts); | ||
2670 | |||
2671 | if (altsd->bNumEndpoints < 1) | ||
2672 | return -EINVAL; | ||
2673 | |||
2674 | /* check direction */ | ||
2675 | dir_in = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); | ||
2676 | maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
2677 | |||
2678 | switch (maxpacksize) { | ||
2679 | default: | ||
2680 | usb_audio_err(mixer->chip, | ||
2681 | "incorrect wMaxPacketSize 0x%x for BADD profile\n", | ||
2682 | maxpacksize); | ||
2683 | return -EINVAL; | ||
2684 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: | ||
2685 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: | ||
2686 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: | ||
2687 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: | ||
2688 | chmask = 1; | ||
2689 | break; | ||
2690 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: | ||
2691 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: | ||
2692 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: | ||
2693 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: | ||
2694 | chmask = 3; | ||
2695 | break; | ||
2696 | } | ||
2697 | |||
2698 | if (dir_in) | ||
2699 | c_chmask = chmask; | ||
2700 | else | ||
2701 | p_chmask = chmask; | ||
2702 | } | ||
2703 | |||
2704 | usb_audio_dbg(mixer->chip, | ||
2705 | "UAC3 BADD profile 0x%x: detected c_chmask=%d p_chmask=%d\n", | ||
2706 | badd_profile, c_chmask, p_chmask); | ||
2707 | |||
2708 | /* check the mapping table */ | ||
2709 | for (map = uac3_badd_usbmix_ctl_maps; map->id; map++) { | ||
2710 | if (map->id == badd_profile) | ||
2711 | break; | ||
2712 | } | ||
2713 | |||
2714 | if (!map->id) | ||
2715 | return -EINVAL; | ||
2716 | |||
2717 | for (f = uac3_badd_profiles; f->name; f++) { | ||
2718 | if (badd_profile == f->subclass) | ||
2719 | break; | ||
2720 | } | ||
2721 | if (!f->name) | ||
2722 | return -EINVAL; | ||
2723 | if (!uac3_badd_func_has_valid_channels(mixer, f, c_chmask, p_chmask)) | ||
2724 | return -EINVAL; | ||
2725 | st_chmask = f->st_chmask; | ||
2726 | |||
2727 | /* Playback */ | ||
2728 | if (p_chmask) { | ||
2729 | /* Master channel, always writable */ | ||
2730 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2731 | UAC3_BADD_FU_ID2, map->map); | ||
2732 | /* Mono/Stereo volume channels, always writable */ | ||
2733 | build_feature_ctl_badd(mixer, p_chmask, UAC_FU_VOLUME, | ||
2734 | UAC3_BADD_FU_ID2, map->map); | ||
2735 | } | ||
2736 | |||
2737 | /* Capture */ | ||
2738 | if (c_chmask) { | ||
2739 | /* Master channel, always writable */ | ||
2740 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2741 | UAC3_BADD_FU_ID5, map->map); | ||
2742 | /* Mono/Stereo volume channels, always writable */ | ||
2743 | build_feature_ctl_badd(mixer, c_chmask, UAC_FU_VOLUME, | ||
2744 | UAC3_BADD_FU_ID5, map->map); | ||
2745 | } | ||
2746 | |||
2747 | /* Side tone-mixing */ | ||
2748 | if (st_chmask) { | ||
2749 | /* Master channel, always writable */ | ||
2750 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2751 | UAC3_BADD_FU_ID7, map->map); | ||
2752 | /* Mono volume channel, always writable */ | ||
2753 | build_feature_ctl_badd(mixer, 1, UAC_FU_VOLUME, | ||
2754 | UAC3_BADD_FU_ID7, map->map); | ||
2755 | } | ||
2756 | |||
2757 | return 0; | ||
2758 | } | ||
2759 | |||
2500 | /* | 2760 | /* |
2501 | * create mixer controls | 2761 | * create mixer controls |
2502 | * | 2762 | * |
@@ -2882,9 +3142,14 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2882 | break; | 3142 | break; |
2883 | } | 3143 | } |
2884 | 3144 | ||
2885 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 3145 | if (mixer->protocol == UAC_VERSION_3 && |
2886 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 3146 | chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { |
3147 | if ((err = snd_usb_mixer_controls_badd(mixer, ctrlif)) < 0) | ||
3148 | goto _error; | ||
3149 | } else if ((err = snd_usb_mixer_controls(mixer)) < 0 || | ||
3150 | (err = snd_usb_mixer_status_create(mixer)) < 0) { | ||
2887 | goto _error; | 3151 | goto _error; |
3152 | } | ||
2888 | err = create_keep_iface_ctl(mixer); | 3153 | err = create_keep_iface_ctl(mixer); |
2889 | if (err < 0) | 3154 | if (err < 0) |
2890 | goto _error; | 3155 | goto _error; |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index eaa03acd4686..71069e110897 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -485,3 +485,68 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
485 | { 0 } /* terminator */ | 485 | { 0 } /* terminator */ |
486 | }; | 486 | }; |
487 | 487 | ||
488 | /* | ||
489 | * Control map entries for UAC3 BADD profiles | ||
490 | */ | ||
491 | |||
492 | static struct usbmix_name_map uac3_badd_generic_io_map[] = { | ||
493 | { UAC3_BADD_FU_ID2, "Generic Out Playback" }, | ||
494 | { UAC3_BADD_FU_ID5, "Generic In Capture" }, | ||
495 | { 0 } /* terminator */ | ||
496 | }; | ||
497 | static struct usbmix_name_map uac3_badd_headphone_map[] = { | ||
498 | { UAC3_BADD_FU_ID2, "Headphone Playback" }, | ||
499 | { 0 } /* terminator */ | ||
500 | }; | ||
501 | static struct usbmix_name_map uac3_badd_speaker_map[] = { | ||
502 | { UAC3_BADD_FU_ID2, "Speaker Playback" }, | ||
503 | { 0 } /* terminator */ | ||
504 | }; | ||
505 | static struct usbmix_name_map uac3_badd_microphone_map[] = { | ||
506 | { UAC3_BADD_FU_ID5, "Mic Capture" }, | ||
507 | { 0 } /* terminator */ | ||
508 | }; | ||
509 | /* Covers also 'headset adapter' profile */ | ||
510 | static struct usbmix_name_map uac3_badd_headset_map[] = { | ||
511 | { UAC3_BADD_FU_ID2, "Headset Playback" }, | ||
512 | { UAC3_BADD_FU_ID5, "Headset Capture" }, | ||
513 | { UAC3_BADD_FU_ID7, "Sidetone Mixing" }, | ||
514 | { 0 } /* terminator */ | ||
515 | }; | ||
516 | static struct usbmix_name_map uac3_badd_speakerphone_map[] = { | ||
517 | { UAC3_BADD_FU_ID2, "Speaker Playback" }, | ||
518 | { UAC3_BADD_FU_ID5, "Mic Capture" }, | ||
519 | { 0 } /* terminator */ | ||
520 | }; | ||
521 | |||
522 | static struct usbmix_ctl_map uac3_badd_usbmix_ctl_maps[] = { | ||
523 | { | ||
524 | .id = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, | ||
525 | .map = uac3_badd_generic_io_map, | ||
526 | }, | ||
527 | { | ||
528 | .id = UAC3_FUNCTION_SUBCLASS_HEADPHONE, | ||
529 | .map = uac3_badd_headphone_map, | ||
530 | }, | ||
531 | { | ||
532 | .id = UAC3_FUNCTION_SUBCLASS_SPEAKER, | ||
533 | .map = uac3_badd_speaker_map, | ||
534 | }, | ||
535 | { | ||
536 | .id = UAC3_FUNCTION_SUBCLASS_MICROPHONE, | ||
537 | .map = uac3_badd_microphone_map, | ||
538 | }, | ||
539 | { | ||
540 | .id = UAC3_FUNCTION_SUBCLASS_HEADSET, | ||
541 | .map = uac3_badd_headset_map, | ||
542 | }, | ||
543 | { | ||
544 | .id = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, | ||
545 | .map = uac3_badd_headset_map, | ||
546 | }, | ||
547 | { | ||
548 | .id = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, | ||
549 | .map = uac3_badd_speakerphone_map, | ||
550 | }, | ||
551 | { 0 } /* terminator */ | ||
552 | }; | ||
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 764be07474a8..de8bbb304199 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c | |||
@@ -817,15 +817,67 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, | |||
817 | struct uac3_input_terminal_descriptor *input_term; | 817 | struct uac3_input_terminal_descriptor *input_term; |
818 | struct uac3_output_terminal_descriptor *output_term; | 818 | struct uac3_output_terminal_descriptor *output_term; |
819 | struct uac3_cluster_header_descriptor *cluster; | 819 | struct uac3_cluster_header_descriptor *cluster; |
820 | struct uac3_as_header_descriptor *as; | 820 | struct uac3_as_header_descriptor *as = NULL; |
821 | struct uac3_hc_descriptor_header hc_header; | 821 | struct uac3_hc_descriptor_header hc_header; |
822 | struct snd_pcm_chmap_elem *chmap; | 822 | struct snd_pcm_chmap_elem *chmap; |
823 | unsigned char badd_profile; | ||
824 | u64 badd_formats = 0; | ||
823 | unsigned int num_channels; | 825 | unsigned int num_channels; |
824 | struct audioformat *fp; | 826 | struct audioformat *fp; |
825 | u16 cluster_id, wLength; | 827 | u16 cluster_id, wLength; |
826 | int clock = 0; | 828 | int clock = 0; |
827 | int err; | 829 | int err; |
828 | 830 | ||
831 | badd_profile = chip->badd_profile; | ||
832 | |||
833 | if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { | ||
834 | unsigned int maxpacksize = | ||
835 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
836 | |||
837 | switch (maxpacksize) { | ||
838 | default: | ||
839 | dev_err(&dev->dev, | ||
840 | "%u:%d : incorrect wMaxPacketSize for BADD profile\n", | ||
841 | iface_no, altno); | ||
842 | return NULL; | ||
843 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: | ||
844 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: | ||
845 | badd_formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
846 | num_channels = 1; | ||
847 | break; | ||
848 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: | ||
849 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: | ||
850 | badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; | ||
851 | num_channels = 1; | ||
852 | break; | ||
853 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: | ||
854 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: | ||
855 | badd_formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
856 | num_channels = 2; | ||
857 | break; | ||
858 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: | ||
859 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: | ||
860 | badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; | ||
861 | num_channels = 2; | ||
862 | break; | ||
863 | } | ||
864 | |||
865 | chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); | ||
866 | if (!chmap) | ||
867 | return ERR_PTR(-ENOMEM); | ||
868 | |||
869 | if (num_channels == 1) { | ||
870 | chmap->map[0] = SNDRV_CHMAP_MONO; | ||
871 | } else { | ||
872 | chmap->map[0] = SNDRV_CHMAP_FL; | ||
873 | chmap->map[1] = SNDRV_CHMAP_FR; | ||
874 | } | ||
875 | |||
876 | chmap->channels = num_channels; | ||
877 | clock = UAC3_BADD_CS_ID9; | ||
878 | goto found_clock; | ||
879 | } | ||
880 | |||
829 | as = snd_usb_find_csint_desc(alts->extra, alts->extralen, | 881 | as = snd_usb_find_csint_desc(alts->extra, alts->extralen, |
830 | NULL, UAC_AS_GENERAL); | 882 | NULL, UAC_AS_GENERAL); |
831 | if (!as) { | 883 | if (!as) { |
@@ -931,16 +983,29 @@ found_clock: | |||
931 | if (!fp) | 983 | if (!fp) |
932 | return ERR_PTR(-ENOMEM); | 984 | return ERR_PTR(-ENOMEM); |
933 | 985 | ||
934 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, | ||
935 | UAC_VERSION_3, | ||
936 | iface_no); | ||
937 | fp->chmap = chmap; | 986 | fp->chmap = chmap; |
938 | 987 | ||
939 | /* ok, let's parse further... */ | 988 | if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { |
940 | if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { | 989 | fp->attributes = 0; /* No attributes */ |
941 | kfree(fp->rate_table); | 990 | |
942 | kfree(fp); | 991 | fp->fmt_type = UAC_FORMAT_TYPE_I; |
943 | return NULL; | 992 | fp->formats = badd_formats; |
993 | |||
994 | fp->nr_rates = 0; /* SNDRV_PCM_RATE_CONTINUOUS */ | ||
995 | fp->rate_min = UAC3_BADD_SAMPLING_RATE; | ||
996 | fp->rate_max = UAC3_BADD_SAMPLING_RATE; | ||
997 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; | ||
998 | |||
999 | } else { | ||
1000 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, | ||
1001 | UAC_VERSION_3, | ||
1002 | iface_no); | ||
1003 | /* ok, let's parse further... */ | ||
1004 | if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { | ||
1005 | kfree(fp->rate_table); | ||
1006 | kfree(fp); | ||
1007 | return NULL; | ||
1008 | } | ||
944 | } | 1009 | } |
945 | 1010 | ||
946 | return fp; | 1011 | return fp; |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 1cb6b3e9483c..7b28cbde22c0 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -49,6 +49,8 @@ struct snd_usb_audio { | |||
49 | int num_suspended_intf; | 49 | int num_suspended_intf; |
50 | int sample_rate_read_error; | 50 | int sample_rate_read_error; |
51 | 51 | ||
52 | int badd_profile; /* UAC3 BADD profile */ | ||
53 | |||
52 | struct list_head pcm_list; /* list of pcm streams */ | 54 | struct list_head pcm_list; /* list of pcm streams */ |
53 | struct list_head ep_list; /* list of audio-related endpoints */ | 55 | struct list_head ep_list; /* list of audio-related endpoints */ |
54 | int pcm_devs; | 56 | int pcm_devs; |