Browse Source

Merge branch 'fix/pcm-jiffies-check' into for-linus

* fix/pcm-jiffies-check:
  ALSA: Enable PCM hw_ptr_jiffies check only in xrun_debug mode
  ALSA: Fix invalid jiffies check after pause
Takashi Iwai 16 years ago
parent
commit
f5219b6195
3 changed files with 19 additions and 2 deletions
  1. 5 0
      Documentation/sound/alsa/Procfile.txt
  2. 8 2
      sound/core/pcm_lib.c
  3. 6 0
      sound/core/pcm_native.c

+ 5 - 0
Documentation/sound/alsa/Procfile.txt

@@ -104,6 +104,11 @@ card*/pcm*/xrun_debug
 	When this value is greater than 1, the driver will show the
 	When this value is greater than 1, the driver will show the
 	stack trace additionally.  This may help the debugging.
 	stack trace additionally.  This may help the debugging.
 
 
+	Since 2.6.30, this option also enables the hwptr check using
+	jiffies.  This detects spontaneous invalid pointer callback
+	values, but can be lead to too much corrections for a (mostly
+	buggy) hardware that doesn't give smooth pointer updates.
+
 card*/pcm*/sub*/info
 card*/pcm*/sub*/info
 	The general information of this PCM sub-stream.
 	The general information of this PCM sub-stream.
 
 

+ 8 - 2
sound/core/pcm_lib.c

@@ -249,6 +249,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
 			new_hw_ptr = hw_base + pos;
 			new_hw_ptr = hw_base + pos;
 		}
 		}
 	}
 	}
+
+	/* Do jiffies check only in xrun_debug mode */
+	if (!xrun_debug(substream))
+		goto no_jiffies_check;
+
 	/* Skip the jiffies check for hardwares with BATCH flag.
 	/* Skip the jiffies check for hardwares with BATCH flag.
 	 * Such hardware usually just increases the position at each IRQ,
 	 * Such hardware usually just increases the position at each IRQ,
 	 * thus it can't give any strange position.
 	 * thus it can't give any strange position.
@@ -336,7 +341,9 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
 			hw_base = 0;
 			hw_base = 0;
 		new_hw_ptr = hw_base + pos;
 		new_hw_ptr = hw_base + pos;
 	}
 	}
-	if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
+	/* Do jiffies check only in xrun_debug mode */
+	if (xrun_debug(substream) &&
+	    ((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
 		hw_ptr_error(substream,
 		hw_ptr_error(substream,
 			     "hw_ptr skipping! "
 			     "hw_ptr skipping! "
 			     "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
 			     "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
@@ -1478,7 +1485,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
 		runtime->status->hw_ptr %= runtime->buffer_size;
 		runtime->status->hw_ptr %= runtime->buffer_size;
 	else
 	else
 		runtime->status->hw_ptr = 0;
 		runtime->status->hw_ptr = 0;
-	runtime->hw_ptr_jiffies = jiffies;
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 	return 0;
 	return 0;
 }
 }

+ 6 - 0
sound/core/pcm_native.c

@@ -848,6 +848,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
 {
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_trigger_tstamp(substream);
 	snd_pcm_trigger_tstamp(substream);
+	runtime->hw_ptr_jiffies = jiffies;
 	runtime->status->state = state;
 	runtime->status->state = state;
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
 	    runtime->silence_size > 0)
@@ -961,6 +962,11 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
 {
 {
 	if (substream->runtime->trigger_master != substream)
 	if (substream->runtime->trigger_master != substream)
 		return 0;
 		return 0;
+	/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
+	 * a delta betwen the current jiffies, this gives a large enough
+	 * delta, effectively to skip the check once.
+	 */
+	substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
 	return substream->ops->trigger(substream,
 	return substream->ops->trigger(substream,
 				       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
 				       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
 					      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
 					      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);