| From 342cda29343a6272c630f94ed56810a76740251b Mon Sep 17 00:00:00 2001 |
| From: Clemens Ladisch <clemens@ladisch.de> |
| Date: Sat, 15 Jun 2013 11:21:09 +0200 |
| Subject: ALSA: usb-audio: work around Android accessory firmware bug |
| |
| From: Clemens Ladisch <clemens@ladisch.de> |
| |
| commit 342cda29343a6272c630f94ed56810a76740251b upstream. |
| |
| When the Android firmware enables the audio interfaces in accessory |
| mode, it always declares in the control interface's baInterfaceNr array |
| that interfaces 0 and 1 belong to the audio function. However, the |
| accessory interface itself, if also enabled, already is at index 0 and |
| shifts the actual audio interface numbers to 1 and 2, which prevents the |
| PCM streaming interface from being seen by the host driver. |
| |
| To get the PCM interface interface to work, detect when the descriptors |
| point to the (for this driver useless) accessory interface, and redirect |
| to the correct one. |
| |
| Reported-by: Jeremy Rosen <jeremy.rosen@openwide.fr> |
| Tested-by: Jeremy Rosen <jeremy.rosen@openwide.fr> |
| Signed-off-by: Clemens Ladisch <clemens@ladisch.de> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/usb/card.c | 22 ++++++++++++++++++++-- |
| 1 file changed, 20 insertions(+), 2 deletions(-) |
| |
| --- a/sound/usb/card.c |
| +++ b/sound/usb/card.c |
| @@ -149,14 +149,32 @@ static int snd_usb_create_stream(struct |
| return -EINVAL; |
| } |
| |
| + alts = &iface->altsetting[0]; |
| + altsd = get_iface_desc(alts); |
| + |
| + /* |
| + * Android with both accessory and audio interfaces enabled gets the |
| + * interface numbers wrong. |
| + */ |
| + if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) || |
| + chip->usb_id == USB_ID(0x18d1, 0x2d05)) && |
| + interface == 0 && |
| + altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && |
| + altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) { |
| + interface = 2; |
| + iface = usb_ifnum_to_if(dev, interface); |
| + if (!iface) |
| + return -EINVAL; |
| + alts = &iface->altsetting[0]; |
| + altsd = get_iface_desc(alts); |
| + } |
| + |
| if (usb_interface_claimed(iface)) { |
| snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", |
| dev->devnum, ctrlif, interface); |
| return -EINVAL; |
| } |
| |
| - alts = &iface->altsetting[0]; |
| - altsd = get_iface_desc(alts); |
| if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || |
| altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && |
| altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { |