From b71207e9dc044b30d8b5d7f1c2290ba14563f05c Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Fri, 30 Oct 2009 11:51:24 +0100 Subject: [PATCH] ALSA: pcsp - Fix nforce workaround The attached patch fixes the problems introduced in this commit: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=eea0579fc85e64e9f05361d5aacf496fe7a151aa - Fix nForce workaround by honouring the pointer_update var - Revert "ns" to u64, as per the hrtimer API - Revert to the zero-delay timer startup, since I can't reproduce any problem with it (please, give me the hint!) Signed-off-by: Stas Sergeev Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp_lib.c | 65 +++++++++++++++++---------------- sound/drivers/pcsp/pcsp_mixer.c | 2 +- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c index 84cc2658c05b..e1145ac6e908 100644 --- a/sound/drivers/pcsp/pcsp_lib.c +++ b/sound/drivers/pcsp/pcsp_lib.c @@ -39,25 +39,20 @@ static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); /* write the port and returns the next expire time in ns; * called at the trigger-start and in hrtimer callback */ -static unsigned long pcsp_timer_update(struct hrtimer *handle) +static u64 pcsp_timer_update(struct snd_pcsp *chip) { unsigned char timer_cnt, val; u64 ns; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); unsigned long flags; if (chip->thalf) { outb(chip->val61, 0x61); chip->thalf = 0; - if (!atomic_read(&chip->timer_active)) - return 0; return chip->ns_rem; } - if (!atomic_read(&chip->timer_active)) - return 0; substream = chip->playback_substream; if (!substream) return 0; @@ -88,24 +83,17 @@ static unsigned long pcsp_timer_update(struct hrtimer *handle) return ns; } -enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) +static void pcsp_pointer_update(struct snd_pcsp *chip) { - struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); struct snd_pcm_substream *substream; - int periods_elapsed, pointer_update; size_t period_bytes, buffer_bytes; - unsigned long ns; + int periods_elapsed; unsigned long flags; - pointer_update = !chip->thalf; - ns = pcsp_timer_update(handle); - if (!ns) - return HRTIMER_NORESTART; - /* update the playback position */ substream = chip->playback_substream; if (!substream) - return HRTIMER_NORESTART; + return; period_bytes = snd_pcm_lib_period_bytes(substream); buffer_bytes = snd_pcm_lib_buffer_bytes(substream); @@ -134,6 +122,26 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) if (periods_elapsed) tasklet_schedule(&pcsp_pcm_tasklet); +} + +enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) +{ + struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer); + int pointer_update; + u64 ns; + + if (!atomic_read(&chip->timer_active) || !chip->playback_substream) + return HRTIMER_NORESTART; + + pointer_update = !chip->thalf; + ns = pcsp_timer_update(chip); + if (!ns) { + printk(KERN_WARNING "PCSP: unexpected stop\n"); + return HRTIMER_NORESTART; + } + + if (pointer_update) + pcsp_pointer_update(chip); hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns)); @@ -142,8 +150,6 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) static int pcsp_start_playing(struct snd_pcsp *chip) { - unsigned long ns; - #if PCSP_DEBUG printk(KERN_INFO "PCSP: start_playing called\n"); #endif @@ -159,11 +165,7 @@ static int pcsp_start_playing(struct snd_pcsp *chip) atomic_set(&chip->timer_active, 1); chip->thalf = 0; - ns = pcsp_timer_update(&pcsp_chip.timer); - if (!ns) - return -EIO; - - hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL); + hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL); return 0; } @@ -232,21 +234,22 @@ static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream) static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) { struct snd_pcsp *chip = snd_pcm_substream_chip(substream); + pcsp_sync_stop(chip); + chip->playback_ptr = 0; + chip->period_ptr = 0; + chip->fmt_size = + snd_pcm_format_physical_width(substream->runtime->format) >> 3; + chip->is_signed = snd_pcm_format_signed(substream->runtime->format); #if PCSP_DEBUG printk(KERN_INFO "PCSP: prepare called, " - "size=%zi psize=%zi f=%zi f1=%i\n", + "size=%zi psize=%zi f=%zi f1=%i fsize=%i\n", snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream) / snd_pcm_lib_period_bytes(substream), - substream->runtime->periods); + substream->runtime->periods, + chip->fmt_size); #endif - pcsp_sync_stop(chip); - chip->playback_ptr = 0; - chip->period_ptr = 0; - chip->fmt_size = - snd_pcm_format_physical_width(substream->runtime->format) >> 3; - chip->is_signed = snd_pcm_format_signed(substream->runtime->format); return 0; } diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 199b03377142..903bc846763f 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -72,7 +72,7 @@ static int pcsp_treble_put(struct snd_kcontrol *kcontrol, if (treble != chip->treble) { chip->treble = treble; #if PCSP_DEBUG - printk(KERN_INFO "PCSP: rate set to %i\n", PCSP_RATE()); + printk(KERN_INFO "PCSP: rate set to %li\n", PCSP_RATE()); #endif changed = 1; } -- 2.20.1