These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / usb / mixer.c
index cd8ed2e..4f85757 100644 (file)
@@ -282,6 +282,21 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
        return val;
 }
 
+static int uac2_ctl_value_size(int val_type)
+{
+       switch (val_type) {
+       case USB_MIXER_S32:
+       case USB_MIXER_U32:
+               return 4;
+       case USB_MIXER_S16:
+       case USB_MIXER_U16:
+               return 2;
+       default:
+               return 1;
+       }
+       return 0; /* unreachable */
+}
+
 
 /*
  * retrieve a mixer value
@@ -296,14 +311,11 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
        int timeout = 10;
        int idx = 0, err;
 
-       err = snd_usb_autoresume(chip);
+       err = snd_usb_lock_shutdown(chip);
        if (err < 0)
                return -EIO;
 
-       down_read(&chip->shutdown_rwsem);
        while (timeout-- > 0) {
-               if (chip->shutdown)
-                       break;
                idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
                if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
                                    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
@@ -319,8 +331,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
        err = -EINVAL;
 
  out:
-       up_read(&chip->shutdown_rwsem);
-       snd_usb_autosuspend(chip);
+       snd_usb_unlock_shutdown(chip);
        return err;
 }
 
@@ -328,14 +339,14 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
                            int validx, int *value_ret)
 {
        struct snd_usb_audio *chip = cval->head.mixer->chip;
-       unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */
+       unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */
        unsigned char *val;
        int idx = 0, ret, size;
        __u8 bRequest;
 
        if (request == UAC_GET_CUR) {
                bRequest = UAC2_CS_CUR;
-               size = sizeof(__u16);
+               size = uac2_ctl_value_size(cval->val_type);
        } else {
                bRequest = UAC2_CS_RANGE;
                size = sizeof(buf);
@@ -343,21 +354,15 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
 
        memset(buf, 0, sizeof(buf));
 
-       ret = snd_usb_autoresume(chip) ? -EIO : 0;
+       ret = snd_usb_lock_shutdown(chip) ? -EIO : 0;
        if (ret)
                goto error;
 
-       down_read(&chip->shutdown_rwsem);
-       if (chip->shutdown) {
-               ret = -ENODEV;
-       } else {
-               idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
-               ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
+       idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
+       ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
                              USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
                              validx, idx, buf, size);
-       }
-       up_read(&chip->shutdown_rwsem);
-       snd_usb_autosuspend(chip);
+       snd_usb_unlock_shutdown(chip);
 
        if (ret < 0) {
 error:
@@ -446,7 +451,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
                                int request, int validx, int value_set)
 {
        struct snd_usb_audio *chip = cval->head.mixer->chip;
-       unsigned char buf[2];
+       unsigned char buf[4];
        int idx = 0, val_len, err, timeout = 10;
 
        validx += cval->idx_off;
@@ -454,8 +459,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
        if (cval->head.mixer->protocol == UAC_VERSION_1) {
                val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
        } else { /* UAC_VERSION_2 */
-               /* audio class v2 controls are always 2 bytes in size */
-               val_len = sizeof(__u16);
+               val_len = uac2_ctl_value_size(cval->val_type);
 
                /* FIXME */
                if (request != UAC_SET_CUR) {
@@ -469,13 +473,14 @@ 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);
+       buf[2] = (value_set >> 16) & 0xff;
+       buf[3] = (value_set >> 24) & 0xff;
+
+       err = snd_usb_lock_shutdown(chip);
        if (err < 0)
                return -EIO;
-       down_read(&chip->shutdown_rwsem);
+
        while (timeout-- > 0) {
-               if (chip->shutdown)
-                       break;
                idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
                if (snd_usb_ctl_msg(chip->dev,
                                    usb_sndctrlpipe(chip->dev, 0), request,
@@ -490,8 +495,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
        err = -EINVAL;
 
  out:
-       up_read(&chip->shutdown_rwsem);
-       snd_usb_autosuspend(chip);
+       snd_usb_unlock_shutdown(chip);
        return err;
 }
 
@@ -715,15 +719,21 @@ static int check_input_term(struct mixer_build *state, int id,
                                term->name = d->iTerminal;
                        } else { /* UAC_VERSION_2 */
                                struct uac2_input_terminal_descriptor *d = p1;
-                               term->type = le16_to_cpu(d->wTerminalType);
-                               term->channels = d->bNrChannels;
-                               term->chconfig = le32_to_cpu(d->bmChannelConfig);
-                               term->name = d->iTerminal;
 
-                               /* call recursively to get the clock selectors */
+                               /* call recursively to verify that the
+                                * referenced clock entity is valid */
                                err = check_input_term(state, d->bCSourceID, term);
                                if (err < 0)
                                        return err;
+
+                               /* save input term properties after recursion,
+                                * to ensure they are not overriden by the
+                                * recursion calls */
+                               term->id = id;
+                               term->type = le16_to_cpu(d->wTerminalType);
+                               term->channels = d->bNrChannels;
+                               term->chconfig = le32_to_cpu(d->bmChannelConfig);
+                               term->name = d->iTerminal;
                        }
                        return 0;
                case UAC_FEATURE_UNIT: {
@@ -798,24 +808,25 @@ static int check_input_term(struct mixer_build *state, int id,
 /* feature unit control information */
 struct usb_feature_control_info {
        const char *name;
-       unsigned int type;      /* control type (mute, volume, etc.) */
+       int type;       /* data type for uac1 */
+       int type_uac2;  /* data type for uac2 if different from uac1, else -1 */
 };
 
 static struct usb_feature_control_info audio_feature_info[] = {
-       { "Mute",                       USB_MIXER_INV_BOOLEAN },
-       { "Volume",                     USB_MIXER_S16 },
-       { "Tone Control - Bass",        USB_MIXER_S8 },
-       { "Tone Control - Mid",         USB_MIXER_S8 },
-       { "Tone Control - Treble",      USB_MIXER_S8 },
-       { "Graphic Equalizer",          USB_MIXER_S8 }, /* FIXME: not implemeted yet */
-       { "Auto Gain Control",          USB_MIXER_BOOLEAN },
-       { "Delay Control",              USB_MIXER_U16 },
-       { "Bass Boost",                 USB_MIXER_BOOLEAN },
-       { "Loudness",                   USB_MIXER_BOOLEAN },
+       { "Mute",                       USB_MIXER_INV_BOOLEAN, -1 },
+       { "Volume",                     USB_MIXER_S16, -1 },
+       { "Tone Control - Bass",        USB_MIXER_S8, -1 },
+       { "Tone Control - Mid",         USB_MIXER_S8, -1 },
+       { "Tone Control - Treble",      USB_MIXER_S8, -1 },
+       { "Graphic Equalizer",          USB_MIXER_S8, -1 }, /* FIXME: not implemeted yet */
+       { "Auto Gain Control",          USB_MIXER_BOOLEAN, -1 },
+       { "Delay Control",              USB_MIXER_U16, USB_MIXER_U32 },
+       { "Bass Boost",                 USB_MIXER_BOOLEAN, -1 },
+       { "Loudness",                   USB_MIXER_BOOLEAN, -1 },
        /* UAC2 specific */
-       { "Input Gain Control",         USB_MIXER_U16 },
-       { "Input Gain Pad Control",     USB_MIXER_BOOLEAN },
-       { "Phase Inverter Control",     USB_MIXER_BOOLEAN },
+       { "Input Gain Control",         USB_MIXER_S16, -1 },
+       { "Input Gain Pad Control",     USB_MIXER_S16, -1 },
+       { "Phase Inverter Control",     USB_MIXER_BOOLEAN, -1 },
 };
 
 /* private_free callback */
@@ -1215,6 +1226,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                              int readonly_mask)
 {
        struct uac_feature_unit_descriptor *desc = raw_desc;
+       struct usb_feature_control_info *ctl_info;
        unsigned int len = 0;
        int mapped_name = 0;
        int nameid = uac_feature_unit_iFeature(desc);
@@ -1240,7 +1252,13 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
        snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
        cval->control = control;
        cval->cmask = ctl_mask;
-       cval->val_type = audio_feature_info[control-1].type;
+       ctl_info = &audio_feature_info[control-1];
+       if (state->mixer->protocol == UAC_VERSION_1)
+               cval->val_type = ctl_info->type;
+       else /* UAC_VERSION_2 */
+               cval->val_type = ctl_info->type_uac2 >= 0 ?
+                       ctl_info->type_uac2 : ctl_info->type;
+
        if (ctl_mask == 0) {
                cval->channels = 1;     /* master channel */
                cval->master_readonly = readonly_mask;
@@ -1336,6 +1354,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                }
        }
 
+       snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl);
+
        range = (cval->max - cval->min) / cval->res;
        /*
         * Are there devices with volume range more than 255? I use a bit more