__u8  iFeature;                                         \
 } __attribute__ ((packed))
 
+/* 4.3.2.3 Mixer Unit Descriptor */
+struct uac_mixer_unit_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bUnitID;
+       __u8 bNrInPins;
+       __u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_mixer_unit_bNrChannels(struct uac_mixer_unit_descriptor *desc)
+{
+       return desc->baSourceID[desc->bNrInPins];
+}
+
+static inline __u16 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc)
+{
+       return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+               desc->baSourceID[desc->bNrInPins + 1];
+}
+
+static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc)
+{
+       return desc->baSourceID[desc->bNrInPins + 3];
+}
+
+static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc)
+{
+       return &desc->baSourceID[desc->bNrInPins + 4];
+}
+
+static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc)
+{
+       __u8 *raw = (__u8 *) desc;
+       return raw[desc->bLength - 1];
+}
+
+/* 4.3.2.4 Selector Unit Descriptor */
+struct uac_selector_unit_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bUintID;
+       __u8 bNrInPins;
+       __u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
+{
+       __u8 *raw = (__u8 *) desc;
+       return raw[desc->bLength - 1];
+}
+
+/* 4.3.2.5 Feature Unit Descriptor */
+struct uac_feature_unit_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bUnitID;
+       __u8 bSourceID;
+       __u8 bControlSize;
+       __u8 bmaControls[0]; /* variable length */
+} __attribute__((packed));
+
+static inline __u8 uac_feature_unit_iFeature(struct uac_feature_unit_descriptor *desc)
+{
+       __u8 *raw = (__u8 *) desc;
+       return raw[desc->bLength - 1];
+}
+
+/* 4.3.2.6 Processing Unit Descriptors */
+struct uac_processing_unit_descriptor {
+       __u8 bLength;
+       __u8 bDescriptorType;
+       __u8 bDescriptorSubtype;
+       __u8 bUnitID;
+       __u16 wProcessType;
+       __u8 bNrInPins;
+       __u8 baSourceID[];
+} __attribute__ ((packed));
+
+static inline __u8 uac_processing_unit_bNrChannels(struct uac_processing_unit_descriptor *desc)
+{
+       return desc->baSourceID[desc->bNrInPins];
+}
+
+static inline __u16 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc)
+{
+       return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
+               desc->baSourceID[desc->bNrInPins + 1];
+}
+
+static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc)
+{
+       return desc->baSourceID[desc->bNrInPins + 3];
+}
+
+static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc)
+{
+       return desc->baSourceID[desc->bNrInPins + 4];
+}
+
+static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc)
+{
+       return &desc->baSourceID[desc->bNrInPins + 5];
+}
+
+static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc)
+{
+       __u8 control_size = uac_processing_unit_bControlSize(desc);
+       return desc->baSourceID[desc->bNrInPins + control_size];
+}
+
+static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc)
+{
+       __u8 control_size = uac_processing_unit_bControlSize(desc);
+       return &desc->baSourceID[desc->bNrInPins + control_size + 1];
+}
+
 /* 4.5.2 Class-Specific AS Interface Descriptor */
 struct uac_as_header_descriptor_v1 {
        __u8  bLength;                  /* in bytes: 7 */
 
 /* A.10.2 Feature Unit Control Selectors */
 
-struct uac_feature_unit_descriptor {
-       __u8 bLength;
-       __u8 bDescriptorType;
-       __u8 bDescriptorSubtype;
-       __u8 bUnitID;
-       __u8 bSourceID;
-       __u8 bControlSize;
-       __u8 controls[0]; /* variable length */
-} __attribute__((packed));
-
 #define UAC_FU_CONTROL_UNDEFINED       0x00
 #define UAC_MUTE_CONTROL               0x01
 #define UAC_VOLUME_CONTROL             0x02
 
        return strlcat(kctl->id.name, str, sizeof(kctl->id.name));
 }
 
-static void build_feature_ctl(struct mixer_build *state, unsigned char *desc,
+static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
                              unsigned int ctl_mask, int control,
                              struct usb_audio_term *iterm, int unitid)
 {
+       struct uac_feature_unit_descriptor *desc = raw_desc;
        unsigned int len = 0;
        int mapped_name = 0;
-       int nameid = desc[desc[0] - 1];
+       int nameid = uac_feature_unit_iFeature(desc);
        struct snd_kcontrol *kctl;
        struct usb_mixer_elem_info *cval;
        const struct usbmix_name_map *map;
 
        channels = (ftr->bLength - 7) / csize - 1;
 
-       master_bits = snd_usb_combine_bytes(ftr->controls, csize);
+       master_bits = snd_usb_combine_bytes(ftr->bmaControls, csize);
        /* master configuration quirks */
        switch (state->chip->usb_id) {
        case USB_ID(0x08bb, 0x2702):
                break;
        }
        if (channels > 0)
-               first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize);
+               first_ch_bits = snd_usb_combine_bytes(ftr->bmaControls + csize, csize);
        else
                first_ch_bits = 0;
        /* check all control types */
        for (i = 0; i < 10; i++) {
                unsigned int ch_bits = 0;
                for (j = 0; j < channels; j++) {
-                       unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize);
+                       unsigned int mask = snd_usb_combine_bytes(ftr->bmaControls + csize * (j+1), csize);
                        if (mask & (1 << i))
                                ch_bits |= (1 << j);
                }
  * input channel number (zero based) is given in control field instead.
  */
 
-static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc,
+static void build_mixer_unit_ctl(struct mixer_build *state,
+                                struct uac_mixer_unit_descriptor *desc,
                                 int in_pin, int in_ch, int unitid,
                                 struct usb_audio_term *iterm)
 {
        struct usb_mixer_elem_info *cval;
-       unsigned int input_pins = desc[4];
-       unsigned int num_outs = desc[5 + input_pins];
+       unsigned int num_outs = uac_mixer_unit_bNrChannels(desc);
        unsigned int i, len;
        struct snd_kcontrol *kctl;
        const struct usbmix_name_map *map;
        cval->control = in_ch + 1; /* based on 1 */
        cval->val_type = USB_MIXER_S16;
        for (i = 0; i < num_outs; i++) {
-               if (check_matrix_bitmap(desc + 9 + input_pins, in_ch, i, num_outs)) {
+               if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc), in_ch, i, num_outs)) {
                        cval->cmask |= (1 << i);
                        cval->channels++;
                }
 /*
  * parse a mixer unit
  */
-static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, unsigned char *desc)
+static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *raw_desc)
 {
+       struct uac_mixer_unit_descriptor *desc = raw_desc;
        struct usb_audio_term iterm;
        int input_pins, num_ins, num_outs;
        int pin, ich, err;
 
-       if (desc[0] < 11 || ! (input_pins = desc[4]) || ! (num_outs = desc[5 + input_pins])) {
+       if (desc->bLength < 11 || ! (input_pins = desc->bNrInPins) || ! (num_outs = uac_mixer_unit_bNrChannels(desc))) {
                snd_printk(KERN_ERR "invalid MIXER UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
        /* no bmControls field (e.g. Maya44) -> ignore */
-       if (desc[0] <= 10 + input_pins) {
+       if (desc->bLength <= 10 + input_pins) {
                snd_printdd(KERN_INFO "MU %d has no bmControls field\n", unitid);
                return 0;
        }
        num_ins = 0;
        ich = 0;
        for (pin = 0; pin < input_pins; pin++) {
-               err = parse_audio_unit(state, desc[5 + pin]);
+               err = parse_audio_unit(state, desc->baSourceID[pin]);
                if (err < 0)
                        return err;
-               err = check_input_term(state, desc[5 + pin], &iterm);
+               err = check_input_term(state, desc->baSourceID[pin], &iterm);
                if (err < 0)
                        return err;
                num_ins += iterm.channels;
                        int och, ich_has_controls = 0;
 
                        for (och = 0; och < num_outs; ++och) {
-                               if (check_matrix_bitmap(desc + 9 + input_pins,
+                               if (check_matrix_bitmap(uac_mixer_unit_bmControls(desc),
                                                        ich, och, num_outs)) {
                                        ich_has_controls = 1;
                                        break;
 /*
  * build a processing/extension unit
  */
-static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned char *dsc, struct procunit_info *list, char *name)
+static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw_desc, struct procunit_info *list, char *name)
 {
-       int num_ins = dsc[6];
+       struct uac_processing_unit_descriptor *desc = raw_desc;
+       int num_ins = desc->bNrInPins;
        struct usb_mixer_elem_info *cval;
        struct snd_kcontrol *kctl;
        int i, err, nameid, type, len;
                0, NULL, default_value_info
        };
 
-       if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) {
+       if (desc->bLength < 13 || desc->bLength < 13 + num_ins || desc->bLength < num_ins + uac_processing_unit_bControlSize(desc)) {
                snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);
                return -EINVAL;
        }
 
        for (i = 0; i < num_ins; i++) {
-               if ((err = parse_audio_unit(state, dsc[7 + i])) < 0)
+               if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)
                        return err;
        }
 
-       type = combine_word(&dsc[4]);
+       type = le16_to_cpu(desc->wProcessType);
        for (info = list; info && info->type; info++)
                if (info->type == type)
                        break;
                info = &default_info;
 
        for (valinfo = info->values; valinfo->control; valinfo++) {
-               /* FIXME: bitmap might be longer than 8bit */
-               if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1))))
+               __u8 *controls = uac_processing_unit_bmControls(desc);
+
+               if (! (controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1))))
                        continue;
                map = find_map(state, unitid, valinfo->control);
                if (check_ignored_ctl(map))
 
                /* get min/max values */
                if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) {
+                       __u8 *control_spec = uac_processing_unit_specific(desc);
                        /* FIXME: hard-coded */
                        cval->min = 1;
-                       cval->max = dsc[15];
+                       cval->max = control_spec[0];
                        cval->res = 1;
                        cval->initialized = 1;
                } else {
                else if (info->name)
                        strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
                else {
-                       nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
+                       nameid = uac_processing_unit_iProcessing(desc);
                        len = 0;
                        if (nameid)
                                len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
 }
 
 
-static int parse_audio_processing_unit(struct mixer_build *state, int unitid, unsigned char *desc)
+static int parse_audio_processing_unit(struct mixer_build *state, int unitid, void *raw_desc)
 {
-       return build_audio_procunit(state, unitid, desc, procunits, "Processing Unit");
+       return build_audio_procunit(state, unitid, raw_desc, procunits, "Processing Unit");
 }
 
-static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc)
+static int parse_audio_extension_unit(struct mixer_build *state, int unitid, void *raw_desc)
 {
-       return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit");
+       /* Note that we parse extension units with processing unit descriptors.
+        * That's ok as the layout is the same */
+       return build_audio_procunit(state, unitid, raw_desc, extunits, "Extension Unit");
 }
 
 
 /*
  * parse a selector unit
  */
-static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsigned char *desc)
+static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void *raw_desc)
 {
-       unsigned int num_ins = desc[4];
+       struct uac_selector_unit_descriptor *desc = raw_desc;
        unsigned int i, nameid, len;
        int err;
        struct usb_mixer_elem_info *cval;
        const struct usbmix_name_map *map;
        char **namelist;
 
-       if (! num_ins || desc[0] < 5 + num_ins) {
+       if (!desc->bNrInPins || desc->bLength < 5 + desc->bNrInPins) {
                snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid);
                return -EINVAL;
        }
 
-       for (i = 0; i < num_ins; i++) {
-               if ((err = parse_audio_unit(state, desc[5 + i])) < 0)
+       for (i = 0; i < desc->bNrInPins; i++) {
+               if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0)
                        return err;
        }
 
-       if (num_ins == 1) /* only one ? nonsense! */
+       if (desc->bNrInPins == 1) /* only one ? nonsense! */
                return 0;
 
        map = find_map(state, unitid, 0);
        cval->val_type = USB_MIXER_U8;
        cval->channels = 1;
        cval->min = 1;
-       cval->max = num_ins;
+       cval->max = desc->bNrInPins;
        cval->res = 1;
        cval->initialized = 1;
 
-       namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL);
+       namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
        if (! namelist) {
                snd_printk(KERN_ERR "cannot malloc\n");
                kfree(cval);
                return -ENOMEM;
        }
 #define MAX_ITEM_NAME_LEN      64
-       for (i = 0; i < num_ins; i++) {
+       for (i = 0; i < desc->bNrInPins; i++) {
                struct usb_audio_term iterm;
                len = 0;
                namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
                }
                len = check_mapped_selector_name(state, unitid, i, namelist[i],
                                                 MAX_ITEM_NAME_LEN);
-               if (! len && check_input_term(state, desc[5 + i], &iterm) >= 0)
+               if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0)
                        len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0);
                if (! len)
                        sprintf(namelist[i], "Input %d", i);
        kctl->private_value = (unsigned long)namelist;
        kctl->private_free = usb_mixer_selector_elem_free;
 
-       nameid = desc[desc[0] - 1];
+       nameid = uac_selector_unit_iSelector(desc);
        len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
        if (len)
                ;
        }
 
        snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
-                   cval->id, kctl->id.name, num_ins);
+                   cval->id, kctl->id.name, desc->bNrInPins);
        if ((err = add_control_to_empty(state, kctl)) < 0)
                return err;