diff options
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r-- | sound/usb/card.c | 64 |
1 files changed, 55 insertions, 9 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c index c0f8270bc199..40722f8711ad 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -65,6 +65,7 @@ #include "pcm.h" #include "urb.h" #include "format.h" +#include "power.h" MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_DESCRIPTION("USB Audio"); @@ -330,6 +331,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, 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)); @@ -451,6 +453,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __error; } chip = usb_chip[i]; + chip->probing = 1; break; } } @@ -466,6 +469,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, goto __error; } snd_card_set_dev(chip->card, &intf->dev); + chip->pm_intf = intf; break; } if (!chip) { @@ -505,6 +509,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, usb_chip[chip->index] = chip; chip->num_interfaces++; + chip->probing = 0; mutex_unlock(®ister_mutex); return chip; @@ -581,29 +586,61 @@ static void usb_audio_disconnect(struct usb_interface *intf) } #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); struct list_head *p; struct snd_usb_stream *as; + struct usb_mixer_interface *mixer; 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); - } + 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; } static int usb_audio_resume(struct usb_interface *intf) { struct snd_usb_audio *chip = usb_get_intfdata(intf); + struct usb_mixer_interface *mixer; + int err = 0; if (chip == (void *)-1L) return 0; @@ -611,12 +648,20 @@ static int usb_audio_resume(struct usb_interface *intf) return 0; /* * ALSA leaves material resumption to user space - * we just notify + * we just notify and restart the mixers */ + 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 @@ -644,6 +689,7 @@ static struct usb_driver usb_audio_driver = { .suspend = usb_audio_suspend, .resume = usb_audio_resume, .id_table = usb_audio_ids, + .supports_autosuspend = 1, }; static int __init snd_usb_audio_init(void) |