summaryrefslogtreecommitdiff
path: root/sound/usb/mixer.c
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2011-03-11 13:51:12 (GMT)
committerTakashi Iwai <tiwai@suse.de>2011-03-11 13:59:29 (GMT)
commit88a8516a2128a6d078a106ead48092240e8a138f (patch)
treedc839c85a9b2fc2e17759c5a42368cb8300e42bc /sound/usb/mixer.c
parentedf7de31c25ce72f163bf7d1fc0d2711869d073c (diff)
downloadlinux-88a8516a2128a6d078a106ead48092240e8a138f.tar.xz
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/mixer.c')
-rw-r--r--sound/usb/mixer.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 09e5934..5e47757 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -61,6 +61,7 @@
#include "mixer.h"
#include "helper.h"
#include "mixer_quirks.h"
+#include "power.h"
#define MAX_ID_ELEMS 256
@@ -295,16 +296,22 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
+ int err;
+ err = snd_usb_autoresume(cval->mixer->chip);
+ if (err < 0)
+ return -EIO;
while (timeout-- > 0) {
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, val_len, 100) >= val_len) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
+ snd_usb_autosuspend(cval->mixer->chip);
return 0;
}
}
+ snd_usb_autosuspend(cval->mixer->chip);
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return -EINVAL;
@@ -328,12 +335,18 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
memset(buf, 0, sizeof(buf));
+ ret = snd_usb_autoresume(chip) ? -EIO : 0;
+ if (ret)
+ goto error;
+
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
buf, size, 1000);
+ snd_usb_autosuspend(chip);
if (ret < 0) {
+error:
snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
return ret;
@@ -413,7 +426,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
{
struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2];
- int val_len, timeout = 10;
+ int val_len, err, timeout = 10;
if (cval->mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
@@ -433,13 +446,19 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
value_set = convert_bytes_value(cval, value_set);
buf[0] = value_set & 0xff;
buf[1] = (value_set >> 8) & 0xff;
+ err = snd_usb_autoresume(chip);
+ if (err < 0)
+ return -EIO;
while (timeout-- > 0)
if (snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
- buf, val_len, 100) >= 0)
+ buf, val_len, 100) >= 0) {
+ snd_usb_autosuspend(chip);
return 0;
+ }
+ snd_usb_autosuspend(chip);
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
return -EINVAL;