aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-12-27 12:19:57 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-28 06:29:46 -0500
commitadc8d31326c32a2a1e145ab80accbc3c6570b117 (patch)
tree3ffd8362dc56b49bce34f6bcb3196c9d75f7515d /sound/usb
parent7d2b451e65d255427c108e990507964ac39c13ee (diff)
ALSA: usb-audio: make buffer pointer based on bytes instead on frames
Since there are devices that do not align the size of their data packets to frame boundaries, the driver needs to be able to keep track of partial frames. This patch prepares for support for such devices by changing the hwptr_done variable from a frame counter to a byte counter. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usbaudio.c76
1 files changed, 37 insertions, 39 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 286fa14e48bd..8fcb5d5a94b6 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -173,7 +173,7 @@ struct snd_usb_substream {
173 173
174 unsigned int running: 1; /* running status */ 174 unsigned int running: 1; /* running status */
175 175
176 unsigned int hwptr_done; /* processed frame position in the buffer */ 176 unsigned int hwptr_done; /* processed byte position in the buffer */
177 unsigned int transfer_done; /* processed frames since last period update */ 177 unsigned int transfer_done; /* processed frames since last period update */
178 unsigned long active_mask; /* bitmask of active urbs */ 178 unsigned long active_mask; /* bitmask of active urbs */
179 unsigned long unlink_mask; /* bitmask of unlinked urbs */ 179 unsigned long unlink_mask; /* bitmask of unlinked urbs */
@@ -342,7 +342,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
342 unsigned long flags; 342 unsigned long flags;
343 unsigned char *cp; 343 unsigned char *cp;
344 int i; 344 int i;
345 unsigned int stride, len, oldptr; 345 unsigned int stride, frames, bytes, oldptr;
346 int period_elapsed = 0; 346 int period_elapsed = 0;
347 347
348 stride = runtime->frame_bits >> 3; 348 stride = runtime->frame_bits >> 3;
@@ -353,29 +353,28 @@ static int retire_capture_urb(struct snd_usb_substream *subs,
353 snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); 353 snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
354 // continue; 354 // continue;
355 } 355 }
356 len = urb->iso_frame_desc[i].actual_length / stride; 356 frames = urb->iso_frame_desc[i].actual_length / stride;
357 if (! len) 357 bytes = frames * stride;
358 continue;
359 /* update the current pointer */ 358 /* update the current pointer */
360 spin_lock_irqsave(&subs->lock, flags); 359 spin_lock_irqsave(&subs->lock, flags);
361 oldptr = subs->hwptr_done; 360 oldptr = subs->hwptr_done;
362 subs->hwptr_done += len; 361 subs->hwptr_done += bytes;
363 if (subs->hwptr_done >= runtime->buffer_size) 362 if (subs->hwptr_done >= runtime->buffer_size * stride)
364 subs->hwptr_done -= runtime->buffer_size; 363 subs->hwptr_done -= runtime->buffer_size * stride;
365 subs->transfer_done += len; 364 subs->transfer_done += frames;
366 if (subs->transfer_done >= runtime->period_size) { 365 if (subs->transfer_done >= runtime->period_size) {
367 subs->transfer_done -= runtime->period_size; 366 subs->transfer_done -= runtime->period_size;
368 period_elapsed = 1; 367 period_elapsed = 1;
369 } 368 }
370 spin_unlock_irqrestore(&subs->lock, flags); 369 spin_unlock_irqrestore(&subs->lock, flags);
371 /* copy a data chunk */ 370 /* copy a data chunk */
372 if (oldptr + len > runtime->buffer_size) { 371 if (oldptr + bytes > runtime->buffer_size * stride) {
373 unsigned int cnt = runtime->buffer_size - oldptr; 372 unsigned int bytes1 =
374 unsigned int blen = cnt * stride; 373 runtime->buffer_size * stride - oldptr;
375 memcpy(runtime->dma_area + oldptr * stride, cp, blen); 374 memcpy(runtime->dma_area + oldptr, cp, bytes1);
376 memcpy(runtime->dma_area, cp + blen, len * stride - blen); 375 memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
377 } else { 376 } else {
378 memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); 377 memcpy(runtime->dma_area + oldptr, cp, bytes);
379 } 378 }
380 } 379 }
381 if (period_elapsed) 380 if (period_elapsed)
@@ -562,24 +561,24 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
562 struct snd_pcm_runtime *runtime, 561 struct snd_pcm_runtime *runtime,
563 struct urb *urb) 562 struct urb *urb)
564{ 563{
565 int i, stride, offs; 564 int i, stride;
566 unsigned int counts; 565 unsigned int counts, frames, bytes;
567 unsigned long flags; 566 unsigned long flags;
568 int period_elapsed = 0; 567 int period_elapsed = 0;
569 struct snd_urb_ctx *ctx = urb->context; 568 struct snd_urb_ctx *ctx = urb->context;
570 569
571 stride = runtime->frame_bits >> 3; 570 stride = runtime->frame_bits >> 3;
572 571
573 offs = 0; 572 frames = 0;
574 urb->dev = ctx->subs->dev; /* we need to set this at each time */ 573 urb->dev = ctx->subs->dev; /* we need to set this at each time */
575 urb->number_of_packets = 0; 574 urb->number_of_packets = 0;
576 spin_lock_irqsave(&subs->lock, flags); 575 spin_lock_irqsave(&subs->lock, flags);
577 for (i = 0; i < ctx->packets; i++) { 576 for (i = 0; i < ctx->packets; i++) {
578 counts = snd_usb_audio_next_packet_size(subs); 577 counts = snd_usb_audio_next_packet_size(subs);
579 /* set up descriptor */ 578 /* set up descriptor */
580 urb->iso_frame_desc[i].offset = offs * stride; 579 urb->iso_frame_desc[i].offset = frames * stride;
581 urb->iso_frame_desc[i].length = counts * stride; 580 urb->iso_frame_desc[i].length = counts * stride;
582 offs += counts; 581 frames += counts;
583 urb->number_of_packets++; 582 urb->number_of_packets++;
584 subs->transfer_done += counts; 583 subs->transfer_done += counts;
585 if (subs->transfer_done >= runtime->period_size) { 584 if (subs->transfer_done >= runtime->period_size) {
@@ -589,7 +588,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
589 if (subs->transfer_done > 0) { 588 if (subs->transfer_done > 0) {
590 /* FIXME: fill-max mode is not 589 /* FIXME: fill-max mode is not
591 * supported yet */ 590 * supported yet */
592 offs -= subs->transfer_done; 591 frames -= subs->transfer_done;
593 counts -= subs->transfer_done; 592 counts -= subs->transfer_done;
594 urb->iso_frame_desc[i].length = 593 urb->iso_frame_desc[i].length =
595 counts * stride; 594 counts * stride;
@@ -599,7 +598,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
599 if (i < ctx->packets) { 598 if (i < ctx->packets) {
600 /* add a transfer delimiter */ 599 /* add a transfer delimiter */
601 urb->iso_frame_desc[i].offset = 600 urb->iso_frame_desc[i].offset =
602 offs * stride; 601 frames * stride;
603 urb->iso_frame_desc[i].length = 0; 602 urb->iso_frame_desc[i].length = 0;
604 urb->number_of_packets++; 603 urb->number_of_packets++;
605 } 604 }
@@ -609,26 +608,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
609 if (period_elapsed) /* finish at the period boundary */ 608 if (period_elapsed) /* finish at the period boundary */
610 break; 609 break;
611 } 610 }
612 if (subs->hwptr_done + offs > runtime->buffer_size) { 611 bytes = frames * stride;
612 if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
613 /* err, the transferred area goes over buffer boundary. */ 613 /* err, the transferred area goes over buffer boundary. */
614 unsigned int len = runtime->buffer_size - subs->hwptr_done; 614 unsigned int bytes1 =
615 runtime->buffer_size * stride - subs->hwptr_done;
615 memcpy(urb->transfer_buffer, 616 memcpy(urb->transfer_buffer,
616 runtime->dma_area + subs->hwptr_done * stride, 617 runtime->dma_area + subs->hwptr_done, bytes1);
617 len * stride); 618 memcpy(urb->transfer_buffer + bytes1,
618 memcpy(urb->transfer_buffer + len * stride, 619 runtime->dma_area, bytes - bytes1);
619 runtime->dma_area,
620 (offs - len) * stride);
621 } else { 620 } else {
622 memcpy(urb->transfer_buffer, 621 memcpy(urb->transfer_buffer,
623 runtime->dma_area + subs->hwptr_done * stride, 622 runtime->dma_area + subs->hwptr_done, bytes);
624 offs * stride);
625 } 623 }
626 subs->hwptr_done += offs; 624 subs->hwptr_done += bytes;
627 if (subs->hwptr_done >= runtime->buffer_size) 625 if (subs->hwptr_done >= runtime->buffer_size * stride)
628 subs->hwptr_done -= runtime->buffer_size; 626 subs->hwptr_done -= runtime->buffer_size * stride;
629 runtime->delay += offs; 627 runtime->delay += frames;
630 spin_unlock_irqrestore(&subs->lock, flags); 628 spin_unlock_irqrestore(&subs->lock, flags);
631 urb->transfer_buffer_length = offs * stride; 629 urb->transfer_buffer_length = bytes;
632 if (period_elapsed) 630 if (period_elapsed)
633 snd_pcm_period_elapsed(subs->pcm_substream); 631 snd_pcm_period_elapsed(subs->pcm_substream);
634 return 0; 632 return 0;
@@ -901,18 +899,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
901 899
902 900
903/* 901/*
904 * return the current pcm pointer. just return the hwptr_done value. 902 * return the current pcm pointer. just based on the hwptr_done value.
905 */ 903 */
906static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) 904static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream)
907{ 905{
908 struct snd_usb_substream *subs; 906 struct snd_usb_substream *subs;
909 snd_pcm_uframes_t hwptr_done; 907 unsigned int hwptr_done;
910 908
911 subs = (struct snd_usb_substream *)substream->runtime->private_data; 909 subs = (struct snd_usb_substream *)substream->runtime->private_data;
912 spin_lock(&subs->lock); 910 spin_lock(&subs->lock);
913 hwptr_done = subs->hwptr_done; 911 hwptr_done = subs->hwptr_done;
914 spin_unlock(&subs->lock); 912 spin_unlock(&subs->lock);
915 return hwptr_done; 913 return hwptr_done / (substream->runtime->frame_bits >> 3);
916} 914}
917 915
918 916