From 8fc6d4186e0a60b3755a6b88bf67a3ac3214dcc3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 2 Jun 2010 13:29:17 +0200 Subject: ALSA: hda-intel - fix wallclk variable update and condition This patch fixes thinko introduced in "last minutes" before commiting of the last wallclk patch. It also fixes the condition checking if the first period after last wallclk update is processed. There is a little rounding error in period_wallclk. Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dc79564..af701a8 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (WARN_ONCE(!azx_dev->period_bytes, "hda-intel: zero azx_dev->period_bytes")) return -1; /* this shouldn't happen! */ - if (wallclk <= azx_dev->period_wallclk && + if (wallclk < (azx_dev->period_wallclk * 5) / 4 && pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) /* NG - it's below the first next period boundary */ return bdl_pos_adj[chip->dev_index] ? 0 : -1; - azx_dev->start_wallclk = wallclk; + azx_dev->start_wallclk += wallclk; return 1; /* OK, it's fine */ } -- cgit v0.10.2 From 5daeba34d2aab669aea07abee13d53cd116578fb Mon Sep 17 00:00:00 2001 From: David Dillow Date: Sun, 27 Jun 2010 00:13:20 +0200 Subject: ALSA: pcm_lib: avoid timing jitter in snd_pcm_read/write() When using poll() to wait for the next period -- or avail_min samples -- one gets a consistent delay for each system call that is usually just a little short of the selected period time. However, When using snd_pcm_read/write(), one gets a jittery delay that alternates between less than a millisecond and approximately two period times. This is caused by snd_pcm_lib_{read,write}1() transferring any available samples to the user's buffer and adjusting the application pointer prior to sleeping to the end of the current period. When the next period interrupt occurs, there is then less than avail_min samples remaining to be transferred in the period, so we end up sleeping until a second period occurs. This is solved by using runtime->twake as the number of samples needed for a wakeup in addition to selecting the proper wait queue to wake in snd_pcm_update_state(). This requires twake to be non-zero when used by snd_pcm_lib_{read,write}1() even if avail_min is zero. Signed-off-by: Dave Dillow Signed-off-by: Jaroslav Kysela diff --git a/include/sound/pcm.h b/include/sound/pcm.h index dd76cde..83c6fa6 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -313,7 +313,7 @@ struct snd_pcm_runtime { struct snd_pcm_mmap_control *control; /* -- locking / scheduling -- */ - unsigned int twake: 1; /* do transfer (!poll) wakeup */ + snd_pcm_uframes_t twake; /* do transfer (!poll) wakeup if non-zero */ wait_queue_head_t sleep; /* poll sleep */ wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index e9d98be..bcf95d3 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -287,8 +287,11 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, return -EPIPE; } } - if (avail >= runtime->control->avail_min) - wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); + if (runtime->twake) { + if (avail >= runtime->twake) + wake_up(&runtime->tsleep); + } else if (avail >= runtime->control->avail_min) + wake_up(&runtime->sleep); return 0; } @@ -1707,7 +1710,7 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed); * The available space is stored on availp. When err = 0 and avail = 0 * on the capture stream, it indicates the stream is in DRAINING state. */ -static int wait_for_avail_min(struct snd_pcm_substream *substream, +static int wait_for_avail(struct snd_pcm_substream *substream, snd_pcm_uframes_t *availp) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -1757,7 +1760,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, avail = snd_pcm_playback_avail(runtime); else avail = snd_pcm_capture_avail(runtime); - if (avail >= runtime->control->avail_min) + if (avail >= runtime->twake) break; } _endloop: @@ -1820,7 +1823,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->twake = runtime->control->avail_min ? : 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -1833,7 +1836,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, err = -EAGAIN; goto _end_unlock; } - err = wait_for_avail_min(substream, &avail); + runtime->twake = min_t(snd_pcm_uframes_t, size, + runtime->control->avail_min ? : 1); + err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock; } @@ -2042,7 +2047,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, goto _end_unlock; } - runtime->twake = 1; + runtime->twake = runtime->control->avail_min ? : 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t avail; @@ -2060,7 +2065,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, err = -EAGAIN; goto _end_unlock; } - err = wait_for_avail_min(substream, &avail); + runtime->twake = min_t(snd_pcm_uframes_t, size, + runtime->control->avail_min ? : 1); + err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock; if (!avail) -- cgit v0.10.2 From 3a3d5fd125f82200019ef406c4d51ba4d9f0a604 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Sun, 27 Jun 2010 00:04:32 +0200 Subject: sis7019: fix capture issues with multiple periods per buffer When using a timing voice to clock out periods during capture, the driver would slowly loose synchronization and never catch up, eventually reaching a point where it no longer generated interrupts. To avoid this situation, the virtual period clocking was changed to shorten the next timing period when our timing voice falls too far behind the capture voice. In addition, the first virtual period for the timing voice was slightly too short, causing the timing voice to initially be ahead of the capture voice. While tracking down this problem, I noticed that the expected sample offset was being incorrectly initialized, causing an overrun to be incorrectly reported when the timing voice happened to be perfectly synchronized. Reported-by: Hans Schou Signed-off-by: Dave Dillow Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 9cc1b5a..614ff6e 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -264,11 +264,13 @@ static void sis_update_voice(struct voice *voice) * if using small periods. * * If we're less than 9 samples behind, we're on target. + * Otherwise, shorten the next vperiod by the amount we've + * been delayed. */ if (sync > -9) voice->vperiod = voice->sync_period_size + 1; else - voice->vperiod = voice->sync_period_size - 4; + voice->vperiod = voice->sync_period_size + sync + 10; if (voice->vperiod < voice->buffer_size) { sis_update_sso(voice, voice->vperiod); @@ -736,7 +738,7 @@ static void sis_prepare_timing_voice(struct voice *voice, period_size = buffer_size; /* Initially, we want to interrupt just a bit behind the end of - * the period we're clocking out. 10 samples seems to give a good + * the period we're clocking out. 12 samples seems to give a good * delay. * * We want to spread our interrupts throughout the virtual period, @@ -747,7 +749,7 @@ static void sis_prepare_timing_voice(struct voice *voice, * * This is all moot if we don't need to use virtual periods. */ - vperiod = runtime->period_size + 10; + vperiod = runtime->period_size + 12; if (vperiod > period_size) { u16 tail = vperiod % period_size; u16 quarter_period = period_size / 4; @@ -776,7 +778,7 @@ static void sis_prepare_timing_voice(struct voice *voice, */ timing->flags |= VOICE_SYNC_TIMING; timing->sync_base = voice->ctrl_base; - timing->sync_cso = runtime->period_size - 1; + timing->sync_cso = runtime->period_size; timing->sync_period_size = runtime->period_size; timing->sync_buffer_size = runtime->buffer_size; timing->period_size = period_size; -- cgit v0.10.2 From 08b450988905505d12f7671bc24b8da73631d327 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Sun, 27 Jun 2010 00:07:57 +0200 Subject: sis7019: increase reset delays A few boards using this controller are reported to need a little extra time during their reset cycle. Reported-by: Michael Goeke Signed-off-by: Dave Dillow Signed-off-by: Jaroslav Kysela diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 614ff6e..1b8f674 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -1049,7 +1049,7 @@ static int sis_chip_free(struct sis7019 *sis) /* Reset the chip, and disable all interrputs. */ outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); - udelay(10); + udelay(25); outl(0, sis->ioport + SIS_GCR); outl(0, sis->ioport + SIS_GIER); @@ -1085,7 +1085,7 @@ static int sis_chip_init(struct sis7019 *sis) /* Reset the audio controller */ outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); - udelay(10); + udelay(25); outl(0, io + SIS_GCR); /* Get the AC-link semaphore, and reset the codecs @@ -1098,7 +1098,7 @@ static int sis_chip_init(struct sis7019 *sis) return -EIO; outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); - udelay(10); + udelay(250); count = 0xffff; while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) -- cgit v0.10.2