Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / sound / usb / pcm.c
index d82e378..f94397b 100644 (file)
@@ -59,7 +59,12 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
 
        /* Approximation based on number of samples per USB frame (ms),
           some truncation for 44.1 but the estimate is good enough */
-       est_delay =  subs->last_delay - (frame_diff * rate / 1000);
+       est_delay =  frame_diff * rate / 1000;
+       if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+               est_delay = subs->last_delay - est_delay;
+       else
+               est_delay = subs->last_delay + est_delay;
+
        if (est_delay < 0)
                est_delay = 0;
        return est_delay;
@@ -78,8 +83,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
                return SNDRV_PCM_POS_XRUN;
        spin_lock(&subs->lock);
        hwptr_done = subs->hwptr_done;
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               substream->runtime->delay = snd_usb_pcm_delay(subs,
+       substream->runtime->delay = snd_usb_pcm_delay(subs,
                                                substream->runtime->rate);
        spin_unlock(&subs->lock);
        return hwptr_done / (substream->runtime->frame_bits >> 3);
@@ -363,6 +367,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
        switch (subs->stream->chip->usb_id) {
        case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
+       case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
                if (is_playback) {
                        implicit_fb = 1;
                        ep = 0x81;
@@ -1157,6 +1162,10 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
        int i, period_elapsed = 0;
        unsigned long flags;
        unsigned char *cp;
+       int current_frame_number;
+
+       /* read frame number here, update pointer in critical section */
+       current_frame_number = usb_get_current_frame_number(subs->dev);
 
        stride = runtime->frame_bits >> 3;
 
@@ -1171,9 +1180,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
                if (!subs->txfr_quirk)
                        bytes = frames * stride;
                if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
                        int oldbytes = bytes;
-#endif
                        bytes = frames * stride;
                        snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
                                                        oldbytes, bytes);
@@ -1190,6 +1197,15 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
                        subs->transfer_done -= runtime->period_size;
                        period_elapsed = 1;
                }
+               /* capture delay is by construction limited to one URB,
+                * reset delays here
+                */
+               runtime->delay = subs->last_delay = 0;
+
+               /* realign last_frame_number */
+               subs->last_frame_number = current_frame_number;
+               subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
+
                spin_unlock_irqrestore(&subs->lock, flags);
                /* copy a data chunk */
                if (oldptr + bytes > runtime->buffer_size * stride) {