Skip to content

Commit

Permalink
ALSA: usb-audio: Fix crash at re-preparing the PCM stream
Browse files Browse the repository at this point in the history
There are bug reports of a crash with USB-audio devices when PCM
prepare is performed immediately after the stream is stopped via
trigger callback.  It turned out that the problem is that we don't
wait until all URBs are killed.

This patch adds a new function to synchronize the pending stop
operation on an endpoint, and calls in the prepare callback for
avoiding the crash above.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=49181

Reported-and-tested-by: Artem S. Tashkinov <[email protected]>
Cc: <[email protected]> [v3.6]
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
tiwai committed Nov 8, 2012
1 parent d1a3c98 commit f58161b
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 0 deletions.
13 changes: 13 additions & 0 deletions sound/usb/endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#define EP_FLAG_ACTIVATED 0
#define EP_FLAG_RUNNING 1
#define EP_FLAG_STOPPING 2

/*
* snd_usb_endpoint is a model that abstracts everything related to an
Expand Down Expand Up @@ -502,10 +503,20 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
alive, ep->ep_num);
clear_bit(EP_FLAG_STOPPING, &ep->flags);

return 0;
}

/* sync the pending stop operation;
* this function itself doesn't trigger the stop operation
*/
void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
{
if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags))
wait_clear_urbs(ep);
}

/*
* unlink active urbs.
*/
Expand Down Expand Up @@ -918,6 +929,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,

if (wait)
wait_clear_urbs(ep);
else
set_bit(EP_FLAG_STOPPING, &ep->flags);
}
}

Expand Down
1 change: 1 addition & 0 deletions sound/usb/endpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep);
void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
int force, int can_sleep, int wait);
void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_free(struct list_head *head);
Expand Down
3 changes: 3 additions & 0 deletions sound/usb/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
goto unlock;
}

snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);

ret = set_format(subs, subs->cur_audiofmt);
if (ret < 0)
goto unlock;
Expand Down

0 comments on commit f58161b

Please sign in to comment.