aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-05-21 03:15:59 -0400
committerTakashi Iwai <tiwai@suse.de>2010-05-21 10:33:34 -0400
commitead4046b2fdfd69acc4272e693afd249ad3eb689 (patch)
tree9dbc91adb9f4c654f6b9eaa245422162f12e8e47
parent7f06a8b26aba1dc03b42272dc0089a800372c575 (diff)
ALSA: pcm: fix the fix of the runtime->boundary calculation
Commit 7910b4a1db63fefc3d291853d33c34c5b6352e8e in 2.6.34 changed the runtime->boundary calculation to make this value a multiple of both the buffer_size and the period_size, because the latter is assumed by the runtime->hw_ptr_interrupt calculation. However, due to the lack of a ioctl that could read the software parameters before they are set, the kernel requires that alsa-lib calculates the boundary value, too. The changed algorithm leads to a different boundary value used by alsa-lib, which makes, e.g., mplayer fail to play a 44.1 kHz file because the silence_size parameter is now invalid; bug report: <https://bugtrack.alsa-project.org/alsa-bug/view.php?id=5015>. This patch reverts the change to the boundary calculation, and instead fixes the hw_ptr_interrupt calculation to be period-aligned regardless of the boundary value. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Cc: <stable@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/core/pcm_lib.c9
-rw-r--r--sound/core/pcm_native.c39
2 files changed, 10 insertions, 38 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index a2ff86189d2a..22aff180dd1f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -439,8 +439,13 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
439 snd_pcm_playback_silence(substream, new_hw_ptr); 439 snd_pcm_playback_silence(substream, new_hw_ptr);
440 440
441 if (in_interrupt) { 441 if (in_interrupt) {
442 runtime->hw_ptr_interrupt = new_hw_ptr - 442 delta = new_hw_ptr - runtime->hw_ptr_interrupt;
443 (new_hw_ptr % runtime->period_size); 443 if (delta < 0)
444 delta += runtime->boundary;
445 delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
446 runtime->hw_ptr_interrupt += delta;
447 if (runtime->hw_ptr_interrupt >= runtime->boundary)
448 runtime->hw_ptr_interrupt -= runtime->boundary;
444 } 449 }
445 runtime->hw_ptr_base = hw_base; 450 runtime->hw_ptr_base = hw_base;
446 runtime->status->hw_ptr = new_hw_ptr; 451 runtime->status->hw_ptr = new_hw_ptr;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 644c2bb17b86..303ac04ff6e4 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -27,7 +27,6 @@
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>
31#include <sound/core.h> 30#include <sound/core.h>
32#include <sound/control.h> 31#include <sound/control.h>
33#include <sound/info.h> 32#include <sound/info.h>
@@ -370,38 +369,6 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
370 return usecs; 369 return usecs;
371} 370}
372 371
373static int calc_boundary(struct snd_pcm_runtime *runtime)
374{
375 u_int64_t boundary;
376
377 boundary = (u_int64_t)runtime->buffer_size *
378 (u_int64_t)runtime->period_size;
379#if BITS_PER_LONG < 64
380 /* try to find lowest common multiple for buffer and period */
381 if (boundary > LONG_MAX - runtime->buffer_size) {
382 u_int32_t remainder = -1;
383 u_int32_t divident = runtime->buffer_size;
384 u_int32_t divisor = runtime->period_size;
385 while (remainder) {
386 remainder = divident % divisor;
387 if (remainder) {
388 divident = divisor;
389 divisor = remainder;
390 }
391 }
392 boundary = div_u64(boundary, divisor);
393 if (boundary > LONG_MAX - runtime->buffer_size)
394 return -ERANGE;
395 }
396#endif
397 if (boundary == 0)
398 return -ERANGE;
399 runtime->boundary = boundary;
400 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
401 runtime->boundary *= 2;
402 return 0;
403}
404
405static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 372static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
406 struct snd_pcm_hw_params *params) 373 struct snd_pcm_hw_params *params)
407{ 374{
@@ -477,9 +444,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
477 runtime->stop_threshold = runtime->buffer_size; 444 runtime->stop_threshold = runtime->buffer_size;
478 runtime->silence_threshold = 0; 445 runtime->silence_threshold = 0;
479 runtime->silence_size = 0; 446 runtime->silence_size = 0;
480 err = calc_boundary(runtime); 447 runtime->boundary = runtime->buffer_size;
481 if (err < 0) 448 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
482 goto _error; 449 runtime->boundary *= 2;
483 450
484 snd_pcm_timer_resolution_change(substream); 451 snd_pcm_timer_resolution_change(substream);
485 runtime->status->state = SNDRV_PCM_STATE_SETUP; 452 runtime->status->state = SNDRV_PCM_STATE_SETUP;