Merge tag 'arm-dt-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / sound / usb / card.c
index fd6fd17..162bdd6 100644 (file)
@@ -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,37 @@ 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]);
+                       atomic_dec(&chip->active);
+                       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)
@@ -843,9 +868,6 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
        if (chip == (void *)-1L)
                return 0;
 
-       chip->autosuspended = !!PMSG_IS_AUTO(message);
-       if (!chip->autosuspended)
-               snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
        if (!chip->num_suspended_intf++) {
                list_for_each_entry(as, &chip->pcm_list, list) {
                        snd_usb_pcm_suspend(as);
@@ -858,6 +880,11 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
                        snd_usb_mixer_suspend(mixer);
        }
 
+       if (!PMSG_IS_AUTO(message) && !chip->system_suspend) {
+               snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+               chip->system_suspend = chip->num_suspended_intf;
+       }
+
        return 0;
 }
 
@@ -871,10 +898,10 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
 
        if (chip == (void *)-1L)
                return 0;
-       if (--chip->num_suspended_intf)
-               return 0;
 
        atomic_inc(&chip->active); /* avoid autopm */
+       if (chip->num_suspended_intf > 1)
+               goto out;
 
        list_for_each_entry(as, &chip->pcm_list, list) {
                err = snd_usb_pcm_resume(as);
@@ -896,9 +923,12 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
                snd_usbmidi_resume(p);
        }
 
-       if (!chip->autosuspended)
+ out:
+       if (chip->num_suspended_intf == chip->system_suspend) {
                snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
-       chip->autosuspended = 0;
+               chip->system_suspend = 0;
+       }
+       chip->num_suspended_intf--;
 
 err_out:
        atomic_dec(&chip->active); /* allow autopm after this point */