diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 07fd630db88d..304025b23520 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -317,7 +317,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 e9d98be190c5..bcf95d3ff5c7 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) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 9cc1b5aa0148..1b8f6742b5fa 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; @@ -1047,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); @@ -1083,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 @@ -1096,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)