aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/card.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r--sound/usb/card.c64
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 @@
65#include "pcm.h" 65#include "pcm.h"
66#include "urb.h" 66#include "urb.h"
67#include "format.h" 67#include "format.h"
68#include "power.h"
68 69
69MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 70MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
70MODULE_DESCRIPTION("USB Audio"); 71MODULE_DESCRIPTION("USB Audio");
@@ -330,6 +331,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
330 chip->setup = device_setup[idx]; 331 chip->setup = device_setup[idx];
331 chip->nrpacks = nrpacks; 332 chip->nrpacks = nrpacks;
332 chip->async_unlink = async_unlink; 333 chip->async_unlink = async_unlink;
334 chip->probing = 1;
333 335
334 chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), 336 chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
335 le16_to_cpu(dev->descriptor.idProduct)); 337 le16_to_cpu(dev->descriptor.idProduct));
@@ -451,6 +453,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
451 goto __error; 453 goto __error;
452 } 454 }
453 chip = usb_chip[i]; 455 chip = usb_chip[i];
456 chip->probing = 1;
454 break; 457 break;
455 } 458 }
456 } 459 }
@@ -466,6 +469,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
466 goto __error; 469 goto __error;
467 } 470 }
468 snd_card_set_dev(chip->card, &intf->dev); 471 snd_card_set_dev(chip->card, &intf->dev);
472 chip->pm_intf = intf;
469 break; 473 break;
470 } 474 }
471 if (!chip) { 475 if (!chip) {
@@ -505,6 +509,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
505 509
506 usb_chip[chip->index] = chip; 510 usb_chip[chip->index] = chip;
507 chip->num_interfaces++; 511 chip->num_interfaces++;
512 chip->probing = 0;
508 mutex_unlock(&register_mutex); 513 mutex_unlock(&register_mutex);
509 return chip; 514 return chip;
510 515
@@ -581,29 +586,61 @@ static void usb_audio_disconnect(struct usb_interface *intf)
581} 586}
582 587
583#ifdef CONFIG_PM 588#ifdef CONFIG_PM
589
590int snd_usb_autoresume(struct snd_usb_audio *chip)
591{
592 int err = -ENODEV;
593
594 if (!chip->shutdown && !chip->probing)
595 err = usb_autopm_get_interface(chip->pm_intf);
596
597 return err;
598}
599
600void snd_usb_autosuspend(struct snd_usb_audio *chip)
601{
602 if (!chip->shutdown && !chip->probing)
603 usb_autopm_put_interface(chip->pm_intf);
604}
605
584static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) 606static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
585{ 607{
586 struct snd_usb_audio *chip = usb_get_intfdata(intf); 608 struct snd_usb_audio *chip = usb_get_intfdata(intf);
587 struct list_head *p; 609 struct list_head *p;
588 struct snd_usb_stream *as; 610 struct snd_usb_stream *as;
611 struct usb_mixer_interface *mixer;
589 612
590 if (chip == (void *)-1L) 613 if (chip == (void *)-1L)
591 return 0; 614 return 0;
592 615
593 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); 616 if (!(message.event & PM_EVENT_AUTO)) {
594 if (!chip->num_suspended_intf++) { 617 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
595 list_for_each(p, &chip->pcm_list) { 618 if (!chip->num_suspended_intf++) {
596 as = list_entry(p, struct snd_usb_stream, list); 619 list_for_each(p, &chip->pcm_list) {
597 snd_pcm_suspend_all(as->pcm); 620 as = list_entry(p, struct snd_usb_stream, list);
598 } 621 snd_pcm_suspend_all(as->pcm);
622 }
623 }
624 } else {
625 /*
626 * otherwise we keep the rest of the system in the dark
627 * to keep this transparent
628 */
629 if (!chip->num_suspended_intf++)
630 chip->autosuspended = 1;
599 } 631 }
600 632
633 list_for_each_entry(mixer, &chip->mixer_list, list)
634 snd_usb_mixer_inactivate(mixer);
635
601 return 0; 636 return 0;
602} 637}
603 638
604static int usb_audio_resume(struct usb_interface *intf) 639static int usb_audio_resume(struct usb_interface *intf)
605{ 640{
606 struct snd_usb_audio *chip = usb_get_intfdata(intf); 641 struct snd_usb_audio *chip = usb_get_intfdata(intf);
642 struct usb_mixer_interface *mixer;
643 int err = 0;
607 644
608 if (chip == (void *)-1L) 645 if (chip == (void *)-1L)
609 return 0; 646 return 0;
@@ -611,12 +648,20 @@ static int usb_audio_resume(struct usb_interface *intf)
611 return 0; 648 return 0;
612 /* 649 /*
613 * ALSA leaves material resumption to user space 650 * ALSA leaves material resumption to user space
614 * we just notify 651 * we just notify and restart the mixers
615 */ 652 */
653 list_for_each_entry(mixer, &chip->mixer_list, list) {
654 err = snd_usb_mixer_activate(mixer);
655 if (err < 0)
656 goto err_out;
657 }
616 658
617 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); 659 if (!chip->autosuspended)
660 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
661 chip->autosuspended = 0;
618 662
619 return 0; 663err_out:
664 return err;
620} 665}
621#else 666#else
622#define usb_audio_suspend NULL 667#define usb_audio_suspend NULL
@@ -644,6 +689,7 @@ static struct usb_driver usb_audio_driver = {
644 .suspend = usb_audio_suspend, 689 .suspend = usb_audio_suspend,
645 .resume = usb_audio_resume, 690 .resume = usb_audio_resume,
646 .id_table = usb_audio_ids, 691 .id_table = usb_audio_ids,
692 .supports_autosuspend = 1,
647}; 693};
648 694
649static int __init snd_usb_audio_init(void) 695static int __init snd_usb_audio_init(void)