aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_native.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r--sound/core/pcm_native.c261
1 files changed, 102 insertions, 159 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0e875d5a9e86..04c6301394d0 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -99,6 +99,57 @@ static inline void down_write_nonblock(struct rw_semaphore *lock)
99 cond_resched(); 99 cond_resched();
100} 100}
101 101
102#define PCM_LOCK_DEFAULT 0
103#define PCM_LOCK_IRQ 1
104#define PCM_LOCK_IRQSAVE 2
105
106static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream,
107 unsigned int mode)
108{
109 unsigned long flags = 0;
110 if (substream->pcm->nonatomic) {
111 down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
112 mutex_lock(&substream->self_group.mutex);
113 } else {
114 switch (mode) {
115 case PCM_LOCK_DEFAULT:
116 read_lock(&snd_pcm_link_rwlock);
117 break;
118 case PCM_LOCK_IRQ:
119 read_lock_irq(&snd_pcm_link_rwlock);
120 break;
121 case PCM_LOCK_IRQSAVE:
122 read_lock_irqsave(&snd_pcm_link_rwlock, flags);
123 break;
124 }
125 spin_lock(&substream->self_group.lock);
126 }
127 return flags;
128}
129
130static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream,
131 unsigned int mode, unsigned long flags)
132{
133 if (substream->pcm->nonatomic) {
134 mutex_unlock(&substream->self_group.mutex);
135 up_read(&snd_pcm_link_rwsem);
136 } else {
137 spin_unlock(&substream->self_group.lock);
138
139 switch (mode) {
140 case PCM_LOCK_DEFAULT:
141 read_unlock(&snd_pcm_link_rwlock);
142 break;
143 case PCM_LOCK_IRQ:
144 read_unlock_irq(&snd_pcm_link_rwlock);
145 break;
146 case PCM_LOCK_IRQSAVE:
147 read_unlock_irqrestore(&snd_pcm_link_rwlock, flags);
148 break;
149 }
150 }
151}
152
102/** 153/**
103 * snd_pcm_stream_lock - Lock the PCM stream 154 * snd_pcm_stream_lock - Lock the PCM stream
104 * @substream: PCM substream 155 * @substream: PCM substream
@@ -109,13 +160,7 @@ static inline void down_write_nonblock(struct rw_semaphore *lock)
109 */ 160 */
110void snd_pcm_stream_lock(struct snd_pcm_substream *substream) 161void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
111{ 162{
112 if (substream->pcm->nonatomic) { 163 __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT);
113 down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
114 mutex_lock(&substream->self_group.mutex);
115 } else {
116 read_lock(&snd_pcm_link_rwlock);
117 spin_lock(&substream->self_group.lock);
118 }
119} 164}
120EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); 165EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
121 166
@@ -127,13 +172,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
127 */ 172 */
128void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) 173void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
129{ 174{
130 if (substream->pcm->nonatomic) { 175 __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0);
131 mutex_unlock(&substream->self_group.mutex);
132 up_read(&snd_pcm_link_rwsem);
133 } else {
134 spin_unlock(&substream->self_group.lock);
135 read_unlock(&snd_pcm_link_rwlock);
136 }
137} 176}
138EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); 177EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
139 178
@@ -147,9 +186,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
147 */ 186 */
148void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) 187void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
149{ 188{
150 if (!substream->pcm->nonatomic) 189 __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ);
151 local_irq_disable();
152 snd_pcm_stream_lock(substream);
153} 190}
154EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); 191EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
155 192
@@ -161,19 +198,13 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
161 */ 198 */
162void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) 199void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
163{ 200{
164 snd_pcm_stream_unlock(substream); 201 __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0);
165 if (!substream->pcm->nonatomic)
166 local_irq_enable();
167} 202}
168EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); 203EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);
169 204
170unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) 205unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
171{ 206{
172 unsigned long flags = 0; 207 return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE);
173 if (!substream->pcm->nonatomic)
174 local_irq_save(flags);
175 snd_pcm_stream_lock(substream);
176 return flags;
177} 208}
178EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); 209EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
179 210
@@ -187,9 +218,7 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
187void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, 218void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
188 unsigned long flags) 219 unsigned long flags)
189{ 220{
190 snd_pcm_stream_unlock(substream); 221 __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags);
191 if (!substream->pcm->nonatomic)
192 local_irq_restore(flags);
193} 222}
194EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); 223EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
195 224
@@ -857,6 +886,18 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
857 return err; 886 return err;
858} 887}
859 888
889static inline snd_pcm_uframes_t
890snd_pcm_calc_delay(struct snd_pcm_substream *substream)
891{
892 snd_pcm_uframes_t delay;
893
894 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
895 delay = snd_pcm_playback_hw_avail(substream->runtime);
896 else
897 delay = snd_pcm_capture_avail(substream->runtime);
898 return delay + substream->runtime->delay;
899}
900
860int snd_pcm_status(struct snd_pcm_substream *substream, 901int snd_pcm_status(struct snd_pcm_substream *substream,
861 struct snd_pcm_status *status) 902 struct snd_pcm_status *status)
862{ 903{
@@ -908,21 +949,9 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
908 _tstamp_end: 949 _tstamp_end:
909 status->appl_ptr = runtime->control->appl_ptr; 950 status->appl_ptr = runtime->control->appl_ptr;
910 status->hw_ptr = runtime->status->hw_ptr; 951 status->hw_ptr = runtime->status->hw_ptr;
911 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 952 status->avail = snd_pcm_avail(substream);
912 status->avail = snd_pcm_playback_avail(runtime); 953 status->delay = snd_pcm_running(substream) ?
913 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || 954 snd_pcm_calc_delay(substream) : 0;
914 runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
915 status->delay = runtime->buffer_size - status->avail;
916 status->delay += runtime->delay;
917 } else
918 status->delay = 0;
919 } else {
920 status->avail = snd_pcm_capture_avail(runtime);
921 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
922 status->delay = status->avail + runtime->delay;
923 else
924 status->delay = 0;
925 }
926 status->avail_max = runtime->avail_max; 955 status->avail_max = runtime->avail_max;
927 status->overrange = runtime->overrange; 956 status->overrange = runtime->overrange;
928 runtime->avail_max = 0; 957 runtime->avail_max = 0;
@@ -2610,10 +2639,9 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
2610 return ret < 0 ? 0 : frames; 2639 return ret < 0 ? 0 : frames;
2611} 2640}
2612 2641
2613static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, 2642static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream,
2614 snd_pcm_uframes_t frames) 2643 snd_pcm_uframes_t frames)
2615{ 2644{
2616 struct snd_pcm_runtime *runtime = substream->runtime;
2617 snd_pcm_sframes_t ret; 2645 snd_pcm_sframes_t ret;
2618 2646
2619 if (frames == 0) 2647 if (frames == 0)
@@ -2623,33 +2651,14 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst
2623 ret = do_pcm_hwsync(substream); 2651 ret = do_pcm_hwsync(substream);
2624 if (!ret) 2652 if (!ret)
2625 ret = rewind_appl_ptr(substream, frames, 2653 ret = rewind_appl_ptr(substream, frames,
2626 snd_pcm_playback_hw_avail(runtime)); 2654 snd_pcm_hw_avail(substream));
2627 snd_pcm_stream_unlock_irq(substream); 2655 snd_pcm_stream_unlock_irq(substream);
2628 return ret; 2656 return ret;
2629} 2657}
2630 2658
2631static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, 2659static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream,
2632 snd_pcm_uframes_t frames) 2660 snd_pcm_uframes_t frames)
2633{ 2661{
2634 struct snd_pcm_runtime *runtime = substream->runtime;
2635 snd_pcm_sframes_t ret;
2636
2637 if (frames == 0)
2638 return 0;
2639
2640 snd_pcm_stream_lock_irq(substream);
2641 ret = do_pcm_hwsync(substream);
2642 if (!ret)
2643 ret = rewind_appl_ptr(substream, frames,
2644 snd_pcm_capture_hw_avail(runtime));
2645 snd_pcm_stream_unlock_irq(substream);
2646 return ret;
2647}
2648
2649static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream,
2650 snd_pcm_uframes_t frames)
2651{
2652 struct snd_pcm_runtime *runtime = substream->runtime;
2653 snd_pcm_sframes_t ret; 2662 snd_pcm_sframes_t ret;
2654 2663
2655 if (frames == 0) 2664 if (frames == 0)
@@ -2659,25 +2668,7 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs
2659 ret = do_pcm_hwsync(substream); 2668 ret = do_pcm_hwsync(substream);
2660 if (!ret) 2669 if (!ret)
2661 ret = forward_appl_ptr(substream, frames, 2670 ret = forward_appl_ptr(substream, frames,
2662 snd_pcm_playback_avail(runtime)); 2671 snd_pcm_avail(substream));
2663 snd_pcm_stream_unlock_irq(substream);
2664 return ret;
2665}
2666
2667static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream,
2668 snd_pcm_uframes_t frames)
2669{
2670 struct snd_pcm_runtime *runtime = substream->runtime;
2671 snd_pcm_sframes_t ret;
2672
2673 if (frames == 0)
2674 return 0;
2675
2676 snd_pcm_stream_lock_irq(substream);
2677 ret = do_pcm_hwsync(substream);
2678 if (!ret)
2679 ret = forward_appl_ptr(substream, frames,
2680 snd_pcm_capture_avail(runtime));
2681 snd_pcm_stream_unlock_irq(substream); 2672 snd_pcm_stream_unlock_irq(substream);
2682 return ret; 2673 return ret;
2683} 2674}
@@ -2695,19 +2686,13 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
2695static int snd_pcm_delay(struct snd_pcm_substream *substream, 2686static int snd_pcm_delay(struct snd_pcm_substream *substream,
2696 snd_pcm_sframes_t *delay) 2687 snd_pcm_sframes_t *delay)
2697{ 2688{
2698 struct snd_pcm_runtime *runtime = substream->runtime;
2699 int err; 2689 int err;
2700 snd_pcm_sframes_t n = 0; 2690 snd_pcm_sframes_t n = 0;
2701 2691
2702 snd_pcm_stream_lock_irq(substream); 2692 snd_pcm_stream_lock_irq(substream);
2703 err = do_pcm_hwsync(substream); 2693 err = do_pcm_hwsync(substream);
2704 if (!err) { 2694 if (!err)
2705 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2695 n = snd_pcm_calc_delay(substream);
2706 n = snd_pcm_playback_hw_avail(runtime);
2707 else
2708 n = snd_pcm_capture_avail(runtime);
2709 n += runtime->delay;
2710 }
2711 snd_pcm_stream_unlock_irq(substream); 2696 snd_pcm_stream_unlock_irq(substream);
2712 if (!err) 2697 if (!err)
2713 *delay = n; 2698 *delay = n;
@@ -2834,10 +2819,7 @@ static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream,
2834 return -EFAULT; 2819 return -EFAULT;
2835 if (put_user(0, _frames)) 2820 if (put_user(0, _frames))
2836 return -EFAULT; 2821 return -EFAULT;
2837 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2822 result = snd_pcm_rewind(substream, frames);
2838 result = snd_pcm_playback_rewind(substream, frames);
2839 else
2840 result = snd_pcm_capture_rewind(substream, frames);
2841 __put_user(result, _frames); 2823 __put_user(result, _frames);
2842 return result < 0 ? result : 0; 2824 return result < 0 ? result : 0;
2843} 2825}
@@ -2852,10 +2834,7 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream,
2852 return -EFAULT; 2834 return -EFAULT;
2853 if (put_user(0, _frames)) 2835 if (put_user(0, _frames))
2854 return -EFAULT; 2836 return -EFAULT;
2855 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2837 result = snd_pcm_forward(substream, frames);
2856 result = snd_pcm_playback_forward(substream, frames);
2857 else
2858 result = snd_pcm_capture_forward(substream, frames);
2859 __put_user(result, _frames); 2838 __put_user(result, _frames);
2860 return result < 0 ? result : 0; 2839 return result < 0 ? result : 0;
2861} 2840}
@@ -2998,7 +2977,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
2998 /* provided only for OSS; capture-only and no value returned */ 2977 /* provided only for OSS; capture-only and no value returned */
2999 if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) 2978 if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
3000 return -EINVAL; 2979 return -EINVAL;
3001 result = snd_pcm_capture_forward(substream, *frames); 2980 result = snd_pcm_forward(substream, *frames);
3002 return result < 0 ? result : 0; 2981 return result < 0 ? result : 0;
3003 } 2982 }
3004 case SNDRV_PCM_IOCTL_HW_PARAMS: 2983 case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -3140,82 +3119,46 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
3140 return result; 3119 return result;
3141} 3120}
3142 3121
3143static __poll_t snd_pcm_playback_poll(struct file *file, poll_table * wait) 3122static __poll_t snd_pcm_poll(struct file *file, poll_table *wait)
3144{ 3123{
3145 struct snd_pcm_file *pcm_file; 3124 struct snd_pcm_file *pcm_file;
3146 struct snd_pcm_substream *substream; 3125 struct snd_pcm_substream *substream;
3147 struct snd_pcm_runtime *runtime; 3126 struct snd_pcm_runtime *runtime;
3148 __poll_t mask; 3127 __poll_t mask, ok;
3149 snd_pcm_uframes_t avail; 3128 snd_pcm_uframes_t avail;
3150 3129
3151 pcm_file = file->private_data; 3130 pcm_file = file->private_data;
3152 3131
3153 substream = pcm_file->substream; 3132 substream = pcm_file->substream;
3133 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
3134 ok = EPOLLOUT | EPOLLWRNORM;
3135 else
3136 ok = EPOLLIN | EPOLLRDNORM;
3154 if (PCM_RUNTIME_CHECK(substream)) 3137 if (PCM_RUNTIME_CHECK(substream))
3155 return EPOLLOUT | EPOLLWRNORM | EPOLLERR; 3138 return ok | EPOLLERR;
3156 runtime = substream->runtime;
3157
3158 poll_wait(file, &runtime->sleep, wait);
3159 3139
3160 snd_pcm_stream_lock_irq(substream);
3161 avail = snd_pcm_playback_avail(runtime);
3162 switch (runtime->status->state) {
3163 case SNDRV_PCM_STATE_RUNNING:
3164 case SNDRV_PCM_STATE_PREPARED:
3165 case SNDRV_PCM_STATE_PAUSED:
3166 if (avail >= runtime->control->avail_min) {
3167 mask = EPOLLOUT | EPOLLWRNORM;
3168 break;
3169 }
3170 /* Fall through */
3171 case SNDRV_PCM_STATE_DRAINING:
3172 mask = 0;
3173 break;
3174 default:
3175 mask = EPOLLOUT | EPOLLWRNORM | EPOLLERR;
3176 break;
3177 }
3178 snd_pcm_stream_unlock_irq(substream);
3179 return mask;
3180}
3181
3182static __poll_t snd_pcm_capture_poll(struct file *file, poll_table * wait)
3183{
3184 struct snd_pcm_file *pcm_file;
3185 struct snd_pcm_substream *substream;
3186 struct snd_pcm_runtime *runtime;
3187 __poll_t mask;
3188 snd_pcm_uframes_t avail;
3189
3190 pcm_file = file->private_data;
3191
3192 substream = pcm_file->substream;
3193 if (PCM_RUNTIME_CHECK(substream))
3194 return EPOLLIN | EPOLLRDNORM | EPOLLERR;
3195 runtime = substream->runtime; 3140 runtime = substream->runtime;
3196
3197 poll_wait(file, &runtime->sleep, wait); 3141 poll_wait(file, &runtime->sleep, wait);
3198 3142
3143 mask = 0;
3199 snd_pcm_stream_lock_irq(substream); 3144 snd_pcm_stream_lock_irq(substream);
3200 avail = snd_pcm_capture_avail(runtime); 3145 avail = snd_pcm_avail(substream);
3201 switch (runtime->status->state) { 3146 switch (runtime->status->state) {
3202 case SNDRV_PCM_STATE_RUNNING: 3147 case SNDRV_PCM_STATE_RUNNING:
3203 case SNDRV_PCM_STATE_PREPARED: 3148 case SNDRV_PCM_STATE_PREPARED:
3204 case SNDRV_PCM_STATE_PAUSED: 3149 case SNDRV_PCM_STATE_PAUSED:
3205 if (avail >= runtime->control->avail_min) { 3150 if (avail >= runtime->control->avail_min)
3206 mask = EPOLLIN | EPOLLRDNORM; 3151 mask = ok;
3207 break;
3208 }
3209 mask = 0;
3210 break; 3152 break;
3211 case SNDRV_PCM_STATE_DRAINING: 3153 case SNDRV_PCM_STATE_DRAINING:
3212 if (avail > 0) { 3154 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
3213 mask = EPOLLIN | EPOLLRDNORM; 3155 mask = ok;
3214 break; 3156 if (!avail)
3157 mask |= EPOLLERR;
3215 } 3158 }
3216 /* Fall through */ 3159 break;
3217 default: 3160 default:
3218 mask = EPOLLIN | EPOLLRDNORM | EPOLLERR; 3161 mask = ok | EPOLLERR;
3219 break; 3162 break;
3220 } 3163 }
3221 snd_pcm_stream_unlock_irq(substream); 3164 snd_pcm_stream_unlock_irq(substream);
@@ -3707,7 +3650,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
3707 .open = snd_pcm_playback_open, 3650 .open = snd_pcm_playback_open,
3708 .release = snd_pcm_release, 3651 .release = snd_pcm_release,
3709 .llseek = no_llseek, 3652 .llseek = no_llseek,
3710 .poll = snd_pcm_playback_poll, 3653 .poll = snd_pcm_poll,
3711 .unlocked_ioctl = snd_pcm_ioctl, 3654 .unlocked_ioctl = snd_pcm_ioctl,
3712 .compat_ioctl = snd_pcm_ioctl_compat, 3655 .compat_ioctl = snd_pcm_ioctl_compat,
3713 .mmap = snd_pcm_mmap, 3656 .mmap = snd_pcm_mmap,
@@ -3721,7 +3664,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
3721 .open = snd_pcm_capture_open, 3664 .open = snd_pcm_capture_open,
3722 .release = snd_pcm_release, 3665 .release = snd_pcm_release,
3723 .llseek = no_llseek, 3666 .llseek = no_llseek,
3724 .poll = snd_pcm_capture_poll, 3667 .poll = snd_pcm_poll,
3725 .unlocked_ioctl = snd_pcm_ioctl, 3668 .unlocked_ioctl = snd_pcm_ioctl,
3726 .compat_ioctl = snd_pcm_ioctl_compat, 3669 .compat_ioctl = snd_pcm_ioctl_compat,
3727 .mmap = snd_pcm_mmap, 3670 .mmap = snd_pcm_mmap,