On Wed, 03 Jun 2020 08:28:09 +0200,
Takashi Iwai wrote:
> 
> And, the most suspicious case is the last one,
> chip->num_suspended-intf.  It means that the device has multiple
> USB interfaces and they went to suspend, while the resume isn't
> performed for the all suspended interfaces in return.

If this is the cause, a patch like below might help.
It gets/puts the all assigned interfaced instead of only the primary
one.


Takashi

---
diff --git a/sound/usb/card.c b/sound/usb/card.c
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -634,7 +634,6 @@ static int usb_audio_probe(struct usb_interface *intf,
                                                                   id, &chip);
                                        if (err < 0)
                                                goto __error;
-                                       chip->pm_intf = intf;
                                        break;
                                } else if (vid[i] != -1 || pid[i] != -1) {
                                        dev_info(&dev->dev,
@@ -651,6 +650,13 @@ static int usb_audio_probe(struct usb_interface *intf,
                        goto __error;
                }
        }
+
+       if (chip->num_interfaces >= MAX_CARD_INTERFACES) {
+               dev_info(&dev->dev, "Too many interfaces assigned to the single 
USB-audio card\n");
+               err = -EINVAL;
+               goto __error;
+       }
+
        dev_set_drvdata(&dev->dev, chip);
 
        /*
@@ -703,6 +709,7 @@ static int usb_audio_probe(struct usb_interface *intf,
        }
 
        usb_chip[chip->index] = chip;
+       chip->intf[chip->num_interfaces] = intf;
        chip->num_interfaces++;
        usb_set_intfdata(intf, chip);
        atomic_dec(&chip->active);
@@ -818,19 +825,36 @@ void snd_usb_unlock_shutdown(struct snd_usb_audio *chip)
 
 int snd_usb_autoresume(struct snd_usb_audio *chip)
 {
+       int i, err;
+
        if (atomic_read(&chip->shutdown))
                return -EIO;
-       if (atomic_inc_return(&chip->active) == 1)
-               return usb_autopm_get_interface(chip->pm_intf);
+       if (atomic_inc_return(&chip->active) != 1)
+               return 0;
+
+       for (i = 0; i < chip->num_interfaces; i++) {
+               err = usb_autopm_get_interface(chip->intf[i]);
+               if (err < 0) {
+                       /* rollback */
+                       while (--i >= 0)
+                               usb_autopm_put_interface(chip->intf[i]);
+                       return err;
+               }
+       }
        return 0;
 }
 
 void snd_usb_autosuspend(struct snd_usb_audio *chip)
 {
+       int i;
+
        if (atomic_read(&chip->shutdown))
                return;
-       if (atomic_dec_and_test(&chip->active))
-               usb_autopm_put_interface(chip->pm_intf);
+       if (!atomic_dec_and_test(&chip->active))
+               return;
+
+       for (i = 0; i < chip->num_interfaces; i++)
+               usb_autopm_put_interface(chip->intf[i]);
 }
 
 static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -19,11 +19,13 @@
 struct media_device;
 struct media_intf_devnode;
 
+#define MAX_CARD_INTERFACES    16
+
 struct snd_usb_audio {
        int index;
        struct usb_device *dev;
        struct snd_card *card;
-       struct usb_interface *pm_intf;
+       struct usb_interface *intf[MAX_CARD_INTERFACES];
        u32 usb_id;
        struct mutex mutex;
        unsigned int autosuspended:1;   

Reply via email to