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.c59
1 files changed, 52 insertions, 7 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index f7e1c9f0d3ed..872887624030 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -27,6 +27,7 @@
27#include <linux/pm_qos_params.h> 27#include <linux/pm_qos_params.h>
28#include <linux/uio.h> 28#include <linux/uio.h>
29#include <linux/dma-mapping.h> 29#include <linux/dma-mapping.h>
30#include <linux/math64.h>
30#include <sound/core.h> 31#include <sound/core.h>
31#include <sound/control.h> 32#include <sound/control.h>
32#include <sound/info.h> 33#include <sound/info.h>
@@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
366 return usecs; 367 return usecs;
367} 368}
368 369
370static int calc_boundary(struct snd_pcm_runtime *runtime)
371{
372 u_int64_t boundary;
373
374 boundary = (u_int64_t)runtime->buffer_size *
375 (u_int64_t)runtime->period_size;
376#if BITS_PER_LONG < 64
377 /* try to find lowest common multiple for buffer and period */
378 if (boundary > LONG_MAX - runtime->buffer_size) {
379 u_int32_t remainder = -1;
380 u_int32_t divident = runtime->buffer_size;
381 u_int32_t divisor = runtime->period_size;
382 while (remainder) {
383 remainder = divident % divisor;
384 if (remainder) {
385 divident = divisor;
386 divisor = remainder;
387 }
388 }
389 boundary = div_u64(boundary, divisor);
390 if (boundary > LONG_MAX - runtime->buffer_size)
391 return -ERANGE;
392 }
393#endif
394 if (boundary == 0)
395 return -ERANGE;
396 runtime->boundary = boundary;
397 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
398 runtime->boundary *= 2;
399 return 0;
400}
401
369static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 402static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
370 struct snd_pcm_hw_params *params) 403 struct snd_pcm_hw_params *params)
371{ 404{
@@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
441 runtime->stop_threshold = runtime->buffer_size; 474 runtime->stop_threshold = runtime->buffer_size;
442 runtime->silence_threshold = 0; 475 runtime->silence_threshold = 0;
443 runtime->silence_size = 0; 476 runtime->silence_size = 0;
444 runtime->boundary = runtime->buffer_size; 477 err = calc_boundary(runtime);
445 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) 478 if (err < 0)
446 runtime->boundary *= 2; 479 goto _error;
447 480
448 snd_pcm_timer_resolution_change(substream); 481 snd_pcm_timer_resolution_change(substream);
449 runtime->status->state = SNDRV_PCM_STATE_SETUP; 482 runtime->status->state = SNDRV_PCM_STATE_SETUP;
@@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
516 struct snd_pcm_sw_params *params) 549 struct snd_pcm_sw_params *params)
517{ 550{
518 struct snd_pcm_runtime *runtime; 551 struct snd_pcm_runtime *runtime;
552 int err;
519 553
520 if (PCM_RUNTIME_CHECK(substream)) 554 if (PCM_RUNTIME_CHECK(substream))
521 return -ENXIO; 555 return -ENXIO;
@@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
540 if (params->silence_threshold > runtime->buffer_size) 574 if (params->silence_threshold > runtime->buffer_size)
541 return -EINVAL; 575 return -EINVAL;
542 } 576 }
577 err = 0;
543 snd_pcm_stream_lock_irq(substream); 578 snd_pcm_stream_lock_irq(substream);
544 runtime->tstamp_mode = params->tstamp_mode; 579 runtime->tstamp_mode = params->tstamp_mode;
545 runtime->period_step = params->period_step; 580 runtime->period_step = params->period_step;
@@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
553 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 588 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
554 runtime->silence_size > 0) 589 runtime->silence_size > 0)
555 snd_pcm_playback_silence(substream, ULONG_MAX); 590 snd_pcm_playback_silence(substream, ULONG_MAX);
556 wake_up(&runtime->sleep); 591 err = snd_pcm_update_state(substream, runtime);
557 } 592 }
558 snd_pcm_stream_unlock_irq(substream); 593 snd_pcm_stream_unlock_irq(substream);
559 return 0; 594 return err;
560} 595}
561 596
562static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, 597static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
@@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
917 runtime->status->state = state; 952 runtime->status->state = state;
918 } 953 }
919 wake_up(&runtime->sleep); 954 wake_up(&runtime->sleep);
955 wake_up(&runtime->tsleep);
920} 956}
921 957
922static struct action_ops snd_pcm_action_stop = { 958static struct action_ops snd_pcm_action_stop = {
@@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
1002 SNDRV_TIMER_EVENT_MPAUSE, 1038 SNDRV_TIMER_EVENT_MPAUSE,
1003 &runtime->trigger_tstamp); 1039 &runtime->trigger_tstamp);
1004 wake_up(&runtime->sleep); 1040 wake_up(&runtime->sleep);
1041 wake_up(&runtime->tsleep);
1005 } else { 1042 } else {
1006 runtime->status->state = SNDRV_PCM_STATE_RUNNING; 1043 runtime->status->state = SNDRV_PCM_STATE_RUNNING;
1007 if (substream->timer) 1044 if (substream->timer)
@@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
1059 runtime->status->suspended_state = runtime->status->state; 1096 runtime->status->suspended_state = runtime->status->state;
1060 runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; 1097 runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
1061 wake_up(&runtime->sleep); 1098 wake_up(&runtime->sleep);
1099 wake_up(&runtime->tsleep);
1062} 1100}
1063 1101
1064static struct action_ops snd_pcm_action_suspend = { 1102static struct action_ops snd_pcm_action_suspend = {
@@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
3162 long size; 3200 long size;
3163 unsigned long offset; 3201 unsigned long offset;
3164 3202
3165#ifdef pgprot_noncached
3166 area->vm_page_prot = pgprot_noncached(area->vm_page_prot); 3203 area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
3167#endif
3168 area->vm_flags |= VM_IO; 3204 area->vm_flags |= VM_IO;
3169 size = area->vm_end - area->vm_start; 3205 size = area->vm_end - area->vm_start;
3170 offset = area->vm_pgoff << PAGE_SHIFT; 3206 offset = area->vm_pgoff << PAGE_SHIFT;
@@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
3178EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); 3214EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
3179#endif /* SNDRV_PCM_INFO_MMAP */ 3215#endif /* SNDRV_PCM_INFO_MMAP */
3180 3216
3217/* mmap callback with pgprot_noncached */
3218int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream,
3219 struct vm_area_struct *area)
3220{
3221 area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
3222 return snd_pcm_default_mmap(substream, area);
3223}
3224EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached);
3225
3181/* 3226/*
3182 * mmap DMA buffer 3227 * mmap DMA buffer
3183 */ 3228 */