Commit message: ALSA: usb-audio: Avoid access before bLength check in build_audio_procunit()

The parser for the processing unit reads bNrInPins field before the
bLength sanity check, which may lead to an out-of-bound access when a
malformed descriptor is given.  Fix it by assignment after the bLength
check.

Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
CVE: CVE-2019-15927
CWE: CWE-125
Vulnerability description: An issue was discovered in the Linux kernel before 4.20.2. An out-of-bounds access exists in the function build_audio_procunit in the file sound/usb/mixer.c.

Project: linux
File: mixer.c

static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
				    void *_ftr)
{
	int channels, i, j;
	struct usb_audio_term iterm;
	unsigned int master_bits, first_ch_bits;
	int err, csize;
	struct uac_feature_unit_descriptor *hdr = _ftr;
	__u8 *bmaControls;

	if (state->mixer->protocol == UAC_VERSION_1) {
		if (hdr->bLength < 7) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
		csize = hdr->bControlSize;
		if (!csize) {
			usb_audio_dbg(state->chip,
				      "unit %u: invalid bControlSize == 0\n",
				      unitid);
			return -EINVAL;
		}
		channels = (hdr->bLength - 7) / csize - 1;
		bmaControls = hdr->bmaControls;
		if (hdr->bLength < 7 + csize) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
	} else if (state->mixer->protocol == UAC_VERSION_2) {
		struct uac2_feature_unit_descriptor *ftr = _ftr;
		if (hdr->bLength < 6) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
		csize = 4;
		channels = (hdr->bLength - 6) / 4 - 1;
		bmaControls = ftr->bmaControls;
		if (hdr->bLength < 6 + csize) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
	} else { /* UAC_VERSION_3 */
		struct uac3_feature_unit_descriptor *ftr = _ftr;

		if (hdr->bLength < 7) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
		csize = 4;
		channels = (ftr->bLength - 7) / 4 - 1;
		bmaControls = ftr->bmaControls;
		if (hdr->bLength < 7 + csize) {
			usb_audio_err(state->chip,
				      "unit %u: invalid UAC3_FEATURE_UNIT descriptor\n",
				      unitid);
			return -EINVAL;
		}
	}

	/* parse the source unit */
	err = parse_audio_unit(state, hdr->bSourceID);
	if (err < 0)
		return err;

	/* determine the input source type and name */
	err = check_input_term(state, hdr->bSourceID, &iterm);
	if (err < 0)
		return err;

	master_bits = snd_usb_combine_bytes(bmaControls, csize);
	/* master configuration quirks */
	switch (state->chip->usb_id) {
	case USB_ID(0x08bb, 0x2702):
		usb_audio_info(state->chip,
			       "usbmixer: master volume quirk for PCM2702 chip\n");
		/* disable non-functional volume control */
		master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
		break;
	case USB_ID(0x1130, 0xf211):
		usb_audio_info(state->chip,
			       "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n");
		/* disable non-functional volume control */
		channels = 0;
		break;

	}
	if (channels > 0)
		first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize);
	else
		first_ch_bits = 0;

	if (state->mixer->protocol == UAC_VERSION_1) {
		/* check all control types */
		for (i = 0; i < 10; i++) {
			unsigned int ch_bits = 0;
			int control = audio_feature_info[i].control;

			for (j = 0; j < channels; j++) {
				unsigned int mask;

				mask = snd_usb_combine_bytes(bmaControls +
							     csize * (j+1), csize);
				if (mask & (1 << i))
					ch_bits |= (1 << j);
			}
			/* audio class v1 controls are never read-only */

			/*
			 * The first channel must be set
			 * (for ease of programming).
			 */
			if (ch_bits & 1)
				build_feature_ctl(state, _ftr, ch_bits, control,
						  &iterm, unitid, 0);
			if (master_bits & (1 << i))
				build_feature_ctl(state, _ftr, 0, control,
						  &iterm, unitid, 0);
		}
	} else { /* UAC_VERSION_2/3 */
		for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {
			unsigned int ch_bits = 0;
			unsigned int ch_read_only = 0;
			int control = audio_feature_info[i].control;

			for (j = 0; j < channels; j++) {
				unsigned int mask;

				mask = snd_usb_combine_bytes(bmaControls +
							     csize * (j+1), csize);
				if (uac_v2v3_control_is_readable(mask, control)) {
					ch_bits |= (1 << j);
					if (!uac_v2v3_control_is_writeable(mask, control))
						ch_read_only |= (1 << j);
				}
			}

			/*
			 * NOTE: build_feature_ctl() will mark the control
			 * read-only if all channels are marked read-only in
			 * the descriptors. Otherwise, the control will be
			 * reported as writeable, but the driver will not
			 * actually issue a write command for read-only
			 * channels.
			 */

			/*
			 * The first channel must be set
			 * (for ease of programming).
			 */
			if (ch_bits & 1)
				build_feature_ctl(state, _ftr, ch_bits, control,
						  &iterm, unitid, ch_read_only);
			if (uac_v2v3_control_is_readable(master_bits, control))
				build_feature_ctl(state, _ftr, 0, control,
						  &iterm, unitid,
						  !uac_v2v3_control_is_writeable(master_bits,
										 control));
		}
	}

	return 0;
}

Project: linux
File: mixer.c

static int parse_audio_processing_unit(struct mixer_build *state, int unitid,
				       void *raw_desc)
{
	switch (state->mixer->protocol) {
	case UAC_VERSION_1:
	case UAC_VERSION_2:
	default:
		return build_audio_procunit(state, unitid, raw_desc,
				procunits, "Processing Unit");
	case UAC_VERSION_3:
		return build_audio_procunit(state, unitid, raw_desc,
				uac3_procunits, "Processing Unit");
	}
}

Project: linux
File: mixer.c

int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
			 int ignore_error)
{
	static struct snd_device_ops dev_ops = {
		.dev_free = snd_usb_mixer_dev_free
	};
	struct usb_mixer_interface *mixer;
	struct snd_info_entry *entry;
	int err;

	strcpy(chip->card->mixername, "USB Mixer");

	mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
	if (!mixer)
		return -ENOMEM;
	mixer->chip = chip;
	mixer->ignore_ctl_error = ignore_error;
	mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems),
				  GFP_KERNEL);
	if (!mixer->id_elems) {
		kfree(mixer);
		return -ENOMEM;
	}

	mixer->hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
	switch (get_iface_desc(mixer->hostif)->bInterfaceProtocol) {
	case UAC_VERSION_1:
	default:
		mixer->protocol = UAC_VERSION_1;
		break;
	case UAC_VERSION_2:
		mixer->protocol = UAC_VERSION_2;
		break;
	case UAC_VERSION_3:
		mixer->protocol = UAC_VERSION_3;
		break;
	}

	if (mixer->protocol == UAC_VERSION_3 &&
			chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
		err = snd_usb_mixer_controls_badd(mixer, ctrlif);
		if (err < 0)
			goto _error;
	} else {
		err = snd_usb_mixer_controls(mixer);
		if (err < 0)
			goto _error;
	}

	err = snd_usb_mixer_status_create(mixer);
	if (err < 0)
		goto _error;

	err = create_keep_iface_ctl(mixer);
	if (err < 0)
		goto _error;

	snd_usb_mixer_apply_create_quirk(mixer);

	err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops);
	if (err < 0)
		goto _error;

	if (list_empty(&chip->mixer_list) &&
	    !snd_card_proc_new(chip->card, "usbmixer", &entry))
		snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read);

	list_add(&mixer->list, &chip->mixer_list);
	return 0;

_error:
	snd_usb_mixer_free(mixer);
	return err;
}

Project: linux
File: mixer.c

static int check_input_term(struct mixer_build *state, int id,
			    struct usb_audio_term *term)
{
	int protocol = state->mixer->protocol;
	int err;
	void *p1;

	memset(term, 0, sizeof(*term));
	while ((p1 = find_audio_control_unit(state, id)) != NULL) {
		unsigned char *hdr = p1;
		term->id = id;

		if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
			switch (hdr[2]) {
			case UAC_INPUT_TERMINAL:
				if (protocol == UAC_VERSION_1) {
					struct uac_input_terminal_descriptor *d = p1;

					term->type = le16_to_cpu(d->wTerminalType);
					term->channels = d->bNrChannels;
					term->chconfig = le16_to_cpu(d->wChannelConfig);
					term->name = d->iTerminal;
				} else { /* UAC_VERSION_2 */
					struct uac2_input_terminal_descriptor *d = p1;

					/* 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: {
				/* the header is the same for v1 and v2 */
				struct uac_feature_unit_descriptor *d = p1;

				id = d->bSourceID;
				break; /* continue to parse */
			}
			case UAC_MIXER_UNIT: {
				struct uac_mixer_unit_descriptor *d = p1;

				term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
				term->channels = uac_mixer_unit_bNrChannels(d);
				term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol);
				term->name = uac_mixer_unit_iMixer(d);
				return 0;
			}
			case UAC_SELECTOR_UNIT:
			case UAC2_CLOCK_SELECTOR: {
				struct uac_selector_unit_descriptor *d = p1;
				/* call recursively to retrieve the channel info */
				err = check_input_term(state, d->baSourceID[0], term);
				if (err < 0)
					return err;
				term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
				term->id = id;
				term->name = uac_selector_unit_iSelector(d);
				return 0;
			}
			case UAC1_PROCESSING_UNIT:
			/* UAC2_EFFECT_UNIT */
				if (protocol == UAC_VERSION_1)
					term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
				else /* UAC_VERSION_2 */
					term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */
				/* fall through */
			case UAC1_EXTENSION_UNIT:
			/* UAC2_PROCESSING_UNIT_V2 */
				if (protocol == UAC_VERSION_1 && !term->type)
					term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */
				else if (protocol == UAC_VERSION_2 && !term->type)
					term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
				/* fall through */
			case UAC2_EXTENSION_UNIT_V2: {
				struct uac_processing_unit_descriptor *d = p1;

				if (protocol == UAC_VERSION_2 &&
					hdr[2] == UAC2_EFFECT_UNIT) {
					/* UAC2/UAC1 unit IDs overlap here in an
					 * uncompatible way. Ignore this unit for now.
					 */
					return 0;
				}

				if (d->bNrInPins) {
					id = d->baSourceID[0];
					break; /* continue to parse */
				}
				if (!term->type)
					term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */

				term->channels = uac_processing_unit_bNrChannels(d);
				term->chconfig = uac_processing_unit_wChannelConfig(d, protocol);
				term->name = uac_processing_unit_iProcessing(d, protocol);
				return 0;
			}
			case UAC2_CLOCK_SOURCE: {
				struct uac_clock_source_descriptor *d = p1;

				term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
				term->id = id;
				term->name = d->iClockSource;
				return 0;
			}
			default:
				return -ENODEV;
			}
		} else { /* UAC_VERSION_3 */
			switch (hdr[2]) {
			case UAC_INPUT_TERMINAL: {
				struct uac3_input_terminal_descriptor *d = p1;

				/* 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);

				err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID));
				if (err < 0)
					return err;
				term->channels = err;

				/* REVISIT: UAC3 IT doesn't have channels cfg */
				term->chconfig = 0;

				term->name = le16_to_cpu(d->wTerminalDescrStr);
				return 0;
			}
			case UAC3_FEATURE_UNIT: {
				struct uac3_feature_unit_descriptor *d = p1;

				id = d->bSourceID;
				break; /* continue to parse */
			}
			case UAC3_CLOCK_SOURCE: {
				struct uac3_clock_source_descriptor *d = p1;

				term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
				term->id = id;
				term->name = le16_to_cpu(d->wClockSourceStr);
				return 0;
			}
			case UAC3_MIXER_UNIT: {
				struct uac_mixer_unit_descriptor *d = p1;

				err = uac_mixer_unit_get_channels(state, d);
				if (err < 0)
					return err;

				term->channels = err;
				term->type = UAC3_MIXER_UNIT << 16; /* virtual type */

				return 0;
			}
			case UAC3_SELECTOR_UNIT:
			case UAC3_CLOCK_SELECTOR: {
				struct uac_selector_unit_descriptor *d = p1;
				/* call recursively to retrieve the channel info */
				err = check_input_term(state, d->baSourceID[0], term);
				if (err < 0)
					return err;
				term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
				term->id = id;
				term->name = 0; /* TODO: UAC3 Class-specific strings */

				return 0;
			}
			case UAC3_PROCESSING_UNIT: {
				struct uac_processing_unit_descriptor *d = p1;

				if (!d->bNrInPins)
					return -EINVAL;

				/* call recursively to retrieve the channel info */
				err = check_input_term(state, d->baSourceID[0], term);
				if (err < 0)
					return err;

				term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
				term->id = id;
				term->name = 0; /* TODO: UAC3 Class-specific strings */

				return 0;
			}
			default:
				return -ENODEV;
			}
		}
	}
	return -ENODEV;
}

Project: linux
File: mixer.c

static int parse_audio_input_terminal(struct mixer_build *state, int unitid,
				      void *raw_desc)
{
	struct usb_audio_term iterm;
	unsigned int control, bmctls, term_id;

	if (state->mixer->protocol == UAC_VERSION_2) {
		struct uac2_input_terminal_descriptor *d_v2 = raw_desc;
		control = UAC2_TE_CONNECTOR;
		term_id = d_v2->bTerminalID;
		bmctls = le16_to_cpu(d_v2->bmControls);
	} else if (state->mixer->protocol == UAC_VERSION_3) {
		struct uac3_input_terminal_descriptor *d_v3 = raw_desc;
		control = UAC3_TE_INSERTION;
		term_id = d_v3->bTerminalID;
		bmctls = le32_to_cpu(d_v3->bmControls);
	} else {
		return 0; /* UAC1. No Insertion control */
	}

	check_input_term(state, term_id, &iterm);

	/* Check for jack detection. */
	if (uac_v2v3_control_is_readable(bmctls, control))
		build_connector_control(state->mixer, &iterm, true);

	return 0;
}

Project: linux
File: mixer.c

static int build_audio_procunit(struct mixer_build *state, int unitid,
				void *raw_desc, struct procunit_info *list,
				char *name)
{
	struct uac_processing_unit_descriptor *desc = raw_desc;
	int num_ins;
	struct usb_mixer_elem_info *cval;
	struct snd_kcontrol *kctl;
	int i, err, nameid, type, len;
	struct procunit_info *info;
	struct procunit_value_info *valinfo;
	const struct usbmix_name_map *map;
	static struct procunit_value_info default_value_info[] = {
		{ 0x01, "Switch", USB_MIXER_BOOLEAN },
		{ 0 }
	};
	static struct procunit_info default_info = {
		0, NULL, default_value_info
	};

	if (desc->bLength < 13) {
		usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
		return -EINVAL;
	}

	num_ins = desc->bNrInPins;
	if (desc->bLength < 13 + num_ins ||
	    desc->bLength < num_ins + uac_processing_unit_bControlSize(desc, state->mixer->protocol)) {
		usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
		return -EINVAL;
	}

	for (i = 0; i < num_ins; i++) {
		err = parse_audio_unit(state, desc->baSourceID[i]);
		if (err < 0)
			return err;
	}

	type = le16_to_cpu(desc->wProcessType);
	for (info = list; info && info->type; info++)
		if (info->type == type)
			break;
	if (!info || !info->type)
		info = &default_info;

	for (valinfo = info->values; valinfo->control; valinfo++) {
		__u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol);

		if (state->mixer->protocol == UAC_VERSION_1) {
			if (!(controls[valinfo->control / 8] &
					(1 << ((valinfo->control % 8) - 1))))
				continue;
		} else { /* UAC_VERSION_2/3 */
			if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8],
							  valinfo->control))
				continue;
		}

		map = find_map(state->map, unitid, valinfo->control);
		if (check_ignored_ctl(map))
			continue;
		cval = kzalloc(sizeof(*cval), GFP_KERNEL);
		if (!cval)
			return -ENOMEM;
		snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
		cval->control = valinfo->control;
		cval->val_type = valinfo->val_type;
		cval->channels = 1;

		if (state->mixer->protocol > UAC_VERSION_1 &&
		    !uac_v2v3_control_is_writeable(controls[valinfo->control / 8],
						   valinfo->control))
			cval->master_readonly = 1;

		/* get min/max values */
		switch (type) {
		case UAC_PROCESS_UP_DOWNMIX: {
			bool mode_sel = false;

			switch (state->mixer->protocol) {
			case UAC_VERSION_1:
			case UAC_VERSION_2:
			default:
				if (cval->control == UAC_UD_MODE_SELECT)
					mode_sel = true;
				break;
			case UAC_VERSION_3:
				if (cval->control == UAC3_UD_MODE_SELECT)
					mode_sel = true;
				break;
			}

			if (mode_sel) {
				__u8 *control_spec = uac_processing_unit_specific(desc,
								state->mixer->protocol);
				cval->min = 1;
				cval->max = control_spec[0];
				cval->res = 1;
				cval->initialized = 1;
				break;
			}

			get_min_max(cval, valinfo->min_value);
			break;
		}
		case USB_XU_CLOCK_RATE:
			/*
			 * E-Mu USB 0404/0202/TrackerPre/0204
			 * samplerate control quirk
			 */
			cval->min = 0;
			cval->max = 5;
			cval->res = 1;
			cval->initialized = 1;
			break;
		default:
			get_min_max(cval, valinfo->min_value);
			break;
		}

		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
		if (!kctl) {
			kfree(cval);
			return -ENOMEM;
		}
		kctl->private_free = snd_usb_mixer_elem_free;

		if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
			/* nothing */ ;
		} else if (info->name) {
			strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
		} else {
			nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
			len = 0;
			if (nameid)
				len = snd_usb_copy_string_desc(state->chip,
							       nameid,
							       kctl->id.name,
							       sizeof(kctl->id.name));
			if (!len)
				strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
		}
		append_ctl_name(kctl, " ");
		append_ctl_name(kctl, valinfo->suffix);

		usb_audio_dbg(state->chip,
			      "[%d] PU [%s] ch = %d, val = %d/%d\n",
			      cval->head.id, kctl->id.name, cval->channels,
			      cval->min, cval->max);

		err = snd_usb_mixer_add_control(&cval->head, kctl);
		if (err < 0)
			return err;
	}
	return 0;
}

Project: linux
File: mixer.c

static int uac_mixer_unit_get_channels(struct mixer_build *state,
				       struct uac_mixer_unit_descriptor *desc)
{
	int mu_channels;

	if (desc->bLength < 11)
		return -EINVAL;
	if (!desc->bNrInPins)
		return -EINVAL;

	switch (state->mixer->protocol) {
	case UAC_VERSION_1:
	case UAC_VERSION_2:
	default:
		mu_channels = uac_mixer_unit_bNrChannels(desc);
		break;
	case UAC_VERSION_3:
		mu_channels = get_cluster_channels_v3(state,
				uac3_mixer_unit_wClusterDescrID(desc));
		break;
	}

	if (!mu_channels)
		return -EINVAL;

	return mu_channels;
}

Project: linux
File: mixer.c

static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
				      void *raw_desc)
{
	/*
	 * 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");
}

Project: linux
File: mixer.c

static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
				     void *raw_desc)
{
	struct uac_selector_unit_descriptor *desc = raw_desc;
	unsigned int i, nameid, len;
	int err;
	struct usb_mixer_elem_info *cval;
	struct snd_kcontrol *kctl;
	const struct usbmix_name_map *map;
	char **namelist;

	if (desc->bLength < 5 || !desc->bNrInPins ||
	    desc->bLength < 5 + desc->bNrInPins) {
		usb_audio_err(state->chip,
			"invalid SELECTOR UNIT descriptor %d\n", unitid);
		return -EINVAL;
	}

	for (i = 0; i < desc->bNrInPins; i++) {
		err = parse_audio_unit(state, desc->baSourceID[i]);
		if (err < 0)
			return err;
	}

	if (desc->bNrInPins == 1) /* only one ? nonsense! */
		return 0;

	map = find_map(state->map, unitid, 0);
	if (check_ignored_ctl(map))
		return 0;

	cval = kzalloc(sizeof(*cval), GFP_KERNEL);
	if (!cval)
		return -ENOMEM;
	snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
	cval->val_type = USB_MIXER_U8;
	cval->channels = 1;
	cval->min = 1;
	cval->max = desc->bNrInPins;
	cval->res = 1;
	cval->initialized = 1;

	switch (state->mixer->protocol) {
	case UAC_VERSION_1:
	default:
		cval->control = 0;
		break;
	case UAC_VERSION_2:
	case UAC_VERSION_3:
		if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
		    desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
			cval->control = UAC2_CX_CLOCK_SELECTOR;
		else /* UAC2/3_SELECTOR_UNIT */
			cval->control = UAC2_SU_SELECTOR;
		break;
	}

	namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL);
	if (!namelist) {
		kfree(cval);
		return -ENOMEM;
	}
#define MAX_ITEM_NAME_LEN	64
	for (i = 0; i < desc->bNrInPins; i++) {
		struct usb_audio_term iterm;
		len = 0;
		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
		if (!namelist[i]) {
			while (i--)
				kfree(namelist[i]);
			kfree(namelist);
			kfree(cval);
			return -ENOMEM;
		}
		len = check_mapped_selector_name(state, unitid, i, namelist[i],
						 MAX_ITEM_NAME_LEN);
		if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0)
			len = get_term_name(state->chip, &iterm, namelist[i],
					    MAX_ITEM_NAME_LEN, 0);
		if (! len)
			sprintf(namelist[i], "Input %u", i);
	}

	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
	if (! kctl) {
		usb_audio_err(state->chip, "cannot malloc kcontrol\n");
		kfree(namelist);
		kfree(cval);
		return -ENOMEM;
	}
	kctl->private_value = (unsigned long)namelist;
	kctl->private_free = usb_mixer_selector_elem_free;

	/* check the static mapping table at first */
	len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
	if (!len) {
		/* no mapping ? */
		switch (state->mixer->protocol) {
		case UAC_VERSION_1:
		case UAC_VERSION_2:
		default:
		/* if iSelector is given, use it */
			nameid = uac_selector_unit_iSelector(desc);
			if (nameid)
				len = snd_usb_copy_string_desc(state->chip,
							nameid, kctl->id.name,
							sizeof(kctl->id.name));
			break;
		case UAC_VERSION_3:
			/* TODO: Class-Specific strings not yet supported */
			break;
		}

		/* ... or pick up the terminal name at next */
		if (!len)
			len = get_term_name(state->chip, &state->oterm,
				    kctl->id.name, sizeof(kctl->id.name), 0);
		/* ... or use the fixed string "USB" as the last resort */
		if (!len)
			strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));

		/* and add the proper suffix */
		if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
		    desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
			append_ctl_name(kctl, " Clock Source");
		else if ((state->oterm.type & 0xff00) == 0x0100)
			append_ctl_name(kctl, " Capture Source");
		else
			append_ctl_name(kctl, " Playback Source");
	}

	usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
		    cval->head.id, kctl->id.name, desc->bNrInPins);
	return snd_usb_mixer_add_control(&cval->head, kctl);
}

Project: linux
File: mixer.c

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;

	err = uac_mixer_unit_get_channels(state, desc);
	if (err < 0) {
		usb_audio_err(state->chip,
			      "invalid MIXER UNIT descriptor %d\n",
			      unitid);
		return err;
	}

	num_outs = err;
	input_pins = desc->bNrInPins;

	num_ins = 0;
	ich = 0;
	for (pin = 0; pin < input_pins; pin++) {
		err = parse_audio_unit(state, desc->baSourceID[pin]);
		if (err < 0)
			continue;
		/* no bmControls field (e.g. Maya44) -> ignore */
		if (desc->bLength <= 10 + input_pins)
			continue;
		err = check_input_term(state, desc->baSourceID[pin], &iterm);
		if (err < 0)
			return err;
		num_ins += iterm.channels;
		for (; ich < num_ins; ich++) {
			int och, ich_has_controls = 0;

			for (och = 0; och < num_outs; och++) {
				__u8 *c = uac_mixer_unit_bmControls(desc,
						state->mixer->protocol);

				if (check_matrix_bitmap(c, ich, och, num_outs)) {
					ich_has_controls = 1;
					break;
				}
			}
			if (ich_has_controls)
				build_mixer_unit_ctl(state, desc, pin, ich, num_outs,
						     unitid, &iterm);
		}
	}
	return 0;
}