Commit 2e43aae2 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: usb-audio: Check implicit feedback EP generically for UAC2

It seems that many UAC2 devices are with the implicit feedback, but
they couldn't be probed properly because the assumption the driver
takes currently isn't applied: they have the single endpoint for both
data and implicit-fb streams, while we checked only the classical sync
endpoints assigned to the next altsetting in the same interface.

This patch extends the search to match with those typical cases where
the implicit fb stream is found in the next interface number.

While we're at it, slightly refactor the code, not returning 0/-ERROR
but use the standard bool to success/failur, which is more intuitive
in this particular case.
Reported-by: default avatarDylan Robinson <dylan_robinson@motu.com>
Tested-by: default avatarKeith Milner <kamilner@superlative.org>
Tested-by: default avatarDylan Robinson <dylan_robinson@motu.com>
Link: https://lore.kernel.org/r/20201123085347.19667-5-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 93db51d0
......@@ -272,33 +272,70 @@ static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream)
return 0;
}
static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
unsigned int altsetting,
struct usb_host_interface **alts,
unsigned int *ep)
/* Check whether the given iface:altsetting points to an implicit fb source */
static bool search_generic_implicit_fb(struct usb_device *dev, int ifnum,
unsigned int altsetting,
struct usb_host_interface **altsp,
unsigned int *ep)
{
struct usb_interface *iface;
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
struct usb_endpoint_descriptor *epd;
iface = usb_ifnum_to_if(dev, ifnum);
if (!iface)
return false;
alts = usb_altnum_to_altsetting(iface, altsetting);
if (!alts)
return false;
altsd = get_iface_desc(alts);
if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING ||
altsd->bInterfaceProtocol != UAC_VERSION_2 ||
altsd->bNumEndpoints < 1)
return false;
epd = get_endpoint(alts, 0);
if (!usb_endpoint_is_isoc_in(epd) ||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_IMPLICIT_FB)
return false;
*ep = epd->bEndpointAddress;
*altsp = alts;
return true;
}
/* Like the function above, but specific to Roland with vendor class and hack */
static bool search_roland_implicit_fb(struct usb_device *dev, int ifnum,
unsigned int altsetting,
struct usb_host_interface **altsp,
unsigned int *ep)
{
struct usb_interface *iface;
struct usb_host_interface *alts;
struct usb_interface_descriptor *altsd;
struct usb_endpoint_descriptor *epd;
iface = usb_ifnum_to_if(dev, ifnum);
if (!iface || iface->num_altsetting < altsetting + 1)
return -ENOENT;
*alts = &iface->altsetting[altsetting];
altsd = get_iface_desc(*alts);
if (altsd->bAlternateSetting != altsetting ||
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
if (!iface)
return false;
alts = usb_altnum_to_altsetting(iface, altsetting);
if (!alts)
return false;
altsd = get_iface_desc(alts);
if (altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
(altsd->bInterfaceSubClass != 2 &&
altsd->bInterfaceProtocol != 2 ) ||
altsd->bInterfaceProtocol != 2) ||
altsd->bNumEndpoints < 1)
return -ENOENT;
epd = get_endpoint(*alts, 0);
return false;
epd = get_endpoint(alts, 0);
if (!usb_endpoint_is_isoc_in(epd) ||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_IMPLICIT_FB)
return -ENOENT;
return false;
*ep = epd->bEndpointAddress;
return 0;
*altsp = alts;
return true;
}
/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk
......@@ -375,6 +412,19 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
return 0;
}
/* Generic UAC2 implicit feedback */
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
altsd->bInterfaceClass == USB_CLASS_AUDIO &&
altsd->bInterfaceProtocol == UAC_VERSION_2 &&
altsd->bNumEndpoints == 1) {
ifnum = altsd->bInterfaceNumber + 1;
if (search_generic_implicit_fb(dev, ifnum,
altsd->bAlternateSetting,
&alts, &ep))
goto add_sync_ep;
}
/* Roland/BOSS implicit feedback with vendor spec class */
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
altsd->bInterfaceProtocol == 2 &&
......@@ -382,9 +432,8 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
altsd->bAlternateSetting,
&alts, &ep) >= 0) {
&alts, &ep))
goto add_sync_ep;
}
/* No quirk */
return 0;
......
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