forked from hardkernel/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
- Loading branch information
Showing
6 changed files
with
118 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ | |
#include "pcm.h" | ||
#include "urb.h" | ||
#include "format.h" | ||
#include "power.h" | ||
|
||
MODULE_AUTHOR("Takashi Iwai <[email protected]>"); | ||
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,6 +586,23 @@ 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); | ||
|
@@ -591,25 +613,34 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) | |
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; | ||
} | ||
|
||
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; | ||
|
@@ -619,12 +650,18 @@ static int usb_audio_resume(struct usb_interface *intf) | |
* 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 | ||
|
@@ -652,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) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters