diff options
author | Jorge Sanjuan <jorge.sanjuan@codethink.co.uk> | 2018-07-11 08:37:51 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2018-07-16 10:34:44 -0400 |
commit | c77e1ef1cdf74dba09edfa706fecc9fddd7bd084 (patch) | |
tree | bbf515da4082d4f8d0eb6ccc886598225a5dacb8 /sound/usb/mixer.c | |
parent | d6e08c7eabefc9b027d31d56024810eba76ce113 (diff) |
ALSA: usb-audio: Add support for Selector Units in UAC3
This patch add support for Selector Units and Clock Selector Units
defined in the new UAC3 spec.
Selector Units play a really important role in the new UAC3 spec as
Processing Units do not define an on/off switch control anymore.
This forces topology designers to add bypass paths in the topology
to enable/dissable the Processing Units.
Signed-off-by: Jorge Sanjuan <jorge.sanjuan@codethink.co.uk>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r-- | sound/usb/mixer.c | 54 |
1 files changed, 44 insertions, 10 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index ca963e94ec03..a51f2320a3dd 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -940,6 +940,19 @@ static int check_input_term(struct mixer_build *state, int id, | |||
940 | 940 | ||
941 | return 0; | 941 | return 0; |
942 | } | 942 | } |
943 | case UAC3_SELECTOR_UNIT: | ||
944 | case UAC3_CLOCK_SELECTOR: { | ||
945 | struct uac_selector_unit_descriptor *d = p1; | ||
946 | /* call recursively to retrieve the channel info */ | ||
947 | err = check_input_term(state, d->baSourceID[0], term); | ||
948 | if (err < 0) | ||
949 | return err; | ||
950 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
951 | term->id = id; | ||
952 | term->name = 0; /* TODO: UAC3 Class-specific strings */ | ||
953 | |||
954 | return 0; | ||
955 | } | ||
943 | default: | 956 | default: |
944 | return -ENODEV; | 957 | return -ENODEV; |
945 | } | 958 | } |
@@ -2509,11 +2522,20 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2509 | cval->res = 1; | 2522 | cval->res = 1; |
2510 | cval->initialized = 1; | 2523 | cval->initialized = 1; |
2511 | 2524 | ||
2512 | if (state->mixer->protocol == UAC_VERSION_1) | 2525 | switch (state->mixer->protocol) { |
2526 | case UAC_VERSION_1: | ||
2527 | default: | ||
2513 | cval->control = 0; | 2528 | cval->control = 0; |
2514 | else /* UAC_VERSION_2 */ | 2529 | break; |
2515 | cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ? | 2530 | case UAC_VERSION_2: |
2516 | UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR; | 2531 | case UAC_VERSION_3: |
2532 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR || | ||
2533 | desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR) | ||
2534 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
2535 | else /* UAC2/3_SELECTOR_UNIT */ | ||
2536 | cval->control = UAC2_SU_SELECTOR; | ||
2537 | break; | ||
2538 | } | ||
2517 | 2539 | ||
2518 | namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); | 2540 | namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL); |
2519 | if (!namelist) { | 2541 | if (!namelist) { |
@@ -2555,12 +2577,22 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2555 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 2577 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
2556 | if (!len) { | 2578 | if (!len) { |
2557 | /* no mapping ? */ | 2579 | /* no mapping ? */ |
2580 | switch (state->mixer->protocol) { | ||
2581 | case UAC_VERSION_1: | ||
2582 | case UAC_VERSION_2: | ||
2583 | default: | ||
2558 | /* if iSelector is given, use it */ | 2584 | /* if iSelector is given, use it */ |
2559 | nameid = uac_selector_unit_iSelector(desc); | 2585 | nameid = uac_selector_unit_iSelector(desc); |
2560 | if (nameid) | 2586 | if (nameid) |
2561 | len = snd_usb_copy_string_desc(state->chip, nameid, | 2587 | len = snd_usb_copy_string_desc(state->chip, |
2562 | kctl->id.name, | 2588 | nameid, kctl->id.name, |
2563 | sizeof(kctl->id.name)); | 2589 | sizeof(kctl->id.name)); |
2590 | break; | ||
2591 | case UAC_VERSION_3: | ||
2592 | /* TODO: Class-Specific strings not yet supported */ | ||
2593 | break; | ||
2594 | } | ||
2595 | |||
2564 | /* ... or pick up the terminal name at next */ | 2596 | /* ... or pick up the terminal name at next */ |
2565 | if (!len) | 2597 | if (!len) |
2566 | len = get_term_name(state->chip, &state->oterm, | 2598 | len = get_term_name(state->chip, &state->oterm, |
@@ -2570,7 +2602,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2570 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 2602 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
2571 | 2603 | ||
2572 | /* and add the proper suffix */ | 2604 | /* and add the proper suffix */ |
2573 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | 2605 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR || |
2606 | desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR) | ||
2574 | append_ctl_name(kctl, " Clock Source"); | 2607 | append_ctl_name(kctl, " Clock Source"); |
2575 | else if ((state->oterm.type & 0xff00) == 0x0100) | 2608 | else if ((state->oterm.type & 0xff00) == 0x0100) |
2576 | append_ctl_name(kctl, " Capture Source"); | 2609 | append_ctl_name(kctl, " Capture Source"); |
@@ -2641,6 +2674,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
2641 | return parse_audio_mixer_unit(state, unitid, p1); | 2674 | return parse_audio_mixer_unit(state, unitid, p1); |
2642 | case UAC3_CLOCK_SOURCE: | 2675 | case UAC3_CLOCK_SOURCE: |
2643 | return parse_clock_source_unit(state, unitid, p1); | 2676 | return parse_clock_source_unit(state, unitid, p1); |
2677 | case UAC3_SELECTOR_UNIT: | ||
2644 | case UAC3_CLOCK_SELECTOR: | 2678 | case UAC3_CLOCK_SELECTOR: |
2645 | return parse_audio_selector_unit(state, unitid, p1); | 2679 | return parse_audio_selector_unit(state, unitid, p1); |
2646 | case UAC3_FEATURE_UNIT: | 2680 | case UAC3_FEATURE_UNIT: |