ALSA: usb-audio: Refactoring endpoint URB deactivation

Minor code refactoring to consolidate the URB deactivation code in
endpoint.c.  A slight behavior change is that the error handling in
snd_usb_endpoint_start() leaves EP_FLAG_STOPPING now.  This should be
synced with the later PCM sync_stop callback.

Tested-by: Keith Milner <kamilner@superlative.org>
Tested-by: Dylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-30-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2020-11-23 09:53:35 +01:00
parent 43b81e8406
commit d0f09d1e4a

View File

@ -777,6 +777,9 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
unsigned long end_time = jiffies + msecs_to_jiffies(1000); unsigned long end_time = jiffies + msecs_to_jiffies(1000);
int alive; int alive;
if (!test_bit(EP_FLAG_STOPPING, &ep->flags))
return 0;
do { do {
alive = bitmap_weight(&ep->active_mask, ep->nurbs); alive = bitmap_weight(&ep->active_mask, ep->nurbs);
if (!alive) if (!alive)
@ -802,22 +805,31 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep)
*/ */
void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep) void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
{ {
if (ep && test_bit(EP_FLAG_STOPPING, &ep->flags)) if (ep)
wait_clear_urbs(ep); wait_clear_urbs(ep);
} }
/* /*
* unlink active urbs. * Stop and unlink active urbs.
*
* This function checks and clears EP_FLAG_RUNNING state.
* When @wait_sync is set, it waits until all pending URBs are killed.
*/ */
static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) static int stop_and_unlink_urbs(struct snd_usb_endpoint *ep, bool force,
bool wait_sync)
{ {
unsigned int i; unsigned int i;
if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */ if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */
return -EBADFD; return -EBADFD;
clear_bit(EP_FLAG_RUNNING, &ep->flags); if (atomic_read(&ep->running))
return -EBUSY;
if (!test_and_clear_bit(EP_FLAG_RUNNING, &ep->flags))
goto out;
set_bit(EP_FLAG_STOPPING, &ep->flags);
INIT_LIST_HEAD(&ep->ready_playback_urbs); INIT_LIST_HEAD(&ep->ready_playback_urbs);
ep->next_packet_head = 0; ep->next_packet_head = 0;
ep->next_packet_queued = 0; ep->next_packet_queued = 0;
@ -831,6 +843,9 @@ static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force)
} }
} }
out:
if (wait_sync)
return wait_clear_urbs(ep);
return 0; return 0;
} }
@ -845,8 +860,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL); snd_usb_endpoint_set_callback(ep, NULL, NULL, NULL);
/* stop urbs */ /* stop urbs */
deactivate_urbs(ep, force); stop_and_unlink_urbs(ep, force, true);
wait_clear_urbs(ep);
for (i = 0; i < ep->nurbs; i++) for (i = 0; i < ep->nurbs; i++)
release_urb_ctx(&ep->urb[i]); release_urb_ctx(&ep->urb[i]);
@ -1261,9 +1275,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
if (atomic_inc_return(&ep->running) != 1) if (atomic_inc_return(&ep->running) != 1)
return 0; return 0;
/* just to be sure */
deactivate_urbs(ep, false);
ep->active_mask = 0; ep->active_mask = 0;
ep->unlink_mask = 0; ep->unlink_mask = 0;
ep->phase = 0; ep->phase = 0;
@ -1317,11 +1328,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
return 0; return 0;
__error: __error:
if (ep->sync_master) snd_usb_endpoint_stop(ep);
WRITE_ONCE(ep->sync_master->sync_slave, NULL);
clear_bit(EP_FLAG_RUNNING, &ep->flags);
atomic_dec(&ep->running);
deactivate_urbs(ep, false);
return -EPIPE; return -EPIPE;
} }
@ -1354,10 +1361,8 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
if (ep->sync_master) if (ep->sync_master)
WRITE_ONCE(ep->sync_master->sync_slave, NULL); WRITE_ONCE(ep->sync_master->sync_slave, NULL);
if (!atomic_dec_return(&ep->running)) { if (!atomic_dec_return(&ep->running))
deactivate_urbs(ep, false); stop_and_unlink_urbs(ep, false, false);
set_bit(EP_FLAG_STOPPING, &ep->flags);
}
} }
/** /**