summaryrefslogtreecommitdiff
path: root/sound/usb/mixer.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-18 10:46:37 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-18 10:46:37 -0700
commitd3e458d78167102cc961237cfceef6fffc80c0b3 (patch)
treee9195c1294daf053614e63ac52b0b44a28479017 /sound/usb/mixer.c
parentf2e1fbb5f2177227f71c4fc0491e531dd7acd385 (diff)
parentd351cf4603edb2a5bfa9a48d06c425511c63f2a3 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (308 commits) ALSA: sound/pci/asihpi: check adapter index in hpi_ioctl ALSA: aloop - Fix possible IRQ lock inversion ALSA: sound/core: merge list_del()/list_add_tail() to list_move_tail() ALSA: ctxfi - use list_move() instead of list_del()/list_add() combination ALSA: firewire - msleep needs delay.h ALSA: firewire-lib, firewire-speakers: handle packet queueing errors ALSA: firewire-lib: allocate DMA buffer separately ALSA: firewire-lib: use no-info SYT for packets without SYT sample ALSA: add LaCie FireWire Speakers/Griffin FireWave Surround driver ALSA: hda - Remove an unused variable in patch_realtek.c ALSA: hda - pin-adc-mux-dmic auto-configuration of 92HD8X codecs ALSA: hda - fix digital mic selection in mixer on 92HD8X codecs ALSA: hda - Move default input-src selection to init part ALSA: hda - Initialize special cases for input src in init phase ALSA: ctxfi - Clear input settings before initialization ALSA: ctxfi - Fix SPDIF status retrieval ALSA: ctxfi - Fix incorrect SPDIF status bit mask ALSA: ctxfi - Fix microphone boost codes/comments ALSA: atiixp - Fix wrong time-out checks during ac-link reset ALSA: intel8x0m: append 'm' to "r_intel8x0" ...
Diffstat (limited to 'sound/usb/mixer.c')
-rw-r--r--sound/usb/mixer.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 85af6051b52d..5e4775716607 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;
@@ -987,6 +1006,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
+ unsigned int range;
control++; /* change from zero-based to 1-based value */
@@ -1121,6 +1141,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
break;
+ case USB_ID(0x046d, 0x0808):
case USB_ID(0x046d, 0x0809):
case USB_ID(0x046d, 0x0991):
/* Most audio usb devices lie about volume resolution.
@@ -1136,6 +1157,21 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
+ range = (cval->max - cval->min) / cval->res;
+ /* Are there devices with volume range more than 255? I use a bit more
+ * to be sure. 384 is a resolution magic number found on Logitech
+ * devices. It will definitively catch all buggy Logitech devices.
+ */
+ if (range > 384) {
+ snd_printk(KERN_WARNING "usb_audio: Warning! Unlikely big "
+ "volume range (=%u), cval->res is probably wrong.",
+ range);
+ snd_printk(KERN_WARNING "usb_audio: [%d] FU [%s] ch = %d, "
+ "val = %d/%d/%d", cval->id,
+ kctl->id.name, cval->channels,
+ cval->min, cval->max, cval->res);
+ }
+
snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
cval->id, kctl->id.name, cval->channels, cval->min, cval->max, cval->res);
add_control_to_empty(state, kctl);
@@ -2058,8 +2094,9 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
{
struct usb_mixer_interface *mixer = urb->context;
int len = urb->actual_length;
+ int ustatus = urb->status;
- if (urb->status != 0)
+ if (ustatus != 0)
goto requeue;
if (mixer->protocol == UAC_VERSION_1) {
@@ -2100,12 +2137,32 @@ static void snd_usb_mixer_interrupt(struct urb *urb)
}
requeue:
- if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
+ if (ustatus != -ENOENT && ustatus != -ECONNRESET && ustatus != -ESHUTDOWN) {
urb->dev = mixer->chip->dev;
usb_submit_urb(urb, GFP_ATOMIC);
}
}
+/* stop any bus activity of a mixer */
+void snd_usb_mixer_inactivate(struct usb_mixer_interface *mixer)
+{
+ usb_kill_urb(mixer->urb);
+ usb_kill_urb(mixer->rc_urb);
+}
+
+int snd_usb_mixer_activate(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ if (mixer->urb) {
+ err = usb_submit_urb(mixer->urb, GFP_NOIO);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
/* create the handler for the optional status interrupt endpoint */
static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
{