mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	ALSA: usb-audio: Clean up check_input_term()
The primary changes in this patch are cleanups of __check_input_term() and move to a non-nested switch-case block by evaluating the pair of UAC version and the unit type, as we've done for parse_audio_unit(). Also each parser is split into the function for readability. Now, a slight behavior change by this cleanup is the handling of processing and extension units. Formerly we've dealt with them differently between UAC1/2 and UAC3; the latter returns an error if no input sources are available, while the former continues to parse. In this patch, unify the behavior in all cases: when input sources are available, it parses recursively, then override the type and the id, as well as channel information if not provided yet. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									744f51e863
								
							
						
					
					
						commit
						e0ccdef926
					
				
					 1 changed files with 212 additions and 195 deletions
				
			
		| 
						 | 
				
			
			@ -758,151 +758,62 @@ static int uac_mixer_unit_get_channels(struct mixer_build *state,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * parse the source unit recursively until it reaches to a terminal
 | 
			
		||||
 * or a branched unit.
 | 
			
		||||
 * Parse Input Terminal Unit
 | 
			
		||||
 */
 | 
			
		||||
static int __check_input_term(struct mixer_build *state, int id,
 | 
			
		||||
			    struct usb_audio_term *term)
 | 
			
		||||
			      struct usb_audio_term *term);
 | 
			
		||||
 | 
			
		||||
static int parse_term_uac1_iterm_unit(struct mixer_build *state,
 | 
			
		||||
				      struct usb_audio_term *term,
 | 
			
		||||
				      void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	int protocol = state->mixer->protocol;
 | 
			
		||||
	int err;
 | 
			
		||||
	void *p1;
 | 
			
		||||
	unsigned char *hdr;
 | 
			
		||||
 | 
			
		||||
	memset(term, 0, sizeof(*term));
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		/* a loop in the terminal chain? */
 | 
			
		||||
		if (test_and_set_bit(id, state->termbitmap))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
		p1 = find_audio_control_unit(state, id);
 | 
			
		||||
		if (!p1)
 | 
			
		||||
			break;
 | 
			
		||||
		if (!snd_usb_validate_audio_desc(p1, protocol))
 | 
			
		||||
			break; /* bad descriptor */
 | 
			
		||||
 | 
			
		||||
		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;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
					/* call recursively to verify that the
 | 
			
		||||
					 * referenced clock entity is valid */
 | 
			
		||||
static int parse_term_uac2_iterm_unit(struct mixer_build *state,
 | 
			
		||||
				      struct usb_audio_term *term,
 | 
			
		||||
				      void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac2_input_terminal_descriptor *d = p1;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* call recursively to verify the referenced clock entity */
 | 
			
		||||
	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 */
 | 
			
		||||
	 * 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: {
 | 
			
		||||
static int parse_term_uac3_iterm_unit(struct mixer_build *state,
 | 
			
		||||
				      struct usb_audio_term *term,
 | 
			
		||||
				      void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac3_input_terminal_descriptor *d = p1;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
				/* call recursively to verify that the
 | 
			
		||||
				 * referenced clock entity is valid */
 | 
			
		||||
	/* call recursively to verify the referenced clock entity */
 | 
			
		||||
	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 */
 | 
			
		||||
	 * to ensure they are not overriden by the recursion calls
 | 
			
		||||
	 */
 | 
			
		||||
	term->id = id;
 | 
			
		||||
	term->type = le16_to_cpu(d->wTerminalType);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -917,13 +828,91 @@ static int __check_input_term(struct mixer_build *state, int id,
 | 
			
		|||
	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 */
 | 
			
		||||
static int parse_term_mixer_unit(struct mixer_build *state,
 | 
			
		||||
				 struct usb_audio_term *term,
 | 
			
		||||
				 void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac_mixer_unit_descriptor *d = p1;
 | 
			
		||||
	int protocol = state->mixer->protocol;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	err = uac_mixer_unit_get_channels(state, d);
 | 
			
		||||
	if (err <= 0)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
 | 
			
		||||
	term->channels = err;
 | 
			
		||||
	if (protocol != UAC_VERSION_3) {
 | 
			
		||||
		term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol);
 | 
			
		||||
		term->name = uac_mixer_unit_iMixer(d);
 | 
			
		||||
	}
 | 
			
		||||
			case UAC3_CLOCK_SOURCE: {
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_term_selector_unit(struct mixer_build *state,
 | 
			
		||||
				    struct usb_audio_term *term,
 | 
			
		||||
				    void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac_selector_unit_descriptor *d = p1;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
	if (state->mixer->protocol != UAC_VERSION_3)
 | 
			
		||||
		term->name = uac_selector_unit_iSelector(d);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_term_proc_unit(struct mixer_build *state,
 | 
			
		||||
				struct usb_audio_term *term,
 | 
			
		||||
				void *p1, int id, int vtype)
 | 
			
		||||
{
 | 
			
		||||
	struct uac_processing_unit_descriptor *d = p1;
 | 
			
		||||
	int protocol = state->mixer->protocol;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	if (d->bNrInPins) {
 | 
			
		||||
		/* call recursively to retrieve the channel info */
 | 
			
		||||
		err = __check_input_term(state, d->baSourceID[0], term);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	term->type = vtype << 16; /* virtual type */
 | 
			
		||||
	term->id = id;
 | 
			
		||||
 | 
			
		||||
	if (protocol == UAC_VERSION_3)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	if (!term->channels) {
 | 
			
		||||
		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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_term_uac2_clock_source(struct mixer_build *state,
 | 
			
		||||
					struct usb_audio_term *term,
 | 
			
		||||
					void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac_clock_source_descriptor *d = p1;
 | 
			
		||||
 | 
			
		||||
	term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
 | 
			
		||||
	term->id = id;
 | 
			
		||||
	term->name = d->iClockSource;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_term_uac3_clock_source(struct mixer_build *state,
 | 
			
		||||
					struct usb_audio_term *term,
 | 
			
		||||
					void *p1, int id)
 | 
			
		||||
{
 | 
			
		||||
	struct uac3_clock_source_descriptor *d = p1;
 | 
			
		||||
 | 
			
		||||
	term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
 | 
			
		||||
| 
						 | 
				
			
			@ -931,53 +920,82 @@ static int __check_input_term(struct mixer_build *state, int 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;
 | 
			
		||||
#define PTYPE(a, b)	((a) << 8 | (b))
 | 
			
		||||
 | 
			
		||||
				term->channels = err;
 | 
			
		||||
				term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
 | 
			
		||||
/*
 | 
			
		||||
 * parse the source unit recursively until it reaches to a terminal
 | 
			
		||||
 * or a branched unit.
 | 
			
		||||
 */
 | 
			
		||||
static int __check_input_term(struct mixer_build *state, int id,
 | 
			
		||||
			      struct usb_audio_term *term)
 | 
			
		||||
{
 | 
			
		||||
	int protocol = state->mixer->protocol;
 | 
			
		||||
	void *p1;
 | 
			
		||||
	unsigned char *hdr;
 | 
			
		||||
 | 
			
		||||
				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)
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		/* a loop in the terminal chain? */
 | 
			
		||||
		if (test_and_set_bit(id, state->termbitmap))
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
 | 
			
		||||
				/* call recursively to retrieve the channel info */
 | 
			
		||||
				err = __check_input_term(state, d->baSourceID[0], term);
 | 
			
		||||
				if (err < 0)
 | 
			
		||||
					return err;
 | 
			
		||||
		p1 = find_audio_control_unit(state, id);
 | 
			
		||||
		if (!p1)
 | 
			
		||||
			break;
 | 
			
		||||
		if (!snd_usb_validate_audio_desc(p1, protocol))
 | 
			
		||||
			break; /* bad descriptor */
 | 
			
		||||
 | 
			
		||||
				term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
 | 
			
		||||
		hdr = p1;
 | 
			
		||||
		term->id = id;
 | 
			
		||||
				term->name = 0; /* TODO: UAC3 Class-specific strings */
 | 
			
		||||
 | 
			
		||||
				return 0;
 | 
			
		||||
		switch (PTYPE(protocol, hdr[2])) {
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC_FEATURE_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC_FEATURE_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_FEATURE_UNIT): {
 | 
			
		||||
			/* the header is the same for all versions */
 | 
			
		||||
			struct uac_feature_unit_descriptor *d = p1;
 | 
			
		||||
 | 
			
		||||
			id = d->bSourceID;
 | 
			
		||||
			break; /* continue to parse */
 | 
			
		||||
		}
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL):
 | 
			
		||||
			return parse_term_uac1_iterm_unit(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
 | 
			
		||||
			return parse_term_uac2_iterm_unit(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC_INPUT_TERMINAL):
 | 
			
		||||
			return parse_term_uac3_iterm_unit(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC_MIXER_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC_MIXER_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_MIXER_UNIT):
 | 
			
		||||
			return parse_term_mixer_unit(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC_SELECTOR_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC_SELECTOR_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SELECTOR):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_SELECTOR_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SELECTOR):
 | 
			
		||||
			return parse_term_selector_unit(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC1_PROCESSING_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_PROCESSING_UNIT):
 | 
			
		||||
			return parse_term_proc_unit(state, term, p1, id,
 | 
			
		||||
						    UAC3_PROCESSING_UNIT);
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC2_EFFECT_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_EFFECT_UNIT):
 | 
			
		||||
			return parse_term_proc_unit(state, term, p1, id,
 | 
			
		||||
						    UAC3_EFFECT_UNIT);
 | 
			
		||||
		case PTYPE(UAC_VERSION_1, UAC1_EXTENSION_UNIT):
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2):
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_EXTENSION_UNIT):
 | 
			
		||||
			return parse_term_proc_unit(state, term, p1, id,
 | 
			
		||||
						    UAC3_EXTENSION_UNIT);
 | 
			
		||||
		case PTYPE(UAC_VERSION_2, UAC2_CLOCK_SOURCE):
 | 
			
		||||
			return parse_term_uac2_clock_source(state, term, p1, id);
 | 
			
		||||
		case PTYPE(UAC_VERSION_3, UAC3_CLOCK_SOURCE):
 | 
			
		||||
			return parse_term_uac3_clock_source(state, term, p1, id);
 | 
			
		||||
		default:
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	}
 | 
			
		||||
	return -ENODEV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2712,7 +2730,6 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
 | 
			
		|||
		return 0; /* skip invalid unit */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#define PTYPE(a, b)	((a) << 8 | (b))
 | 
			
		||||
	switch (PTYPE(protocol, p1[2])) {
 | 
			
		||||
	case PTYPE(UAC_VERSION_1, UAC_INPUT_TERMINAL):
 | 
			
		||||
	case PTYPE(UAC_VERSION_2, UAC_INPUT_TERMINAL):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue