At Sun, 14 Aug 2011 11:31:16 +0200, Daniel Mack wrote: > > The snd_usb_caiaq driver currently assumes that output urbs are serviced > in time and doesn't track when and whether they are given back by the > USB core. That usually works fine, but due to temporary limitations of > the XHCI stack, we faced that urbs were submitted more than once with > this approach. > > As it's no good practice to fire and forget urbs anyway, this patch > introduces a proper bit mask to track which requests have been submitted > and given back. > > That alone however doesn't make the driver work in case the host > controller is broken and doesn't give back urbs at all, and the output > stream will stop once all pre-allocated output urbs are consumed. But > it does prevent crashes of the controller stack in such cases. > > See http://bugzilla.kernel.org/show_bug.cgi?id=40702 for more details. > > Signed-off-by: Daniel Mack <zon...@gmail.com> > Reported-and-tested-by: Matej Laitl <ma...@laitl.cz> > Cc: Sarah Sharp <sarah.a.sh...@linux.intel.com> > Cc: sta...@kernel.org
Applied now. Thanks. Takashi > --- > sound/usb/caiaq/audio.c | 31 +++++++++++++++++++++++++++---- > sound/usb/caiaq/device.h | 1 + > 2 files changed, 28 insertions(+), 4 deletions(-) > > diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c > index aa52b3e..2cf87f5 100644 > --- a/sound/usb/caiaq/audio.c > +++ b/sound/usb/caiaq/audio.c > @@ -139,8 +139,12 @@ static void stream_stop(struct snd_usb_caiaqdev *dev) > > for (i = 0; i < N_URBS; i++) { > usb_kill_urb(dev->data_urbs_in[i]); > - usb_kill_urb(dev->data_urbs_out[i]); > + > + if (test_bit(i, &dev->outurb_active_mask)) > + usb_kill_urb(dev->data_urbs_out[i]); > } > + > + dev->outurb_active_mask = 0; > } > > static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) > @@ -612,8 +616,8 @@ static void read_completed(struct urb *urb) > { > struct snd_usb_caiaq_cb_info *info = urb->context; > struct snd_usb_caiaqdev *dev; > - struct urb *out; > - int frame, len, send_it = 0, outframe = 0; > + struct urb *out = NULL; > + int i, frame, len, send_it = 0, outframe = 0; > size_t offset = 0; > > if (urb->status || !info) > @@ -624,7 +628,17 @@ static void read_completed(struct urb *urb) > if (!dev->streaming) > return; > > - out = dev->data_urbs_out[info->index]; > + /* find an unused output urb that is unused */ > + for (i = 0; i < N_URBS; i++) > + if (test_and_set_bit(i, &dev->outurb_active_mask) == 0) { > + out = dev->data_urbs_out[i]; > + break; > + } > + > + if (!out) { > + log("Unable to find an output urb to use\n"); > + goto requeue; > + } > > /* read the recently received packet and send back one which has > * the same layout */ > @@ -655,8 +669,12 @@ static void read_completed(struct urb *urb) > out->number_of_packets = outframe; > out->transfer_flags = URB_ISO_ASAP; > usb_submit_urb(out, GFP_ATOMIC); > + } else { > + struct snd_usb_caiaq_cb_info *oinfo = out->context; > + clear_bit(oinfo->index, &dev->outurb_active_mask); > } > > +requeue: > /* re-submit inbound urb */ > for (frame = 0; frame < FRAMES_PER_URB; frame++) { > urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; > @@ -678,6 +696,8 @@ static void write_completed(struct urb *urb) > dev->output_running = 1; > wake_up(&dev->prepare_wait_queue); > } > + > + clear_bit(info->index, &dev->outurb_active_mask); > } > > static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int > *ret) > @@ -829,6 +849,9 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) > if (!dev->data_cb_info) > return -ENOMEM; > > + dev->outurb_active_mask = 0; > + BUILD_BUG_ON(N_URBS > (sizeof(dev->outurb_active_mask) * 8)); > + > for (i = 0; i < N_URBS; i++) { > dev->data_cb_info[i].dev = dev; > dev->data_cb_info[i].index = i; > diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h > index b2b3101..3f9c633 100644 > --- a/sound/usb/caiaq/device.h > +++ b/sound/usb/caiaq/device.h > @@ -96,6 +96,7 @@ struct snd_usb_caiaqdev { > int input_panic, output_panic, warned; > char *audio_in_buf, *audio_out_buf; > unsigned int samplerates, bpp; > + unsigned long outurb_active_mask; > > struct snd_pcm_substream *sub_playback[MAX_STREAMS]; > struct snd_pcm_substream *sub_capture[MAX_STREAMS]; > -- > 1.7.6 > _______________________________________________ stable mailing list stable@linux.kernel.org http://linux.kernel.org/mailman/listinfo/stable