diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/usbaudio.c | 106 |
1 files changed, 86 insertions, 20 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 3f974a64c55e..823296d7d578 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
@@ -171,7 +171,6 @@ struct snd_usb_substream { | |||
171 | unsigned int curframesize; /* current packet size in frames (for capture) */ | 171 | unsigned int curframesize; /* current packet size in frames (for capture) */ |
172 | unsigned int fill_max: 1; /* fill max packet size always */ | 172 | unsigned int fill_max: 1; /* fill max packet size always */ |
173 | unsigned int fmt_type; /* USB audio format type (1-3) */ | 173 | unsigned int fmt_type; /* USB audio format type (1-3) */ |
174 | unsigned int packs_per_ms; /* packets per millisecond (for playback) */ | ||
175 | 174 | ||
176 | unsigned int running: 1; /* running status */ | 175 | unsigned int running: 1; /* running status */ |
177 | 176 | ||
@@ -608,9 +607,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
608 | break; | 607 | break; |
609 | } | 608 | } |
610 | } | 609 | } |
611 | /* finish at the frame boundary at/after the period boundary */ | 610 | if (period_elapsed) /* finish at the period boundary */ |
612 | if (period_elapsed && | ||
613 | (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1) | ||
614 | break; | 611 | break; |
615 | } | 612 | } |
616 | if (subs->hwptr_done + offs > runtime->buffer_size) { | 613 | if (subs->hwptr_done + offs > runtime->buffer_size) { |
@@ -1068,7 +1065,6 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri | |||
1068 | packs_per_ms = 8 >> subs->datainterval; | 1065 | packs_per_ms = 8 >> subs->datainterval; |
1069 | else | 1066 | else |
1070 | packs_per_ms = 1; | 1067 | packs_per_ms = 1; |
1071 | subs->packs_per_ms = packs_per_ms; | ||
1072 | 1068 | ||
1073 | if (is_playback) { | 1069 | if (is_playback) { |
1074 | urb_packs = max(nrpacks, 1); | 1070 | urb_packs = max(nrpacks, 1); |
@@ -1088,18 +1084,17 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri | |||
1088 | minsize -= minsize >> 3; | 1084 | minsize -= minsize >> 3; |
1089 | minsize = max(minsize, 1u); | 1085 | minsize = max(minsize, 1u); |
1090 | total_packs = (period_bytes + minsize - 1) / minsize; | 1086 | total_packs = (period_bytes + minsize - 1) / minsize; |
1091 | /* round up to multiple of packs_per_ms */ | ||
1092 | total_packs = (total_packs + packs_per_ms - 1) | ||
1093 | & ~(packs_per_ms - 1); | ||
1094 | /* we need at least two URBs for queueing */ | 1087 | /* we need at least two URBs for queueing */ |
1095 | if (total_packs < 2 * packs_per_ms) { | 1088 | if (total_packs < 2) { |
1096 | total_packs = 2 * packs_per_ms; | 1089 | total_packs = 2; |
1097 | } else { | 1090 | } else { |
1098 | /* and we don't want too long a queue either */ | 1091 | /* and we don't want too long a queue either */ |
1099 | maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); | 1092 | maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2); |
1100 | total_packs = min(total_packs, maxpacks); | 1093 | total_packs = min(total_packs, maxpacks); |
1101 | } | 1094 | } |
1102 | } else { | 1095 | } else { |
1096 | while (urb_packs > 1 && urb_packs * maxsize >= period_bytes) | ||
1097 | urb_packs >>= 1; | ||
1103 | total_packs = MAX_URBS * urb_packs; | 1098 | total_packs = MAX_URBS * urb_packs; |
1104 | } | 1099 | } |
1105 | subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; | 1100 | subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; |
@@ -1564,11 +1559,15 @@ static struct snd_pcm_hardware snd_usb_hardware = | |||
1564 | #define hwc_debug(fmt, args...) /**/ | 1559 | #define hwc_debug(fmt, args...) /**/ |
1565 | #endif | 1560 | #endif |
1566 | 1561 | ||
1567 | static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audioformat *fp) | 1562 | static int hw_check_valid_format(struct snd_usb_substream *subs, |
1563 | struct snd_pcm_hw_params *params, | ||
1564 | struct audioformat *fp) | ||
1568 | { | 1565 | { |
1569 | struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | 1566 | struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
1570 | struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | 1567 | struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
1571 | struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 1568 | struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
1569 | struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); | ||
1570 | unsigned int ptime; | ||
1572 | 1571 | ||
1573 | /* check the format */ | 1572 | /* check the format */ |
1574 | if (!snd_mask_test(fmts, fp->format)) { | 1573 | if (!snd_mask_test(fmts, fp->format)) { |
@@ -1589,6 +1588,14 @@ static int hw_check_valid_format(struct snd_pcm_hw_params *params, struct audiof | |||
1589 | hwc_debug(" > check: rate_max %d < min %d\n", fp->rate_max, it->min); | 1588 | hwc_debug(" > check: rate_max %d < min %d\n", fp->rate_max, it->min); |
1590 | return 0; | 1589 | return 0; |
1591 | } | 1590 | } |
1591 | /* check whether the period time is >= the data packet interval */ | ||
1592 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH) { | ||
1593 | ptime = 125 * (1 << fp->datainterval); | ||
1594 | if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { | ||
1595 | hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); | ||
1596 | return 0; | ||
1597 | } | ||
1598 | } | ||
1592 | return 1; | 1599 | return 1; |
1593 | } | 1600 | } |
1594 | 1601 | ||
@@ -1607,7 +1614,7 @@ static int hw_rule_rate(struct snd_pcm_hw_params *params, | |||
1607 | list_for_each(p, &subs->fmt_list) { | 1614 | list_for_each(p, &subs->fmt_list) { |
1608 | struct audioformat *fp; | 1615 | struct audioformat *fp; |
1609 | fp = list_entry(p, struct audioformat, list); | 1616 | fp = list_entry(p, struct audioformat, list); |
1610 | if (!hw_check_valid_format(params, fp)) | 1617 | if (!hw_check_valid_format(subs, params, fp)) |
1611 | continue; | 1618 | continue; |
1612 | if (changed++) { | 1619 | if (changed++) { |
1613 | if (rmin > fp->rate_min) | 1620 | if (rmin > fp->rate_min) |
@@ -1661,7 +1668,7 @@ static int hw_rule_channels(struct snd_pcm_hw_params *params, | |||
1661 | list_for_each(p, &subs->fmt_list) { | 1668 | list_for_each(p, &subs->fmt_list) { |
1662 | struct audioformat *fp; | 1669 | struct audioformat *fp; |
1663 | fp = list_entry(p, struct audioformat, list); | 1670 | fp = list_entry(p, struct audioformat, list); |
1664 | if (!hw_check_valid_format(params, fp)) | 1671 | if (!hw_check_valid_format(subs, params, fp)) |
1665 | continue; | 1672 | continue; |
1666 | if (changed++) { | 1673 | if (changed++) { |
1667 | if (rmin > fp->channels) | 1674 | if (rmin > fp->channels) |
@@ -1714,7 +1721,7 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, | |||
1714 | list_for_each(p, &subs->fmt_list) { | 1721 | list_for_each(p, &subs->fmt_list) { |
1715 | struct audioformat *fp; | 1722 | struct audioformat *fp; |
1716 | fp = list_entry(p, struct audioformat, list); | 1723 | fp = list_entry(p, struct audioformat, list); |
1717 | if (!hw_check_valid_format(params, fp)) | 1724 | if (!hw_check_valid_format(subs, params, fp)) |
1718 | continue; | 1725 | continue; |
1719 | fbits |= (1ULL << fp->format); | 1726 | fbits |= (1ULL << fp->format); |
1720 | } | 1727 | } |
@@ -1732,6 +1739,44 @@ static int hw_rule_format(struct snd_pcm_hw_params *params, | |||
1732 | return changed; | 1739 | return changed; |
1733 | } | 1740 | } |
1734 | 1741 | ||
1742 | static int hw_rule_period_time(struct snd_pcm_hw_params *params, | ||
1743 | struct snd_pcm_hw_rule *rule) | ||
1744 | { | ||
1745 | struct snd_usb_substream *subs = rule->private; | ||
1746 | struct audioformat *fp; | ||
1747 | struct snd_interval *it; | ||
1748 | unsigned char min_datainterval; | ||
1749 | unsigned int pmin; | ||
1750 | int changed; | ||
1751 | |||
1752 | it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); | ||
1753 | hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); | ||
1754 | min_datainterval = 0xff; | ||
1755 | list_for_each_entry(fp, &subs->fmt_list, list) { | ||
1756 | if (!hw_check_valid_format(subs, params, fp)) | ||
1757 | continue; | ||
1758 | min_datainterval = min(min_datainterval, fp->datainterval); | ||
1759 | } | ||
1760 | if (min_datainterval == 0xff) { | ||
1761 | hwc_debug(" --> get emtpy\n"); | ||
1762 | it->empty = 1; | ||
1763 | return -EINVAL; | ||
1764 | } | ||
1765 | pmin = 125 * (1 << min_datainterval); | ||
1766 | changed = 0; | ||
1767 | if (it->min < pmin) { | ||
1768 | it->min = pmin; | ||
1769 | it->openmin = 0; | ||
1770 | changed = 1; | ||
1771 | } | ||
1772 | if (snd_interval_checkempty(it)) { | ||
1773 | it->empty = 1; | ||
1774 | return -EINVAL; | ||
1775 | } | ||
1776 | hwc_debug(" --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); | ||
1777 | return changed; | ||
1778 | } | ||
1779 | |||
1735 | /* | 1780 | /* |
1736 | * If the device supports unusual bit rates, does the request meet these? | 1781 | * If the device supports unusual bit rates, does the request meet these? |
1737 | */ | 1782 | */ |
@@ -1777,6 +1822,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | |||
1777 | static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) | 1822 | static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) |
1778 | { | 1823 | { |
1779 | struct list_head *p; | 1824 | struct list_head *p; |
1825 | unsigned int pt, ptmin; | ||
1826 | int param_period_time_if_needed; | ||
1780 | int err; | 1827 | int err; |
1781 | 1828 | ||
1782 | runtime->hw.formats = subs->formats; | 1829 | runtime->hw.formats = subs->formats; |
@@ -1786,6 +1833,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1786 | runtime->hw.channels_min = 256; | 1833 | runtime->hw.channels_min = 256; |
1787 | runtime->hw.channels_max = 0; | 1834 | runtime->hw.channels_max = 0; |
1788 | runtime->hw.rates = 0; | 1835 | runtime->hw.rates = 0; |
1836 | ptmin = UINT_MAX; | ||
1789 | /* check min/max rates and channels */ | 1837 | /* check min/max rates and channels */ |
1790 | list_for_each(p, &subs->fmt_list) { | 1838 | list_for_each(p, &subs->fmt_list) { |
1791 | struct audioformat *fp; | 1839 | struct audioformat *fp; |
@@ -1804,34 +1852,52 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1804 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = | 1852 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = |
1805 | fp->frame_size; | 1853 | fp->frame_size; |
1806 | } | 1854 | } |
1855 | pt = 125 * (1 << fp->datainterval); | ||
1856 | ptmin = min(ptmin, pt); | ||
1807 | } | 1857 | } |
1808 | 1858 | ||
1809 | /* set the period time minimum 1ms */ | 1859 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
1810 | /* FIXME: high-speed mode allows 125us minimum period, but many parts | 1860 | if (snd_usb_get_speed(subs->dev) != USB_SPEED_HIGH) |
1811 | * in the current code assume the 1ms period. | 1861 | /* full speed devices have fixed data packet interval */ |
1812 | */ | 1862 | ptmin = 1000; |
1863 | if (ptmin == 1000) | ||
1864 | /* if period time doesn't go below 1 ms, no rules needed */ | ||
1865 | param_period_time_if_needed = -1; | ||
1813 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, | 1866 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, |
1814 | 1000, | 1867 | ptmin, UINT_MAX); |
1815 | /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); | ||
1816 | 1868 | ||
1817 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1869 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1818 | hw_rule_rate, subs, | 1870 | hw_rule_rate, subs, |
1819 | SNDRV_PCM_HW_PARAM_FORMAT, | 1871 | SNDRV_PCM_HW_PARAM_FORMAT, |
1820 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1872 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1873 | param_period_time_if_needed, | ||
1821 | -1)) < 0) | 1874 | -1)) < 0) |
1822 | return err; | 1875 | return err; |
1823 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 1876 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
1824 | hw_rule_channels, subs, | 1877 | hw_rule_channels, subs, |
1825 | SNDRV_PCM_HW_PARAM_FORMAT, | 1878 | SNDRV_PCM_HW_PARAM_FORMAT, |
1826 | SNDRV_PCM_HW_PARAM_RATE, | 1879 | SNDRV_PCM_HW_PARAM_RATE, |
1880 | param_period_time_if_needed, | ||
1827 | -1)) < 0) | 1881 | -1)) < 0) |
1828 | return err; | 1882 | return err; |
1829 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | 1883 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, |
1830 | hw_rule_format, subs, | 1884 | hw_rule_format, subs, |
1831 | SNDRV_PCM_HW_PARAM_RATE, | 1885 | SNDRV_PCM_HW_PARAM_RATE, |
1832 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1886 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1887 | param_period_time_if_needed, | ||
1833 | -1)) < 0) | 1888 | -1)) < 0) |
1834 | return err; | 1889 | return err; |
1890 | if (param_period_time_if_needed >= 0) { | ||
1891 | err = snd_pcm_hw_rule_add(runtime, 0, | ||
1892 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
1893 | hw_rule_period_time, subs, | ||
1894 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1895 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1896 | SNDRV_PCM_HW_PARAM_RATE, | ||
1897 | -1); | ||
1898 | if (err < 0) | ||
1899 | return err; | ||
1900 | } | ||
1835 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | 1901 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) |
1836 | return err; | 1902 | return err; |
1837 | return 0; | 1903 | return 0; |