ALSA: usb-audio: add control index offset
authorEldad Zack <eldad@fogrefinery.com>
Wed, 28 Nov 2012 22:55:35 +0000 (23:55 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 29 Nov 2012 07:43:12 +0000 (08:43 +0100)
Currently, channel IDs exceeding 31 (0x1f) cannot be used.
The channel ID is derived from the cmask. Extending cmask
to a 64-bit type would only allow it to go up to 63 (0x3f).
Some devices have channel IDs exceeding that as well.
To address that, add an offset to the mixer element which
is then accounted for in the UAC set/get functions.

Signed-off-by: Eldad Zack <eldad@fogrefinery.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/mixer.c
sound/usb/mixer.h
sound/usb/mixer_quirks.c

index 298070e8f2d4e354da19dbca3e3d704a7b799321..b0fc6ae037a220d9f5524c326104208f21b529c5 100644 (file)
@@ -382,6 +382,8 @@ error:
 
 static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
 {
+       validx += cval->idx_off;
+
        return (cval->mixer->protocol == UAC_VERSION_1) ?
                get_ctl_value_v1(cval, request, validx, value_ret) :
                get_ctl_value_v2(cval, request, validx, value_ret);
@@ -432,6 +434,8 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
        unsigned char buf[2];
        int idx = 0, val_len, err, timeout = 10;
 
+       validx += cval->idx_off;
+
        if (cval->mixer->protocol == UAC_VERSION_1) {
                val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
        } else { /* UAC_VERSION_2 */
index a7f3d45a8acf1f6255a86f88038ca64012069137..aab80df201bdde8f6015d9b2451abb0c24efddb7 100644 (file)
@@ -43,6 +43,7 @@ struct usb_mixer_elem_info {
        unsigned int id;
        unsigned int control;   /* CS or ICN (high byte) */
        unsigned int cmask; /* channel mask bitmap: 0 = master */
+       unsigned int idx_off; /* Control index offset */
        unsigned int ch_readonly;
        unsigned int master_readonly;
        int channels;
index ae2b7143522097bffd2a6060721d4f3db6b8000e..4199b97e76a122581c145957c622e4e5448b5fda 100644 (file)
@@ -63,11 +63,12 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
  * Since there doesn't seem to be a devices that needs a multichannel
  * version, we keep it mono for simplicity.
  */
-static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
+static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
                                unsigned int unitid,
                                unsigned int control,
                                unsigned int cmask,
                                int val_type,
+                               unsigned int idx_off,
                                const char *name,
                                snd_kcontrol_tlv_rw_t *tlv_callback)
 {
@@ -85,6 +86,7 @@ static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
        cval->channels = 1;
        cval->control = control;
        cval->cmask = cmask;
+       cval->idx_off = idx_off;
 
        /* get_min_max() is called only for integer volumes later,
         * so provide a short-cut for booleans */
@@ -120,6 +122,18 @@ static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
        return 0;
 }
 
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
+                               unsigned int unitid,
+                               unsigned int control,
+                               unsigned int cmask,
+                               int val_type,
+                               const char *name,
+                               snd_kcontrol_tlv_rw_t *tlv_callback)
+{
+       return snd_create_std_mono_ctl_offset(mixer, unitid, control, cmask,
+               val_type, 0 /* Offset */, name, tlv_callback);
+}
+
 /*
  * Create a set of standard UAC controls from a table
  */