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 @@ | |||
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 | ||
69 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 70 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
70 | MODULE_DESCRIPTION("USB Audio"); | 71 | MODULE_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(®ister_mutex); | 513 | mutex_unlock(®ister_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 | |||
590 | int 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 | |||
600 | void 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 | |||
584 | static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | 606 | static 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 | ||
604 | static int usb_audio_resume(struct usb_interface *intf) | 639 | static 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; | 663 | err_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 | ||
649 | static int __init snd_usb_audio_init(void) | 695 | static int __init snd_usb_audio_init(void) |