diff options
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r-- | sound/core/pcm_lib.c | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 86d0caf91b35..3420bd3da5d7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/time.h> | 24 | #include <linux/time.h> |
25 | #include <linux/math64.h> | 25 | #include <linux/math64.h> |
26 | #include <linux/export.h> | ||
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/control.h> | 28 | #include <sound/control.h> |
28 | #include <sound/info.h> | 29 | #include <sound/info.h> |
@@ -1399,6 +1400,32 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, | |||
1399 | 1400 | ||
1400 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); | 1401 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); |
1401 | 1402 | ||
1403 | static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, | ||
1404 | struct snd_pcm_hw_rule *rule) | ||
1405 | { | ||
1406 | unsigned int base_rate = (unsigned int)(uintptr_t)rule->private; | ||
1407 | struct snd_interval *rate; | ||
1408 | |||
1409 | rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
1410 | return snd_interval_list(rate, 1, &base_rate, 0); | ||
1411 | } | ||
1412 | |||
1413 | /** | ||
1414 | * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling | ||
1415 | * @runtime: PCM runtime instance | ||
1416 | * @base_rate: the rate at which the hardware does not resample | ||
1417 | */ | ||
1418 | int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime, | ||
1419 | unsigned int base_rate) | ||
1420 | { | ||
1421 | return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE, | ||
1422 | SNDRV_PCM_HW_PARAM_RATE, | ||
1423 | snd_pcm_hw_rule_noresample_func, | ||
1424 | (void *)(uintptr_t)base_rate, | ||
1425 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1426 | } | ||
1427 | EXPORT_SYMBOL(snd_pcm_hw_rule_noresample); | ||
1428 | |||
1402 | static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, | 1429 | static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, |
1403 | snd_pcm_hw_param_t var) | 1430 | snd_pcm_hw_param_t var) |
1404 | { | 1431 | { |
@@ -1761,6 +1788,10 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1761 | snd_pcm_uframes_t avail = 0; | 1788 | snd_pcm_uframes_t avail = 0; |
1762 | long wait_time, tout; | 1789 | long wait_time, tout; |
1763 | 1790 | ||
1791 | init_waitqueue_entry(&wait, current); | ||
1792 | set_current_state(TASK_INTERRUPTIBLE); | ||
1793 | add_wait_queue(&runtime->tsleep, &wait); | ||
1794 | |||
1764 | if (runtime->no_period_wakeup) | 1795 | if (runtime->no_period_wakeup) |
1765 | wait_time = MAX_SCHEDULE_TIMEOUT; | 1796 | wait_time = MAX_SCHEDULE_TIMEOUT; |
1766 | else { | 1797 | else { |
@@ -1771,16 +1802,32 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1771 | } | 1802 | } |
1772 | wait_time = msecs_to_jiffies(wait_time * 1000); | 1803 | wait_time = msecs_to_jiffies(wait_time * 1000); |
1773 | } | 1804 | } |
1774 | init_waitqueue_entry(&wait, current); | 1805 | |
1775 | add_wait_queue(&runtime->tsleep, &wait); | ||
1776 | for (;;) { | 1806 | for (;;) { |
1777 | if (signal_pending(current)) { | 1807 | if (signal_pending(current)) { |
1778 | err = -ERESTARTSYS; | 1808 | err = -ERESTARTSYS; |
1779 | break; | 1809 | break; |
1780 | } | 1810 | } |
1811 | |||
1812 | /* | ||
1813 | * We need to check if space became available already | ||
1814 | * (and thus the wakeup happened already) first to close | ||
1815 | * the race of space already having become available. | ||
1816 | * This check must happen after been added to the waitqueue | ||
1817 | * and having current state be INTERRUPTIBLE. | ||
1818 | */ | ||
1819 | if (is_playback) | ||
1820 | avail = snd_pcm_playback_avail(runtime); | ||
1821 | else | ||
1822 | avail = snd_pcm_capture_avail(runtime); | ||
1823 | if (avail >= runtime->twake) | ||
1824 | break; | ||
1781 | snd_pcm_stream_unlock_irq(substream); | 1825 | snd_pcm_stream_unlock_irq(substream); |
1782 | tout = schedule_timeout_interruptible(wait_time); | 1826 | |
1827 | tout = schedule_timeout(wait_time); | ||
1828 | |||
1783 | snd_pcm_stream_lock_irq(substream); | 1829 | snd_pcm_stream_lock_irq(substream); |
1830 | set_current_state(TASK_INTERRUPTIBLE); | ||
1784 | switch (runtime->status->state) { | 1831 | switch (runtime->status->state) { |
1785 | case SNDRV_PCM_STATE_SUSPENDED: | 1832 | case SNDRV_PCM_STATE_SUSPENDED: |
1786 | err = -ESTRPIPE; | 1833 | err = -ESTRPIPE; |
@@ -1806,14 +1853,9 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1806 | err = -EIO; | 1853 | err = -EIO; |
1807 | break; | 1854 | break; |
1808 | } | 1855 | } |
1809 | if (is_playback) | ||
1810 | avail = snd_pcm_playback_avail(runtime); | ||
1811 | else | ||
1812 | avail = snd_pcm_capture_avail(runtime); | ||
1813 | if (avail >= runtime->twake) | ||
1814 | break; | ||
1815 | } | 1856 | } |
1816 | _endloop: | 1857 | _endloop: |
1858 | set_current_state(TASK_RUNNING); | ||
1817 | remove_wait_queue(&runtime->tsleep, &wait); | 1859 | remove_wait_queue(&runtime->tsleep, &wait); |
1818 | *availp = avail; | 1860 | *availp = avail; |
1819 | return err; | 1861 | return err; |