aboutsummaryrefslogtreecommitdiff
path: root/sound/usb/card.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r--sound/usb/card.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 63868d36..b2d3a980 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -110,6 +110,71 @@ static DEFINE_MUTEX(register_mutex);
static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
static struct usb_driver usb_audio_driver;
+struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num,
+ unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio
+ **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip))
+{
+ int idx;
+ struct snd_usb_stream *as;
+ struct snd_usb_substream *subs = NULL;
+ struct snd_usb_audio *chip = NULL;
+
+ mutex_lock(&register_mutex);
+ /*
+ * legacy audio snd card number assignment is dynamic. Hence
+ * search using chip->card->number
+ */
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+ if (!usb_chip[idx])
+ continue;
+ if (usb_chip[idx]->card->number == card_num) {
+ chip = usb_chip[idx];
+ break;
+ }
+ }
+
+ if (!chip || chip->shutdown) {
+ pr_debug("%s: instance of usb crad # %d does not exist\n",
+ __func__, card_num);
+ goto err;
+ }
+
+ if (pcm_idx >= chip->pcm_devs) {
+ pr_err("%s: invalid pcm dev number %u > %d\n", __func__,
+ pcm_idx, chip->pcm_devs);
+ goto err;
+ }
+
+ if (direction > SNDRV_PCM_STREAM_CAPTURE) {
+ pr_err("%s: invalid direction %u\n", __func__, direction);
+ goto err;
+ }
+
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ if (as->pcm_index == pcm_idx) {
+ subs = &as->substream[direction];
+ if (subs->interface < 0 && !subs->data_endpoint &&
+ !subs->sync_endpoint) {
+ pr_debug("%s: stream disconnected, bail out\n",
+ __func__);
+ subs = NULL;
+ goto err;
+ }
+ goto done;
+ }
+ }
+
+done:
+ chip->card_num = card_num;
+ chip->disconnect_cb = disconnect_cb;
+err:
+ *uchip = chip;
+ if (!subs)
+ pr_debug("%s: substream instance not found\n", __func__);
+ mutex_unlock(&register_mutex);
+ return subs;
+}
+
/*
* disconnect streams
* called from snd_usb_audio_disconnect()
@@ -324,6 +389,7 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip)
list_for_each_safe(p, n, &chip->ep_list)
snd_usb_endpoint_free(p);
+ mutex_destroy(&chip->dev_lock);
mutex_destroy(&chip->mutex);
kfree(chip);
return 0;
@@ -390,6 +456,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
mutex_init(&chip->mutex);
init_rwsem(&chip->shutdown_rwsem);
+ mutex_init(&chip->dev_lock);
chip->index = idx;
chip->dev = dev;
chip->card = card;
@@ -614,6 +681,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
chip->shutdown = 1;
up_write(&chip->shutdown_rwsem);
+ if (chip->disconnect_cb)
+ chip->disconnect_cb(chip);
+
mutex_lock(&register_mutex);
if (!was_shutdown) {
struct snd_usb_endpoint *ep;