aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/card.c
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2011-03-11 08:51:12 -0500
committerTakashi Iwai <tiwai@suse.de>2011-03-11 08:59:29 -0500
commit88a8516a2128a6d078a106ead48092240e8a138f (patch)
treedc839c85a9b2fc2e17759c5a42368cb8300e42bc /sound/usb/card.c
parentedf7de31c25ce72f163bf7d1fc0d2711869d073c (diff)
ALSA: usbaudio: implement USB autosuspend
Devices are autosuspended if no pcm nor midi channel is open Mixer devices may be opened. This way they are active when in use to play or record sound, but can be suspended while users have a mixer application running. [Small clean-ups using static inline by tiwai] Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/card.c')
-rw-r--r--sound/usb/card.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 7fa53d91e73b..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,6 +586,23 @@ 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);
@@ -591,18 +613,26 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
591 if (chip == (void *)-1L) 613 if (chip == (void *)-1L)
592 return 0; 614 return 0;
593 615
594 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); 616 if (!(message.event & PM_EVENT_AUTO)) {
595 if (!chip->num_suspended_intf++) { 617 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot);
596 list_for_each(p, &chip->pcm_list) { 618 if (!chip->num_suspended_intf++) {
597 as = list_entry(p, struct snd_usb_stream, list); 619 list_for_each(p, &chip->pcm_list) {
598 snd_pcm_suspend_all(as->pcm); 620 as = list_entry(p, struct snd_usb_stream, list);
599 } 621 snd_pcm_suspend_all(as->pcm);
600 622 }
601 list_for_each_entry(mixer, &chip->mixer_list, list) { 623 }
602 snd_usb_mixer_inactivate(mixer); 624 } else {
603 } 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;
604 } 631 }
605 632
633 list_for_each_entry(mixer, &chip->mixer_list, list)
634 snd_usb_mixer_inactivate(mixer);
635
606 return 0; 636 return 0;
607} 637}
608 638
@@ -610,6 +640,7 @@ static int usb_audio_resume(struct usb_interface *intf)
610{ 640{
611 struct snd_usb_audio *chip = usb_get_intfdata(intf); 641 struct snd_usb_audio *chip = usb_get_intfdata(intf);
612 struct usb_mixer_interface *mixer; 642 struct usb_mixer_interface *mixer;
643 int err = 0;
613 644
614 if (chip == (void *)-1L) 645 if (chip == (void *)-1L)
615 return 0; 646 return 0;
@@ -619,12 +650,18 @@ static int usb_audio_resume(struct usb_interface *intf)
619 * ALSA leaves material resumption to user space 650 * ALSA leaves material resumption to user space
620 * we just notify and restart the mixers 651 * we just notify and restart the mixers
621 */ 652 */
622 list_for_each_entry(mixer, &chip->mixer_list, list) 653 list_for_each_entry(mixer, &chip->mixer_list, list) {
623 snd_usb_mixer_activate(mixer); 654 err = snd_usb_mixer_activate(mixer);
655 if (err < 0)
656 goto err_out;
657 }
624 658
625 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;
626 662
627 return 0; 663err_out:
664 return err;
628} 665}
629#else 666#else
630#define usb_audio_suspend NULL 667#define usb_audio_suspend NULL
@@ -652,6 +689,7 @@ static struct usb_driver usb_audio_driver = {
652 .suspend = usb_audio_suspend, 689 .suspend = usb_audio_suspend,
653 .resume = usb_audio_resume, 690 .resume = usb_audio_resume,
654 .id_table = usb_audio_ids, 691 .id_table = usb_audio_ids,
692 .supports_autosuspend = 1,
655}; 693};
656 694
657static int __init snd_usb_audio_init(void) 695static int __init snd_usb_audio_init(void)