#include "pcm.h"
 #include "urb.h"
 #include "format.h"
+#include "power.h"
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("USB Audio");
        chip->setup = device_setup[idx];
        chip->nrpacks = nrpacks;
        chip->async_unlink = async_unlink;
+       chip->probing = 1;
 
        chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
                              le16_to_cpu(dev->descriptor.idProduct));
                                goto __error;
                        }
                        chip = usb_chip[i];
+                       chip->probing = 1;
                        break;
                }
        }
                                        goto __error;
                                }
                                snd_card_set_dev(chip->card, &intf->dev);
+                               chip->pm_intf = intf;
                                break;
                        }
                if (!chip) {
 
        usb_chip[chip->index] = chip;
        chip->num_interfaces++;
+       chip->probing = 0;
        mutex_unlock(®ister_mutex);
        return chip;
 
 }
 
 #ifdef CONFIG_PM
+
+int snd_usb_autoresume(struct snd_usb_audio *chip)
+{
+       int err = -ENODEV;
+
+       if (!chip->shutdown && !chip->probing)
+               err = usb_autopm_get_interface(chip->pm_intf);
+
+       return err;
+}
+
+void snd_usb_autosuspend(struct snd_usb_audio *chip)
+{
+       if (!chip->shutdown && !chip->probing)
+               usb_autopm_put_interface(chip->pm_intf);
+}
+
 static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
        if (chip == (void *)-1L)
                return 0;
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
-       if (!chip->num_suspended_intf++) {
-               list_for_each(p, &chip->pcm_list) {
-                       as = list_entry(p, struct snd_usb_stream, list);
-                       snd_pcm_suspend_all(as->pcm);
-               }
-
-               list_for_each_entry(mixer, &chip->mixer_list, list) {
-                       snd_usb_mixer_inactivate(mixer);
-               }
+       if (!(message.event & PM_EVENT_AUTO)) {
+               snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
+               if (!chip->num_suspended_intf++) {
+                       list_for_each(p, &chip->pcm_list) {
+                               as = list_entry(p, struct snd_usb_stream, list);
+                               snd_pcm_suspend_all(as->pcm);
+                       }
+               }
+       } else {
+               /*
+                * otherwise we keep the rest of the system in the dark
+                * to keep this transparent
+                */
+               if (!chip->num_suspended_intf++)
+                       chip->autosuspended = 1;
        }
 
+       list_for_each_entry(mixer, &chip->mixer_list, list)
+               snd_usb_mixer_inactivate(mixer);
+
        return 0;
 }
 
 {
        struct snd_usb_audio *chip = usb_get_intfdata(intf);
        struct usb_mixer_interface *mixer;
+       int err = 0;
 
        if (chip == (void *)-1L)
                return 0;
         * ALSA leaves material resumption to user space
         * we just notify and restart the mixers
         */
-       list_for_each_entry(mixer, &chip->mixer_list, list)
-               snd_usb_mixer_activate(mixer);
+       list_for_each_entry(mixer, &chip->mixer_list, list) {
+               err = snd_usb_mixer_activate(mixer);
+               if (err < 0)
+                       goto err_out;
+       }
 
-       snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+       if (!chip->autosuspended)
+               snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
+       chip->autosuspended = 0;
 
-       return 0;
+err_out:
+       return err;
 }
 #else
 #define usb_audio_suspend      NULL
        .suspend =      usb_audio_suspend,
        .resume =       usb_audio_resume,
        .id_table =     usb_audio_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init snd_usb_audio_init(void)
 
 #include <sound/asequencer.h>
 #include "usbaudio.h"
 #include "midi.h"
+#include "power.h"
 #include "helper.h"
 
 /*
        struct snd_usb_midi* umidi = substream->rmidi->private_data;
        struct usbmidi_out_port* port = NULL;
        int i, j;
+       int err;
 
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
                if (umidi->endpoints[i].out)
                snd_BUG();
                return -ENXIO;
        }
+       err = usb_autopm_get_interface(umidi->iface);
+       if (err < 0)
+               return -EIO;
        substream->runtime->private_data = port;
        port->state = STATE_UNKNOWN;
        substream_open(substream, 1);
 
 static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
 {
+       struct snd_usb_midi* umidi = substream->rmidi->private_data;
+
        substream_open(substream, 0);
+       usb_autopm_put_interface(umidi->iface);
        return 0;
 }
 
 
 #include "mixer.h"
 #include "helper.h"
 #include "mixer_quirks.h"
+#include "power.h"
 
 #define MAX_ID_ELEMS   256
 
        unsigned char buf[2];
        int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
        int timeout = 10;
+       int err;
 
+       err = snd_usb_autoresume(cval->mixer->chip);
+       if (err < 0)
+               return -EIO;
        while (timeout-- > 0) {
                if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
                                    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
                                    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
                                    buf, val_len, 100) >= val_len) {
                        *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
+                       snd_usb_autosuspend(cval->mixer->chip);
                        return 0;
                }
        }
+       snd_usb_autosuspend(cval->mixer->chip);
        snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
                    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
        return -EINVAL;
 
        memset(buf, 0, sizeof(buf));
 
+       ret = snd_usb_autoresume(chip) ? -EIO : 0;
+       if (ret)
+               goto error;
+
        ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
                              USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
                              validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
                              buf, size, 1000);
+       snd_usb_autosuspend(chip);
 
        if (ret < 0) {
+error:
                snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
                           request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
                return ret;
 {
        struct snd_usb_audio *chip = cval->mixer->chip;
        unsigned char buf[2];
-       int val_len, timeout = 10;
+       int val_len, err, timeout = 10;
 
        if (cval->mixer->protocol == UAC_VERSION_1) {
                val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
        value_set = convert_bytes_value(cval, value_set);
        buf[0] = value_set & 0xff;
        buf[1] = (value_set >> 8) & 0xff;
+       err = snd_usb_autoresume(chip);
+       if (err < 0)
+               return -EIO;
        while (timeout-- > 0)
                if (snd_usb_ctl_msg(chip->dev,
                                    usb_sndctrlpipe(chip->dev, 0), request,
                                    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
                                    validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
-                                   buf, val_len, 100) >= 0)
+                                   buf, val_len, 100) >= 0) {
+                       snd_usb_autosuspend(chip);
                        return 0;
+               }
+       snd_usb_autosuspend(chip);
        snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
                    request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
        return -EINVAL;
 
 #include "helper.h"
 #include "pcm.h"
 #include "clock.h"
+#include "power.h"
 
 /*
  * return the current pcm pointer.  just based on the hwptr_done value.
                pt = 125 * (1 << fp->datainterval);
                ptmin = min(ptmin, pt);
        }
+       err = snd_usb_autoresume(subs->stream->chip);
+       if (err < 0)
+               return err;
 
        param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
        if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
                                       SNDRV_PCM_HW_PARAM_CHANNELS,
                                       param_period_time_if_needed,
                                       -1)) < 0)
-               return err;
+               goto rep_err;
        if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
                                       hw_rule_channels, subs,
                                       SNDRV_PCM_HW_PARAM_FORMAT,
                                       SNDRV_PCM_HW_PARAM_RATE,
                                       param_period_time_if_needed,
                                       -1)) < 0)
-               return err;
+               goto rep_err;
        if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
                                       hw_rule_format, subs,
                                       SNDRV_PCM_HW_PARAM_RATE,
                                       SNDRV_PCM_HW_PARAM_CHANNELS,
                                       param_period_time_if_needed,
                                       -1)) < 0)
-               return err;
+               goto rep_err;
        if (param_period_time_if_needed >= 0) {
                err = snd_pcm_hw_rule_add(runtime, 0,
                                          SNDRV_PCM_HW_PARAM_PERIOD_TIME,
                                          SNDRV_PCM_HW_PARAM_RATE,
                                          -1);
                if (err < 0)
-                       return err;
+                       goto rep_err;
        }
        if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0)
-               return err;
+               goto rep_err;
        return 0;
+
+rep_err:
+       snd_usb_autosuspend(subs->stream->chip);
+       return err;
 }
 
 static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
        runtime->hw = snd_usb_hardware;
        runtime->private_data = subs;
        subs->pcm_substream = substream;
+       /* runtime PM is also done there */
        return setup_hw_info(runtime, subs);
 }
 
                subs->interface = -1;
        }
        subs->pcm_substream = NULL;
+       snd_usb_autosuspend(subs->stream->chip);
        return 0;
 }
 
 
--- /dev/null
+#ifndef __USBAUDIO_POWER_H
+#define __USBAUDIO_POWER_H
+
+#ifdef CONFIG_PM
+int snd_usb_autoresume(struct snd_usb_audio *chip);
+void snd_usb_autosuspend(struct snd_usb_audio *chip);
+#else
+static inline int snd_usb_autoresume(struct snd_usb_audio *chip)
+{
+       return 0;
+}
+static inline void snd_usb_autosuspend(struct snd_usb_audio *chip)
+{
+}
+#endif
+
+#endif /* __USBAUDIO_POWER_H */
 
        int index;
        struct usb_device *dev;
        struct snd_card *card;
+       struct usb_interface *pm_intf;
        u32 usb_id;
-       int shutdown;
        struct mutex shutdown_mutex;
+       unsigned int shutdown:1;
+       unsigned int probing:1;
+       unsigned int autosuspended:1;   
        unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */
+       
        int num_interfaces;
        int num_suspended_intf;