X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=sound%2Fusb%2Fmixer.c;fp=sound%2Fusb%2Fmixer.c;h=ddf66204f8dee742ca956770e61e8a6ffdcf8d08;hb=4bd32b7ba749e007b5e2962e12c13afadee1e193;hp=de8fe209b77299808973d548e274d6cacb022aef;hpb=9c59fb632e3585fe24af1eb2420bafc5884c010d;p=sagit-ice-cold%2Fkernel_xiaomi_msm8998.git diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index de8fe209b772..ddf66204f8de 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -82,6 +82,7 @@ struct mixer_build { unsigned char *buffer; unsigned int buflen; DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS); + DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS); struct usb_audio_term oterm; const struct usbmix_name_map *map; const struct usbmix_selector_map *selector_map; @@ -721,15 +722,24 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm * 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, +static int __check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) { int err; void *p1; + unsigned char *hdr; memset(term, 0, sizeof(*term)); - while ((p1 = find_audio_control_unit(state, id)) != NULL) { - unsigned char *hdr = p1; + 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; + + hdr = p1; term->id = id; switch (hdr[2]) { case UAC_INPUT_TERMINAL: @@ -744,7 +754,7 @@ static int check_input_term(struct mixer_build *state, int id, /* call recursively to verify that the * referenced clock entity is valid */ - err = check_input_term(state, d->bCSourceID, term); + err = __check_input_term(state, d->bCSourceID, term); if (err < 0) return err; @@ -759,8 +769,8 @@ static int check_input_term(struct mixer_build *state, int id, } else { /* UAC_VERSION_3 */ struct uac3_input_terminal_descriptor *d = p1; - err = check_input_term(state, - d->bCSourceID, term); + err = __check_input_term(state, + d->bCSourceID, term); if (err < 0) return err; @@ -817,8 +827,8 @@ static int check_input_term(struct mixer_build *state, int id, } else { struct uac_selector_unit_descriptor *d = p1; /* call recursively to retrieve channel info */ - err = check_input_term(state, - d->baSourceID[0], term); + err = __check_input_term(state, + d->baSourceID[0], term); if (err < 0) return err; /* virtual type */ @@ -881,6 +891,15 @@ static int check_input_term(struct mixer_build *state, int id, return -ENODEV; } + +static int check_input_term(struct mixer_build *state, int id, + struct usb_audio_term *term) +{ + memset(term, 0, sizeof(*term)); + memset(state->termbitmap, 0, sizeof(state->termbitmap)); + return __check_input_term(state, id, term); +} + /* * Feature Unit */ @@ -1886,7 +1905,8 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, NUM_CHANNELS_MONO : NUM_CHANNELS_STEREO; } else { if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || - !(num_outs = uac_mixer_unit_bNrChannels(desc))) { + desc->bLength < sizeof(*desc) + desc->bNrInPins || + !(num_outs = uac_mixer_unit_bNrChannels(desc))) { usb_audio_err(state->chip, "invalid MIXER UNIT descriptor %d\n", unitid);