On Thu, Sep 02, 2010 at 01:13:48PM +0200, Clemens Ladisch wrote:
Daniel Mack wrote:
On Thu, Sep 02, 2010 at 11:12:59AM +0200, Clemens Ladisch wrote:
Also, the Interface Class protocol for the device defaults to Vendor Specific Class, but the driver only recognizes Class 1 or 2. The device is really Class 1, so we have to force it to reflect this. There are 4 places that we need to set this."
Daniel, this seems to be a regression introduced with the UAC2 changes. The old driver accepted vendor-specific interfaces, if some quirk forced it to look at them.
Hmm, I don't follow. What's the problem, and why should that be caused by the UAC2 changes? Sorry, but I seem to have missed that thread.
I've got several reports that devices no longer work since UAC2 support got added. But I've just noticed this is not related to the interface class but to the interface protocol: the new code added checks for UAC_VERSION_1 or _2, but real devices apparently write just random junk into this field. (For vendor-specific interfaces, they are actually justified to do so.)
Grr. So what about cases where this "random junk" is 0x20 by coincidence?
We need something like the following (untested), unless you have a better idea:
We could also fix up such devices with quirks tables, but your approach is probably better as it catches all devices right away.
Thanks, Daniel
diff --git a/sound/usb/card.c b/sound/usb/card.c index 9feb00c..d5141a1 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -216,6 +216,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) }
switch (protocol) {
- default:
snd_printdd(KERN_WARN "unknown interface protocol %#02x, assuming v1\n");
/* fall through */
- case UAC_VERSION_1: { struct uac1_ac_header_descriptor *h1 = control_header;
@@ -253,10 +257,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;
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index b853f8d..7754a10 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -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;
}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index bb9f938..22589b5 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -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_WARN "%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);
@@ -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 */
diff --git a/sound/usb/format.c b/sound/usb/format.c index 4387f54..2ec73dd 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -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;
@@ -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;
@@ -385,6 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, */ switch (protocol) { case UAC_VERSION_1:
- default: fp->channels = fmt->bNrChannels; ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7); break;
@@ -434,7 +433,8 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, fp->channels = 1;
switch (protocol) {
- case UAC_VERSION_1: {
- case UAC_VERSION_1:
- default: { struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; brate = le16_to_cpu(fmt->wMaxBitRate); framesize = le16_to_cpu(fmt->wSamplesPerFrame);
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c166db0..0478fa3 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -365,7 +365,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) {
- return (cval->mixer->protocol == UAC_VERSION_1) ?
- return (cval->mixer->protocol != UAC_VERSION_2) ? get_ctl_value_v1(cval, request, validx, value_ret) : get_ctl_value_v2(cval, request, validx, value_ret);
} @@ -415,7 +415,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, unsigned char buf[2]; int val_len, timeout = 10;
- if (cval->mixer->protocol == UAC_VERSION_1) {
- if (cval->mixer->protocol != UAC_VERSION_2) { val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1; } else { /* UAC_VERSION_2 */ /* audio class v2 controls are always 2 bytes in size */
@@ -642,7 +642,7 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ term->id = id; switch (hdr[2]) { case UAC_INPUT_TERMINAL:
if (state->mixer->protocol == UAC_VERSION_1) {
if (state->mixer->protocol != UAC_VERSION_2) { struct uac_input_terminal_descriptor *d = p1; term->type = le16_to_cpu(d->wTerminalType); term->channels = d->bNrChannels;
@@ -1159,7 +1159,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void struct uac_feature_unit_descriptor *hdr = _ftr; __u8 *bmaControls;
- if (state->mixer->protocol == UAC_VERSION_1) {
- if (state->mixer->protocol != UAC_VERSION_2) { csize = hdr->bControlSize; channels = (hdr->bLength - 7) / csize - 1; bmaControls = hdr->bmaControls;
@@ -1198,7 +1198,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void else first_ch_bits = 0;
- if (state->mixer->protocol == UAC_VERSION_1) {
- if (state->mixer->protocol != UAC_VERSION_2) { /* check all control types */ for (i = 0; i < 10; i++) { unsigned int ch_bits = 0;
@@ -1865,13 +1865,13 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) return parse_audio_feature_unit(state, unitid, p1); case UAC1_PROCESSING_UNIT: /* UAC2_EFFECT_UNIT has the same value */
if (state->mixer->protocol == UAC_VERSION_1)
else return 0; /* FIXME - effect units not implemented yet */ case UAC1_EXTENSION_UNIT: /* UAC2_PROCESSING_UNIT_V2 has the same value */if (state->mixer->protocol != UAC_VERSION_2) return parse_audio_processing_unit(state, unitid, p1);
if (state->mixer->protocol == UAC_VERSION_1)
else /* UAC_VERSION_2 */ return parse_audio_processing_unit(state, unitid, p1);if (state->mixer->protocol != UAC_VERSION_2) return parse_audio_extension_unit(state, unitid, p1);
@@ -1932,7 +1932,7 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
p = NULL; while ((p = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, p, UAC_OUTPUT_TERMINAL)) != NULL) {
if (mixer->protocol == UAC_VERSION_1) {
if (mixer->protocol != UAC_VERSION_2) { struct uac1_output_terminal_descriptor *desc = p; if (desc->bLength < sizeof(*desc))
@@ -2070,7 +2070,7 @@ static void snd_usb_mixer_interrupt(struct urb *urb) if (urb->status != 0) goto requeue;
- if (mixer->protocol == UAC_VERSION_1) {
if (mixer->protocol != UAC_VERSION_2) { struct uac1_status_word *status;
for (status = urb->transfer_buffer;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3634ced..3b5135c 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -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;
}
/*