diff options
Diffstat (limited to 'sound')
-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 | ||