aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Mack <zonque@gmail.com>2012-08-30 12:52:30 -0400
committerTakashi Iwai <tiwai@suse.de>2012-08-31 15:03:48 -0400
commit245baf983cc39524cce39c24d01b276e6e653c9e (patch)
tree2fbd88aebcbbe95b60a6ae62d946a840ae1ff28b
parentfbcfbf5f673847657ccd98afb4d8e13af7fdc372 (diff)
ALSA: snd-usb: fix calls to next_packet_size
In order to support devices with implicit feedback streaming models, packet sizes are now stored with each individual urb, and the PCM handling code which fills the buffers purely relies on the size fields now. However, calling snd_usb_audio_next_packet_size() for all possible packets in an URB at once, prior to letting the PCM code do its job does in fact not lead to the same behaviour than what the old code did: The PCM code will break its loop once a period boundary is reached, consequently using up less packets that it really could. As snd_usb_audio_next_packet_size() implements a feedback mechanism to the endpoints phase accumulator, the number of calls to that function matters, and when called too often, the data rate runs out of bounds. Fix this by making the next_packet function public, and call it from the PCM code as before if the packet data sizes are not defined. Signed-off-by: Daniel Mack <zonque@gmail.com> Cc: stable@kernel.org [v3.5+] Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/usb/endpoint.c13
-rw-r--r--sound/usb/endpoint.h1
-rw-r--r--sound/usb/pcm.c7
3 files changed, 8 insertions, 13 deletions
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index b896c5559524..d6e2bb49c59c 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -141,7 +141,7 @@ int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
141 * 141 *
142 * For implicit feedback, next_packet_size() is unused. 142 * For implicit feedback, next_packet_size() is unused.
143 */ 143 */
144static int next_packet_size(struct snd_usb_endpoint *ep) 144int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep)
145{ 145{
146 unsigned long flags; 146 unsigned long flags;
147 int ret; 147 int ret;
@@ -177,15 +177,6 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep,
177 ep->retire_data_urb(ep->data_subs, urb); 177 ep->retire_data_urb(ep->data_subs, urb);
178} 178}
179 179
180static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
181 struct snd_urb_ctx *ctx)
182{
183 int i;
184
185 for (i = 0; i < ctx->packets; ++i)
186 ctx->packet_size[i] = next_packet_size(ep);
187}
188
189/* 180/*
190 * Prepare a PLAYBACK urb for submission to the bus. 181 * Prepare a PLAYBACK urb for submission to the bus.
191 */ 182 */
@@ -370,7 +361,6 @@ static void snd_complete_urb(struct urb *urb)
370 goto exit_clear; 361 goto exit_clear;
371 } 362 }
372 363
373 prepare_outbound_urb_sizes(ep, ctx);
374 prepare_outbound_urb(ep, ctx); 364 prepare_outbound_urb(ep, ctx);
375 } else { 365 } else {
376 retire_inbound_urb(ep, ctx); 366 retire_inbound_urb(ep, ctx);
@@ -857,7 +847,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
857 goto __error; 847 goto __error;
858 848
859 if (usb_pipeout(ep->pipe)) { 849 if (usb_pipeout(ep->pipe)) {
860 prepare_outbound_urb_sizes(ep, urb->context);
861 prepare_outbound_urb(ep, urb->context); 850 prepare_outbound_urb(ep, urb->context);
862 } else { 851 } else {
863 prepare_inbound_urb(ep, urb->context); 852 prepare_inbound_urb(ep, urb->context);
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index a8e60c1408e5..cbbbdf226d66 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -21,6 +21,7 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
21void snd_usb_endpoint_free(struct list_head *head); 21void snd_usb_endpoint_free(struct list_head *head);
22 22
23int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep); 23int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
24int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
24 25
25void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, 26void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
26 struct snd_usb_endpoint *sender, 27 struct snd_usb_endpoint *sender,
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 5ceb8f1d63fb..e80b6687f43a 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1029,6 +1029,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
1029 struct urb *urb) 1029 struct urb *urb)
1030{ 1030{
1031 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 1031 struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
1032 struct snd_usb_endpoint *ep = subs->data_endpoint;
1032 struct snd_urb_ctx *ctx = urb->context; 1033 struct snd_urb_ctx *ctx = urb->context;
1033 unsigned int counts, frames, bytes; 1034 unsigned int counts, frames, bytes;
1034 int i, stride, period_elapsed = 0; 1035 int i, stride, period_elapsed = 0;
@@ -1040,7 +1041,11 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
1040 urb->number_of_packets = 0; 1041 urb->number_of_packets = 0;
1041 spin_lock_irqsave(&subs->lock, flags); 1042 spin_lock_irqsave(&subs->lock, flags);
1042 for (i = 0; i < ctx->packets; i++) { 1043 for (i = 0; i < ctx->packets; i++) {
1043 counts = ctx->packet_size[i]; 1044 if (ctx->packet_size[i])
1045 counts = ctx->packet_size[i];
1046 else
1047 counts = snd_usb_endpoint_next_packet_size(ep);
1048
1044 /* set up descriptor */ 1049 /* set up descriptor */
1045 urb->iso_frame_desc[i].offset = frames * stride; 1050 urb->iso_frame_desc[i].offset = frames * stride;
1046 urb->iso_frame_desc[i].length = counts * stride; 1051 urb->iso_frame_desc[i].length = counts * stride;