[alsa-devel] [PATCH] ALSA: snd_usb_caiaq: track submitted output urbs
Takashi Iwai
tiwai at suse.de
Sun Aug 14 18:12:07 CEST 2011
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 <zonque at gmail.com>
> Reported-and-tested-by: Matej Laitl <matej at laitl.cz>
> Cc: Sarah Sharp <sarah.a.sharp at linux.intel.com>
> Cc: stable at 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
>
More information about the Alsa-devel
mailing list