diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/usbaudio.c | 135 |
1 files changed, 19 insertions, 116 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 175c7d1da5cf..b7fa0b0b713d 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -1736,97 +1736,6 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, | |||
1736 | return changed; | 1736 | return changed; |
1737 | } | 1737 | } |
1738 | 1738 | ||
1739 | #define MAX_MASK 64 | ||
1740 | |||
1741 | /* | ||
1742 | * check whether the registered audio formats need special hw-constraints | ||
1743 | */ | ||
1744 | static int check_hw_params_convention(struct snd_usb_substream *subs) | ||
1745 | { | ||
1746 | int i; | ||
1747 | u32 *channels; | ||
1748 | u32 *rates; | ||
1749 | u32 cmaster, rmaster; | ||
1750 | u32 rate_min = 0, rate_max = 0; | ||
1751 | struct list_head *p; | ||
1752 | int err = 1; | ||
1753 | |||
1754 | channels = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); | ||
1755 | rates = kcalloc(MAX_MASK, sizeof(u32), GFP_KERNEL); | ||
1756 | if (!channels || !rates) { | ||
1757 | err = -ENOMEM; | ||
1758 | goto __out; | ||
1759 | } | ||
1760 | |||
1761 | list_for_each(p, &subs->fmt_list) { | ||
1762 | struct audioformat *f; | ||
1763 | f = list_entry(p, struct audioformat, list); | ||
1764 | /* unconventional channels? */ | ||
1765 | if (f->channels > 32) | ||
1766 | goto __out; | ||
1767 | /* continuous rate min/max matches? */ | ||
1768 | if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { | ||
1769 | if (rate_min && f->rate_min != rate_min) | ||
1770 | goto __out; | ||
1771 | if (rate_max && f->rate_max != rate_max) | ||
1772 | goto __out; | ||
1773 | rate_min = f->rate_min; | ||
1774 | rate_max = f->rate_max; | ||
1775 | } | ||
1776 | /* combination of continuous rates and fixed rates? */ | ||
1777 | if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) { | ||
1778 | if (f->rates != rates[f->format]) | ||
1779 | goto __out; | ||
1780 | } | ||
1781 | if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { | ||
1782 | if (rates[f->format] && rates[f->format] != f->rates) | ||
1783 | goto __out; | ||
1784 | } | ||
1785 | channels[f->format] |= 1 << (f->channels - 1); | ||
1786 | rates[f->format] |= f->rates; | ||
1787 | /* needs knot? */ | ||
1788 | if (f->rates & SNDRV_PCM_RATE_KNOT) | ||
1789 | goto __out; | ||
1790 | } | ||
1791 | /* check whether channels and rates match for all formats */ | ||
1792 | cmaster = rmaster = 0; | ||
1793 | for (i = 0; i < MAX_MASK; i++) { | ||
1794 | if (cmaster != channels[i] && cmaster && channels[i]) | ||
1795 | goto __out; | ||
1796 | if (rmaster != rates[i] && rmaster && rates[i]) | ||
1797 | goto __out; | ||
1798 | if (channels[i]) | ||
1799 | cmaster = channels[i]; | ||
1800 | if (rates[i]) | ||
1801 | rmaster = rates[i]; | ||
1802 | } | ||
1803 | /* check whether channels match for all distinct rates */ | ||
1804 | memset(channels, 0, MAX_MASK * sizeof(u32)); | ||
1805 | list_for_each(p, &subs->fmt_list) { | ||
1806 | struct audioformat *f; | ||
1807 | f = list_entry(p, struct audioformat, list); | ||
1808 | if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) | ||
1809 | continue; | ||
1810 | for (i = 0; i < 32; i++) { | ||
1811 | if (f->rates & (1 << i)) | ||
1812 | channels[i] |= 1 << (f->channels - 1); | ||
1813 | } | ||
1814 | } | ||
1815 | cmaster = 0; | ||
1816 | for (i = 0; i < 32; i++) { | ||
1817 | if (cmaster != channels[i] && cmaster && channels[i]) | ||
1818 | goto __out; | ||
1819 | if (channels[i]) | ||
1820 | cmaster = channels[i]; | ||
1821 | } | ||
1822 | err = 0; | ||
1823 | |||
1824 | __out: | ||
1825 | kfree(channels); | ||
1826 | kfree(rates); | ||
1827 | return err; | ||
1828 | } | ||
1829 | |||
1830 | /* | 1739 | /* |
1831 | * If the device supports unusual bit rates, does the request meet these? | 1740 | * If the device supports unusual bit rates, does the request meet these? |
1832 | */ | 1741 | */ |
@@ -1909,32 +1818,26 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1909 | 1000, | 1818 | 1000, |
1910 | /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); | 1819 | /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); |
1911 | 1820 | ||
1912 | err = check_hw_params_convention(subs); | 1821 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1913 | if (err < 0) | 1822 | hw_rule_rate, subs, |
1823 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1824 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1825 | -1)) < 0) | ||
1826 | return err; | ||
1827 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1828 | hw_rule_channels, subs, | ||
1829 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1830 | SNDRV_PCM_HW_PARAM_RATE, | ||
1831 | -1)) < 0) | ||
1832 | return err; | ||
1833 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
1834 | hw_rule_format, subs, | ||
1835 | SNDRV_PCM_HW_PARAM_RATE, | ||
1836 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1837 | -1)) < 0) | ||
1838 | return err; | ||
1839 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | ||
1914 | return err; | 1840 | return err; |
1915 | else if (err) { | ||
1916 | hwc_debug("setting extra hw constraints...\n"); | ||
1917 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
1918 | hw_rule_rate, subs, | ||
1919 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1920 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1921 | -1)) < 0) | ||
1922 | return err; | ||
1923 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1924 | hw_rule_channels, subs, | ||
1925 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1926 | SNDRV_PCM_HW_PARAM_RATE, | ||
1927 | -1)) < 0) | ||
1928 | return err; | ||
1929 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
1930 | hw_rule_format, subs, | ||
1931 | SNDRV_PCM_HW_PARAM_RATE, | ||
1932 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1933 | -1)) < 0) | ||
1934 | return err; | ||
1935 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | ||
1936 | return err; | ||
1937 | } | ||
1938 | return 0; | 1841 | return 0; |
1939 | } | 1842 | } |
1940 | 1843 | ||