Skip to content

Commit

Permalink
ALSA: usb-audio: fix detection of vendor-specific device protocol set…
Browse files Browse the repository at this point in the history
…tings

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: Clemens Ladisch <clemens@ladisch.de>
Cc: Daniel Mack <daniel@caiaq.de>
Cc: <stable@kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
cladisch authored and tiwai committed Sep 3, 2010
1 parent 7b6717e commit a2acad8
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 26 deletions.
9 changes: 5 additions & 4 deletions sound/usb/card.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}

switch (protocol) {
default:
snd_printdd(KERN_WARNING "unknown interface protocol %#02x, assuming v1\n",
protocol);
/* fall through */

case UAC_VERSION_1: {
struct uac1_ac_header_descriptor *h1 = control_header;

Expand Down Expand Up @@ -253,10 +258,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)

break;
}

default:
snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol);
return -EINVAL;
}

return 0;
Expand Down
3 changes: 1 addition & 2 deletions sound/usb/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,12 +295,11 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,

switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1:
default:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);

case UAC_VERSION_2:
return set_sample_rate_v2(chip, iface, alts, fmt, rate);
}

return -EINVAL;
}

11 changes: 6 additions & 5 deletions sound/usb/endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,12 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)

/* get audio formats */
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: {
struct uac1_as_header_descriptor *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
Expand Down Expand Up @@ -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);
continue;
}

default:
snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n",
dev->devnum, iface_no, altno, protocol);
continue;
}

/* get format type */
Expand Down
22 changes: 10 additions & 12 deletions sound/usb/format.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
u64 pcm_formats;

switch (protocol) {
case UAC_VERSION_1: {
case UAC_VERSION_1:
default: {
struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
sample_width = fmt->bBitResolution;
sample_bytes = fmt->bSubframeSize;
Expand All @@ -64,9 +65,6 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
format <<= 1;
break;
}

default:
return -EINVAL;
}

pcm_formats = 0;
Expand Down Expand Up @@ -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.
*/
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:
fp->channels = fmt->bNrChannels;
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
Expand All @@ -392,10 +394,6 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
/* fp->channels is already set in this case */
ret = parse_audio_format_rates_v2(chip, fp);
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) {
Expand Down Expand Up @@ -438,6 +436,10 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
fp->channels = 1;

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: {
struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
brate = le16_to_cpu(fmt->wMaxBitRate);
Expand All @@ -456,10 +458,6 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
ret = parse_audio_format_rates_v2(chip, fp);
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;
Expand Down
10 changes: 9 additions & 1 deletion sound/usb/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
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 ||
(err = snd_usb_mixer_status_create(mixer)) < 0)
Expand Down
3 changes: 1 addition & 2 deletions sound/usb/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,12 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,

switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1:
default:
return init_pitch_v1(chip, iface, alts, fmt);

case UAC_VERSION_2:
return init_pitch_v2(chip, iface, alts, fmt);
}

return -EINVAL;
}

/*
Expand Down

0 comments on commit a2acad8

Please sign in to comment.