diff options
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 59 |
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 | ||
370 | static 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 | |||
369 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 402 | static 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 | ||
562 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | 597 | static 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 | ||
922 | static struct action_ops snd_pcm_action_stop = { | 958 | static 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 | ||
1064 | static struct action_ops snd_pcm_action_suspend = { | 1102 | static 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, | |||
3178 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | 3214 | EXPORT_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 */ | ||
3218 | int 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 | } | ||
3224 | EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); | ||
3225 | |||
3181 | /* | 3226 | /* |
3182 | * mmap DMA buffer | 3227 | * mmap DMA buffer |
3183 | */ | 3228 | */ |