Commit a2acad82 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Takashi Iwai

ALSA: usb-audio: fix detection of vendor-specific device protocol settings

The Audio Class v2 support code in 2.6.35 added checks for the
bInterfaceProtocol field.  However, there are devices (usually those
detected by vendor-specific quirks) that do not have one of the
predefined values in this field, which made the driver reject them.

To fix this regression, restore the old behaviour, i.e., assume that
a device with an unknown bInterfaceProtocol field (other than
UAC_VERSION_2) has more or less UAC-v1-compatible descriptors.

[compile warning fixes by tiwai]
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
Cc: Daniel Mack <daniel@caiaq.de>
Cc: <stable@kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 7b6717e1
...@@ -216,6 +216,11 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -216,6 +216,11 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
} }
switch (protocol) { switch (protocol) {
default:
snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n",
protocol);
/* fall through */
case UAC_VERSION_1: { case UAC_VERSION_1: {
struct uac1_ac_header_descriptor *h1 = control_header; struct uac1_ac_header_descriptor *h1 = control_header;
...@@ -253,10 +258,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -253,10 +258,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
break; break;
} }
default:
snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol);
return -EINVAL;
} }
return 0; return 0;
......
...@@ -295,12 +295,11 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, ...@@ -295,12 +295,11 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
switch (altsd->bInterfaceProtocol) { switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1: case UAC_VERSION_1:
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate); return set_sample_rate_v1(chip, iface, alts, fmt, rate);
case UAC_VERSION_2: case UAC_VERSION_2:
return set_sample_rate_v2(chip, iface, alts, fmt, rate); return set_sample_rate_v2(chip, iface, alts, fmt, rate);
} }
return -EINVAL;
} }
...@@ -275,6 +275,12 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -275,6 +275,12 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
/* get audio formats */ /* get audio formats */
switch (protocol) { switch (protocol) {
default:
snd_printdd(KERN_WARNING "%d:%u:%d: unknown interface protocol %#02x, assuming v1\n",
dev->devnum, iface_no, altno, protocol);
protocol = UAC_VERSION_1;
/* fall through */
case UAC_VERSION_1: { case UAC_VERSION_1: {
struct uac1_as_header_descriptor *as = struct uac1_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
...@@ -336,11 +342,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -336,11 +342,6 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
dev->devnum, iface_no, altno, as->bTerminalLink); dev->devnum, iface_no, altno, as->bTerminalLink);
continue; continue;
} }
default:
snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n",
dev->devnum, iface_no, altno, protocol);
continue;
} }
/* get format type */ /* get format type */
......
...@@ -49,7 +49,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, ...@@ -49,7 +49,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
u64 pcm_formats; u64 pcm_formats;
switch (protocol) { switch (protocol) {
case UAC_VERSION_1: { case UAC_VERSION_1:
default: {
struct uac_format_type_i_discrete_descriptor *fmt = _fmt; struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
sample_width = fmt->bBitResolution; sample_width = fmt->bBitResolution;
sample_bytes = fmt->bSubframeSize; sample_bytes = fmt->bSubframeSize;
...@@ -64,9 +65,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip, ...@@ -64,9 +65,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
format <<= 1; format <<= 1;
break; break;
} }
default:
return -EINVAL;
} }
pcm_formats = 0; pcm_formats = 0;
...@@ -384,6 +382,10 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, ...@@ -384,6 +382,10 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
* audio class v2 uses class specific EP0 range requests for that. * audio class v2 uses class specific EP0 range requests for that.
*/ */
switch (protocol) { switch (protocol) {
default:
snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
/* fall through */
case UAC_VERSION_1: case UAC_VERSION_1:
fp->channels = fmt->bNrChannels; fp->channels = fmt->bNrChannels;
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
...@@ -392,10 +394,6 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, ...@@ -392,10 +394,6 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
/* fp->channels is already set in this case */ /* fp->channels is already set in this case */
ret = parse_audio_format_rates_v2(chip, fp); ret = parse_audio_format_rates_v2(chip, fp);
break; break;
default:
snd_printk(KERN_ERR "%d:%u:%d : invalid protocol version %d\n",
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
return -EINVAL;
} }
if (fp->channels < 1) { if (fp->channels < 1) {
...@@ -438,6 +436,10 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ...@@ -438,6 +436,10 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
fp->channels = 1; fp->channels = 1;
switch (protocol) { switch (protocol) {
default:
snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
/* fall through */
case UAC_VERSION_1: { case UAC_VERSION_1: {
struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
brate = le16_to_cpu(fmt->wMaxBitRate); brate = le16_to_cpu(fmt->wMaxBitRate);
...@@ -456,10 +458,6 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, ...@@ -456,10 +458,6 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
ret = parse_audio_format_rates_v2(chip, fp); ret = parse_audio_format_rates_v2(chip, fp);
break; break;
} }
default:
snd_printk(KERN_ERR "%d:%u:%d : invalid protocol version %d\n",
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
return -EINVAL;
} }
return ret; return ret;
......
...@@ -2175,7 +2175,15 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, ...@@ -2175,7 +2175,15 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
} }
host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
mixer->protocol = get_iface_desc(host_iface)->bInterfaceProtocol; switch (get_iface_desc(host_iface)->bInterfaceProtocol) {
case UAC_VERSION_1:
default:
mixer->protocol = UAC_VERSION_1;
break;
case UAC_VERSION_2:
mixer->protocol = UAC_VERSION_2;
break;
}
if ((err = snd_usb_mixer_controls(mixer)) < 0 || if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
(err = snd_usb_mixer_status_create(mixer)) < 0) (err = snd_usb_mixer_status_create(mixer)) < 0)
......
...@@ -173,13 +173,12 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, ...@@ -173,13 +173,12 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
switch (altsd->bInterfaceProtocol) { switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1: case UAC_VERSION_1:
default:
return init_pitch_v1(chip, iface, alts, fmt); return init_pitch_v1(chip, iface, alts, fmt);
case UAC_VERSION_2: case UAC_VERSION_2:
return init_pitch_v2(chip, iface, alts, fmt); return init_pitch_v2(chip, iface, alts, fmt);
} }
return -EINVAL;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment