summaryrefslogtreecommitdiff
path: root/sound/usb/card.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r--sound/usb/card.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 57a8e2d0139f..1a112d3cf210 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -2,6 +2,7 @@
* (Tentative) USB Audio Driver for ALSA
*
* Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
*
* Many codes borrowed from audio.c by
* Alan Cox (alan@lxorguk.ukuu.org.uk)
@@ -47,6 +48,7 @@
#include <linux/mutex.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
+#include <linux/switch.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -111,6 +113,15 @@ MODULE_PARM_DESC(ignore_ctl_error,
* the all interfaces on the same card as one sound device.
*/
+struct usb_audio_switch_data {
+ struct switch_dev sdev;
+ const char *name_on;
+ const char *name_off;
+ const char *state_on;
+ const char *state_off;
+};
+
+static struct usb_audio_switch_data *audio_switch_data[SNDRV_CARDS];
static DEFINE_MUTEX(register_mutex);
static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
static struct usb_driver usb_audio_driver;
@@ -589,16 +600,80 @@ static int usb_audio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
void *chip;
+ struct usb_audio_switch_data *switch_data;
+ int ret = 0;
+ struct snd_usb_audio *uchip;
+ int idx;
+ struct snd_usb_stream *as;
+ struct snd_usb_substream *subs;
+ struct list_head *head;
+ int state = 0;
+
chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
if (chip) {
usb_set_intfdata(intf, chip);
+ uchip = chip;
+ switch_data = kzalloc(sizeof(struct usb_audio_switch_data), GFP_KERNEL);
+ if (!switch_data)
+ return -ENOMEM;
+ switch_data->sdev.name = "usb_audio";
+ ret = switch_dev_register(&switch_data->sdev);
+ if (ret < 0)
+ goto err_switch_dev_register;
+ audio_switch_data[uchip->index] = switch_data;
+
+ list_for_each(head, &uchip->pcm_list) {
+ as = list_entry(head, struct snd_usb_stream, list);
+ for (idx = 0; idx < 2; idx++) {
+ subs = &as->substream[idx];
+ if (!subs->num_formats)
+ continue;
+ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ state |= 0x1;
+ if (subs->direction == SNDRV_PCM_STREAM_CAPTURE)
+ state |= 0x2;
+ }
+ }
+ switch_set_state(&switch_data->sdev, state);
return 0;
} else
return -EIO;
+
+
+err_switch_dev_register:
+ kfree(switch_data);
+ return 0;
}
static void usb_audio_disconnect(struct usb_interface *intf)
{
+ struct snd_usb_audio *uchip = usb_get_intfdata(intf);
+ struct usb_audio_switch_data *switch_data;
+ int idx;
+ struct snd_usb_stream *as;
+ struct snd_usb_substream *subs;
+ struct list_head *head;
+
+ if (uchip == (void *)-1L)
+ return;
+
+ if (uchip) {
+ switch_data = audio_switch_data[uchip->index];
+ if (switch_data) {
+ switch_set_state(&switch_data->sdev, 0);
+ switch_dev_unregister(&switch_data->sdev);
+ kfree(switch_data);
+ }
+ list_for_each(head, &uchip->pcm_list) {
+ as = list_entry(head, struct snd_usb_stream, list);
+ for (idx = 0; idx < 2; idx++) {
+ subs = &as->substream[idx];
+ if (subs->running)
+ snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_DISCONNECTED);
+ }
+ }
+ }
+
snd_usb_audio_disconnect(interface_to_usbdev(intf),
usb_get_intfdata(intf));
}