Commit 57234bc1 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: usb-audio: Stop both endpoints properly at error

start_endpoints() may leave the data endpoint running if an error
happens at starting the sync endpoint.  We should stop both streams
properly, instead.

While we're at it, move the debug prints into the endpoint.c that is a
more suitable place.
Tested-by: default avatarKeith Milner <kamilner@superlative.org>
Tested-by: default avatarDylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-22-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 73037c8d
...@@ -1172,6 +1172,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) ...@@ -1172,6 +1172,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
if (atomic_read(&ep->chip->shutdown)) if (atomic_read(&ep->chip->shutdown))
return -EBADFD; return -EBADFD;
usb_audio_dbg(ep->chip, "Starting %s EP 0x%x (count %d)\n",
ep_type_name(ep->type), ep->ep_num, ep->use_count);
/* already running? */ /* already running? */
if (++ep->use_count != 1) if (++ep->use_count != 1)
return 0; return 0;
...@@ -1254,6 +1257,9 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) ...@@ -1254,6 +1257,9 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
if (!ep) if (!ep)
return; return;
usb_audio_dbg(ep->chip, "Stopping %s EP 0x%x (count %d)\n",
ep_type_name(ep->type), ep->ep_num, ep->use_count);
if (snd_BUG_ON(ep->use_count == 0)) if (snd_BUG_ON(ep->use_count == 0))
return; return;
......
...@@ -211,6 +211,17 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, ...@@ -211,6 +211,17 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip,
} }
} }
static void stop_endpoints(struct snd_usb_substream *subs)
{
if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
snd_usb_endpoint_stop(subs->sync_endpoint);
subs->sync_endpoint->sync_slave = NULL;
}
if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
snd_usb_endpoint_stop(subs->data_endpoint);
}
static int start_endpoints(struct snd_usb_substream *subs) static int start_endpoints(struct snd_usb_substream *subs)
{ {
int err; int err;
...@@ -221,13 +232,11 @@ static int start_endpoints(struct snd_usb_substream *subs) ...@@ -221,13 +232,11 @@ static int start_endpoints(struct snd_usb_substream *subs)
if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
struct snd_usb_endpoint *ep = subs->data_endpoint; struct snd_usb_endpoint *ep = subs->data_endpoint;
dev_dbg(&subs->dev->dev, "Starting data EP 0x%x\n", ep->ep_num);
ep->data_subs = subs; ep->data_subs = subs;
err = snd_usb_endpoint_start(ep); err = snd_usb_endpoint_start(ep);
if (err < 0) { if (err < 0) {
clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
return err; goto error;
} }
} }
...@@ -235,18 +244,20 @@ static int start_endpoints(struct snd_usb_substream *subs) ...@@ -235,18 +244,20 @@ static int start_endpoints(struct snd_usb_substream *subs)
!test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
struct snd_usb_endpoint *ep = subs->sync_endpoint; struct snd_usb_endpoint *ep = subs->sync_endpoint;
dev_dbg(&subs->dev->dev, "Starting sync EP 0x%x\n", ep->ep_num);
ep->sync_slave = subs->data_endpoint; ep->sync_slave = subs->data_endpoint;
err = snd_usb_endpoint_start(ep); err = snd_usb_endpoint_start(ep);
if (err < 0) { if (err < 0) {
clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
ep->sync_slave = NULL; ep->sync_slave = NULL;
return err; goto error;
} }
} }
return 0; return 0;
error:
stop_endpoints(subs);
return err;
} }
static void sync_pending_stops(struct snd_usb_substream *subs) static void sync_pending_stops(struct snd_usb_substream *subs)
...@@ -255,22 +266,6 @@ static void sync_pending_stops(struct snd_usb_substream *subs) ...@@ -255,22 +266,6 @@ static void sync_pending_stops(struct snd_usb_substream *subs)
snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
} }
static void stop_endpoints(struct snd_usb_substream *subs)
{
if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
dev_dbg(&subs->dev->dev, "Stopping sync EP 0x%x\n",
subs->sync_endpoint->ep_num);
snd_usb_endpoint_stop(subs->sync_endpoint);
subs->sync_endpoint->sync_slave = NULL;
}
if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
dev_dbg(&subs->dev->dev, "Stopping data EP 0x%x\n",
subs->data_endpoint->ep_num);
snd_usb_endpoint_stop(subs->data_endpoint);
}
}
/* PCM sync_stop callback */ /* PCM sync_stop callback */
static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment