Skip to content

Commit

Permalink
ALSA: snd-usb: Fix URB cancellation at stream start
Browse files Browse the repository at this point in the history
Commit e9ba389 ("ALSA: usb-audio: Fix scheduling-while-atomic bug in
PCM capture stream") fixed a scheduling-while-atomic bug that happened
when snd_usb_endpoint_start was called from the trigger callback, which
is an atmic context. However, the patch breaks the idea of the endpoints
reference counting, which is the reason why the driver has been
refactored lately.

Revert that commit and let snd_usb_endpoint_start() take care of the URB
cancellation again. As this function is called from both atomic and
non-atomic context, add a flag to denote whether the function may sleep.

Signed-off-by: Daniel Mack <[email protected]>
Cc: [email protected] [3.5+]
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
zonque authored and tiwai committed Aug 30, 2012
1 parent c36b5b0 commit 015618b
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 11 deletions.
11 changes: 9 additions & 2 deletions sound/usb/endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
/**
* snd_usb_endpoint_start: start an snd_usb_endpoint
*
* @ep: the endpoint to start
* @ep: the endpoint to start
* @can_sleep: flag indicating whether the operation is executed in
* non-atomic context
*
* A call to this function will increment the use count of the endpoint.
* In case it is not already running, the URBs for this endpoint will be
Expand All @@ -809,7 +811,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
*
* Returns an error if the URB submission failed, 0 in all other cases.
*/
int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
{
int err;
unsigned int i;
Expand All @@ -821,6 +823,11 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
if (++ep->use_count != 1)
return 0;

/* just to be sure */
deactivate_urbs(ep, 0, can_sleep);
if (can_sleep)
wait_clear_urbs(ep);

ep->active_mask = 0;
ep->unlink_mask = 0;
ep->phase = 0;
Expand Down
2 changes: 1 addition & 1 deletion sound/usb/endpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep);

int snd_usb_endpoint_start(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);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
Expand Down
13 changes: 5 additions & 8 deletions sound/usb/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
}
}

static int start_endpoints(struct snd_usb_substream *subs)
static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
{
int err;

Expand All @@ -225,7 +225,7 @@ static int start_endpoints(struct snd_usb_substream *subs)
snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);

ep->data_subs = subs;
err = snd_usb_endpoint_start(ep);
err = snd_usb_endpoint_start(ep, can_sleep);
if (err < 0) {
clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
return err;
Expand All @@ -239,7 +239,7 @@ static int start_endpoints(struct snd_usb_substream *subs)
snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);

ep->sync_slave = subs->data_endpoint;
err = snd_usb_endpoint_start(ep);
err = snd_usb_endpoint_start(ep, can_sleep);
if (err < 0) {
clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
return err;
Expand Down Expand Up @@ -544,13 +544,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->last_frame_number = 0;
runtime->delay = 0;

/* clear the pending deactivation on the target EPs */
deactivate_endpoints(subs);

/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
return start_endpoints(subs);
return start_endpoints(subs, 1);

return 0;
}
Expand Down Expand Up @@ -1175,7 +1172,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
err = start_endpoints(subs);
err = start_endpoints(subs, 0);
if (err < 0)
return err;

Expand Down

0 comments on commit 015618b

Please sign in to comment.