diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-05-31 07:35:44 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-05-31 12:18:04 -0400 |
commit | 09414207d4daab8c4990bface3a79fdba3474bec (patch) | |
tree | aee93c37d2ff13f676342f139ecd5ccdadaf28d3 /sound/usb | |
parent | 67e1daa0bb30eda6ec5add27c3abf4536030f5a6 (diff) |
ALSA: usb-audio: export UAC2 clock selectors as mixer controls
The UAC2 clock selectors are fortunately compatible with UAC1 audio
selector units, so we can simply reuse the same approach to get all the
linked units.
Requests to this control need a different CS value though.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/mixer.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index cb345360f811..a060d005e209 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -313,8 +313,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
313 | buf, sizeof(buf), 1000); | 313 | buf, sizeof(buf), 1000); |
314 | 314 | ||
315 | if (ret < 0) { | 315 | if (ret < 0) { |
316 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 316 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
317 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | 317 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); |
318 | return ret; | 318 | return ret; |
319 | } | 319 | } |
320 | 320 | ||
@@ -610,6 +610,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
610 | */ | 610 | */ |
611 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) | 611 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) |
612 | { | 612 | { |
613 | int err; | ||
613 | void *p1; | 614 | void *p1; |
614 | 615 | ||
615 | memset(term, 0, sizeof(*term)); | 616 | memset(term, 0, sizeof(*term)); |
@@ -630,6 +631,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
630 | term->channels = d->bNrChannels; | 631 | term->channels = d->bNrChannels; |
631 | term->chconfig = le32_to_cpu(d->bmChannelConfig); | 632 | term->chconfig = le32_to_cpu(d->bmChannelConfig); |
632 | term->name = d->iTerminal; | 633 | term->name = d->iTerminal; |
634 | |||
635 | /* call recursively to get the clock selectors */ | ||
636 | err = check_input_term(state, d->bCSourceID, term); | ||
637 | if (err < 0) | ||
638 | return err; | ||
633 | } | 639 | } |
634 | return 0; | 640 | return 0; |
635 | case UAC_FEATURE_UNIT: { | 641 | case UAC_FEATURE_UNIT: { |
@@ -646,7 +652,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
646 | term->name = uac_mixer_unit_iMixer(d); | 652 | term->name = uac_mixer_unit_iMixer(d); |
647 | return 0; | 653 | return 0; |
648 | } | 654 | } |
649 | case UAC_SELECTOR_UNIT: { | 655 | case UAC_SELECTOR_UNIT: |
656 | case UAC2_CLOCK_SELECTOR: { | ||
650 | struct uac_selector_unit_descriptor *d = p1; | 657 | struct uac_selector_unit_descriptor *d = p1; |
651 | /* call recursively to retrieve the channel info */ | 658 | /* call recursively to retrieve the channel info */ |
652 | if (check_input_term(state, d->baSourceID[0], term) < 0) | 659 | if (check_input_term(state, d->baSourceID[0], term) < 0) |
@@ -669,6 +676,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
669 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); | 676 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); |
670 | return 0; | 677 | return 0; |
671 | } | 678 | } |
679 | case UAC2_CLOCK_SOURCE: { | ||
680 | struct uac_clock_source_descriptor *d = p1; | ||
681 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
682 | term->id = id; | ||
683 | term->name = d->iClockSource; | ||
684 | return 0; | ||
685 | } | ||
672 | default: | 686 | default: |
673 | return -ENODEV; | 687 | return -ENODEV; |
674 | } | 688 | } |
@@ -1610,7 +1624,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1610 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1624 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1611 | int val, err; | 1625 | int val, err; |
1612 | 1626 | ||
1613 | err = get_cur_ctl_value(cval, 0, &val); | 1627 | err = get_cur_ctl_value(cval, cval->control << 8, &val); |
1614 | if (err < 0) { | 1628 | if (err < 0) { |
1615 | if (cval->mixer->ignore_ctl_error) { | 1629 | if (cval->mixer->ignore_ctl_error) { |
1616 | ucontrol->value.enumerated.item[0] = 0; | 1630 | ucontrol->value.enumerated.item[0] = 0; |
@@ -1629,7 +1643,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1629 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1643 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1630 | int val, oval, err; | 1644 | int val, oval, err; |
1631 | 1645 | ||
1632 | err = get_cur_ctl_value(cval, 0, &oval); | 1646 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); |
1633 | if (err < 0) { | 1647 | if (err < 0) { |
1634 | if (cval->mixer->ignore_ctl_error) | 1648 | if (cval->mixer->ignore_ctl_error) |
1635 | return 0; | 1649 | return 0; |
@@ -1638,7 +1652,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1638 | val = ucontrol->value.enumerated.item[0]; | 1652 | val = ucontrol->value.enumerated.item[0]; |
1639 | val = get_abs_value(cval, val); | 1653 | val = get_abs_value(cval, val); |
1640 | if (val != oval) { | 1654 | if (val != oval) { |
1641 | set_cur_ctl_value(cval, 0, val); | 1655 | set_cur_ctl_value(cval, cval->control << 8, val); |
1642 | return 1; | 1656 | return 1; |
1643 | } | 1657 | } |
1644 | return 0; | 1658 | return 0; |
@@ -1720,6 +1734,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1720 | cval->res = 1; | 1734 | cval->res = 1; |
1721 | cval->initialized = 1; | 1735 | cval->initialized = 1; |
1722 | 1736 | ||
1737 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | ||
1738 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
1739 | else | ||
1740 | cval->control = 0; | ||
1741 | |||
1723 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); | 1742 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
1724 | if (! namelist) { | 1743 | if (! namelist) { |
1725 | snd_printk(KERN_ERR "cannot malloc\n"); | 1744 | snd_printk(KERN_ERR "cannot malloc\n"); |
@@ -1769,7 +1788,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1769 | if (! len) | 1788 | if (! len) |
1770 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 1789 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
1771 | 1790 | ||
1772 | if ((state->oterm.type & 0xff00) == 0x0100) | 1791 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) |
1792 | append_ctl_name(kctl, " Clock Source"); | ||
1793 | else if ((state->oterm.type & 0xff00) == 0x0100) | ||
1773 | append_ctl_name(kctl, " Capture Source"); | 1794 | append_ctl_name(kctl, " Capture Source"); |
1774 | else | 1795 | else |
1775 | append_ctl_name(kctl, " Playback Source"); | 1796 | append_ctl_name(kctl, " Playback Source"); |
@@ -1803,10 +1824,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1803 | 1824 | ||
1804 | switch (p1[2]) { | 1825 | switch (p1[2]) { |
1805 | case UAC_INPUT_TERMINAL: | 1826 | case UAC_INPUT_TERMINAL: |
1827 | case UAC2_CLOCK_SOURCE: | ||
1806 | return 0; /* NOP */ | 1828 | return 0; /* NOP */ |
1807 | case UAC_MIXER_UNIT: | 1829 | case UAC_MIXER_UNIT: |
1808 | return parse_audio_mixer_unit(state, unitid, p1); | 1830 | return parse_audio_mixer_unit(state, unitid, p1); |
1809 | case UAC_SELECTOR_UNIT: | 1831 | case UAC_SELECTOR_UNIT: |
1832 | case UAC2_CLOCK_SELECTOR: | ||
1810 | return parse_audio_selector_unit(state, unitid, p1); | 1833 | return parse_audio_selector_unit(state, unitid, p1); |
1811 | case UAC_FEATURE_UNIT: | 1834 | case UAC_FEATURE_UNIT: |
1812 | return parse_audio_feature_unit(state, unitid, p1); | 1835 | return parse_audio_feature_unit(state, unitid, p1); |
@@ -1903,6 +1926,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1903 | err = parse_audio_unit(&state, desc->bSourceID); | 1926 | err = parse_audio_unit(&state, desc->bSourceID); |
1904 | if (err < 0) | 1927 | if (err < 0) |
1905 | return err; | 1928 | return err; |
1929 | |||
1930 | /* for UAC2, use the same approach to also add the clock selectors */ | ||
1931 | err = parse_audio_unit(&state, desc->bCSourceID); | ||
1932 | if (err < 0) | ||
1933 | return err; | ||
1906 | } | 1934 | } |
1907 | } | 1935 | } |
1908 | 1936 | ||