diff options
| -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 | ||
