diff options
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 327 |
1 files changed, 296 insertions, 31 deletions
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; |