ALSA: pcxhr: Fix a counter wrap
authorMarkus Bollinger <bollinger@digigram.com>
Wed, 20 Jun 2012 06:32:48 +0000 (08:32 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 20 Jun 2012 06:35:28 +0000 (08:35 +0200)
fix a counter wrap to avoid resynchronization of stream positions every several
minutes. The resynchronization may create stream position jitter

Signed-off-by: Markus Bollinger <bollinger@digigram.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/pcxhr/pcxhr_core.c

index 304411c1fe4bb6f78fc3160834eeaaf763ed0772..841703b5c52ad3b14dbeb0664326ac325ccabbae 100644 (file)
@@ -1133,13 +1133,12 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr,
        hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24;
        hw_sample_count += (u_int64_t)rmh.stat[1];
 
-       snd_printdd("stream %c%d : abs samples real(%ld) timer(%ld)\n",
+       snd_printdd("stream %c%d : abs samples real(%llu) timer(%llu)\n",
                    stream->pipe->is_capture ? 'C' : 'P',
                    stream->substream->number,
-                   (long unsigned int)hw_sample_count,
-                   (long unsigned int)(stream->timer_abs_periods +
-                                       stream->timer_period_frag +
-                                       mgr->granularity));
+                   hw_sample_count,
+                   stream->timer_abs_periods + stream->timer_period_frag +
+                                               mgr->granularity);
        return hw_sample_count;
 }
 
@@ -1243,10 +1242,18 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
 
                if ((dsp_time_diff < 0) &&
                    (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) {
-                       snd_printdd("ERROR DSP TIME old(%d) new(%d) -> "
-                                   "resynchronize all streams\n",
+                       /* handle dsp counter wraparound without resync */
+                       int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1;
+                       snd_printdd("WARNING DSP timestamp old(%d) new(%d)",
                                    mgr->dsp_time_last, dsp_time_new);
-                       mgr->dsp_time_err++;
+                       if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) {
+                               snd_printdd("-> timestamp wraparound OK: "
+                                           "diff=%d\n", tmp_diff);
+                               dsp_time_diff = tmp_diff;
+                       } else {
+                               snd_printdd("-> resynchronize all streams\n");
+                               mgr->dsp_time_err++;
+                       }
                }
 #ifdef CONFIG_SND_DEBUG_VERBOSE
                if (dsp_time_diff == 0)