audio : fix usb audio no sound problem.
authorsmj <smj@rock-chips.com>
Tue, 28 Oct 2014 06:46:03 +0000 (14:46 +0800)
committersmj <smj@rock-chips.com>
Tue, 28 Oct 2014 06:56:41 +0000 (14:56 +0800)
sound/usb/card.c

index f00b15a7301fe5bf520bc1f0563c77caa5902988..bfac3568ae2cb596a0739a2cd8fc08b1677f3fce 100644 (file)
@@ -45,7 +45,9 @@
 #include <linux/usb/audio.h>
 #include <linux/usb/audio-v2.h>
 #include <linux/module.h>
+#ifdef CONFIG_SWITCH
 #include <linux/switch.h>
+#endif
 
 #include <sound/control.h>
 #include <sound/core.h>
@@ -114,10 +116,39 @@ static DEFINE_MUTEX(register_mutex);
 static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
 static struct usb_driver usb_audio_driver;
 #ifdef CONFIG_SND_RK_SOC
-#define USB_AUDIO_CARD_NUM 2
+#define USB_AUDIO_CARD_NUM     3
 struct switch_dev *usb_audio_sdev;
 #endif
 
+#ifdef CONFIG_SWITCH
+//usb audio card will begin from RBASE_USB_AUDIO_IDX.
+#define RBASE_USB_AUDIO_IDX    (3)
+#define NO_USBAUDIO_PLAYBACK   (-1)
+#define NO_USBAUDIO_CAPTURE    (-1)
+
+struct usb_audio_switch {
+       int playback_switch_cur_state;
+       int capture_switch_cur_state;
+       struct switch_dev sUsbaudio_Playback;
+       struct switch_dev sUsbaudio_Capture;
+};
+
+// state: card*10 + device
+static struct usb_audio_switch sUsbaudio_Switch = {
+       .playback_switch_cur_state = NO_USBAUDIO_PLAYBACK,
+       .capture_switch_cur_state = NO_USBAUDIO_CAPTURE,
+       .sUsbaudio_Playback = {
+               .name = "usb_audio_playback",
+               .state = NO_USBAUDIO_PLAYBACK, //this means no usb audio playback available
+       },
+
+       .sUsbaudio_Capture = {
+               .name = "usb_audio_capture",
+               .state = NO_USBAUDIO_CAPTURE, //this means no usb audio capture available
+       },
+};
+#endif
+
 /*
  * disconnect streams
  * called from snd_usb_audio_disconnect()
@@ -466,6 +497,65 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
        return 0;
 }
 
+#ifdef CONFIG_SWITCH
+static int usb_audio_card_switch_state_update(struct snd_card *card, bool force){
+       struct snd_device *dev;
+    struct snd_pcm *pcm;
+    struct snd_pcm_str *pstr;
+
+       if (snd_BUG_ON(!card))
+               return -EINVAL;
+       //we use the latest devices
+       list_for_each_entry(dev, &card->devices, list) {
+               if (dev->type == SNDRV_DEV_PCM && dev->state == SNDRV_DEV_REGISTERED) {
+                       pcm = (struct snd_pcm*)dev->device_data;
+                       if (NULL != pcm) {
+                               //playback available?
+                               pstr = &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK];
+                               snd_printdd(KERN_INFO "playback substream_count: 0x%x\n", pstr->substream_count);
+                               if (pstr->substream_count > 0) {
+                                       sUsbaudio_Switch.playback_switch_cur_state = card->number * 10;
+                               }
+                               //capture available?
+                               pstr = &pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
+                               snd_printdd(KERN_INFO "capture substream_count: 0x%x\n", pstr->substream_count);
+                               if (pstr->substream_count > 0) {
+                                       sUsbaudio_Switch.capture_switch_cur_state = card->number * 10;
+                               }
+                       }
+               }
+       }
+       if (force) {
+               switch_set_state(&sUsbaudio_Switch.sUsbaudio_Playback, sUsbaudio_Switch.playback_switch_cur_state);
+               switch_set_state(&sUsbaudio_Switch.sUsbaudio_Capture, sUsbaudio_Switch.capture_switch_cur_state);
+       }
+       return 0;
+
+}
+
+static void usb_audio_switch_state_update_all(void)
+{
+       int index = 0;
+       struct snd_card *card;
+
+       sUsbaudio_Switch.playback_switch_cur_state = NO_USBAUDIO_PLAYBACK;
+       sUsbaudio_Switch.capture_switch_cur_state = NO_USBAUDIO_CAPTURE;
+
+       for (index = 0; index < SNDRV_CARDS; ++index) {
+               if (NULL != usb_chip[index]) {
+                       card = usb_chip[index]->card;
+                       usb_audio_card_switch_state_update(card, false);
+               }
+       }
+
+       switch_set_state(&sUsbaudio_Switch.sUsbaudio_Playback,
+                        sUsbaudio_Switch.playback_switch_cur_state);
+       switch_set_state(&sUsbaudio_Switch.sUsbaudio_Capture,
+                        sUsbaudio_Switch.capture_switch_cur_state);
+}
+#endif
+
+
 /*
  * probe the active usb device
  *
@@ -520,6 +610,7 @@ snd_usb_audio_probe(struct usb_device *dev,
                /* it's a fresh one.
                 * now look for an empty slot and create a new card instance
                 */
+               // use RBASE_USB_AUDIO_IDX instead of zero, modify by zxg.
                for (i = 0; i < SNDRV_CARDS; i++)
                        if (enable[i] && ! usb_chip[i] &&
                            (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
@@ -565,7 +656,12 @@ snd_usb_audio_probe(struct usb_device *dev,
        if (snd_card_register(chip->card) < 0) {
                goto __error;
        }
-
+#ifdef CONFIG_SWITCH
+       if (usb_audio_card_switch_state_update(chip->card, true) < 0) {
+               printk(KERN_ERR "usb_audio_card_switch_state_update failed!!!\n");
+       goto __error;
+       }
+#endif
        usb_chip[chip->index] = chip;
        chip->num_interfaces++;
        chip->probing = 0;
@@ -627,6 +723,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
        } else {
                mutex_unlock(&register_mutex);
        }
+#ifdef CONFIG_SWITCH
+       usb_audio_switch_state_update_all();
+#endif
 }
 
 /*
@@ -770,11 +869,24 @@ static struct usb_driver usb_audio_driver = {
 
 static int __init snd_usb_audio_init(void)
 {
+       int ret;
+#ifdef CONFIG_SWITCH
+       int i;
+       ret = switch_dev_register(&sUsbaudio_Switch.sUsbaudio_Playback);
+       if (ret)
+               goto err;
+       ret = switch_dev_register(&sUsbaudio_Switch.sUsbaudio_Capture);
+       if (ret)
+               goto err_drv;
+
+       switch_set_state(&sUsbaudio_Switch.sUsbaudio_Playback, NO_USBAUDIO_PLAYBACK);
+       switch_set_state(&sUsbaudio_Switch.sUsbaudio_Capture, NO_USBAUDIO_CAPTURE);
+#endif
+
        if (nrpacks < 1 || nrpacks > MAX_PACKS) {
                printk(KERN_WARNING "invalid nrpacks value.\n");
                return -EINVAL;
        }
-
 #ifdef CONFIG_SND_RK_SOC
        usb_audio_sdev = kzalloc(sizeof(usb_audio_sdev), GFP_KERNEL);
        usb_audio_sdev->name = "usb_audio";
@@ -785,7 +897,20 @@ static int __init snd_usb_audio_init(void)
        }
 #endif
 
+    //re initial array index for rebasing usb audio cards create, modify by zxg.
+    for(i=0; i<SNDRV_CARDS; ++i){
+        index[i] = i;
+    }
+
        return usb_register(&usb_audio_driver);
+
+err_drv:
+#ifdef CONFIG_SWITCH
+       switch_dev_unregister(&sUsbaudio_Switch.sUsbaudio_Playback);
+#endif
+err:
+    return ret;
+
 }
 
 static void __exit snd_usb_audio_cleanup(void)
@@ -794,7 +919,14 @@ static void __exit snd_usb_audio_cleanup(void)
 #ifdef CONFIG_SND_RK_SOC
        kfree(usb_audio_sdev);
 #endif
+       switch_dev_unregister(&sUsbaudio_Switch.sUsbaudio_Capture);
+       switch_dev_unregister(&sUsbaudio_Switch.sUsbaudio_Playback);
 }
 
 module_init(snd_usb_audio_init);
+/* use late initcall_sync instead of module_init,
+ * make sure that usbaudio probe after board codec.
+ * added by zxg@rock-chips.com
+ */
+late_initcall_sync(snd_usb_audio_init);
 module_exit(snd_usb_audio_cleanup);