| From 0b361daf55f495f82aa3800ca2264f4eb2bcaa4a Mon Sep 17 00:00:00 2001 |
| From: Alexander Tsoy <alexander@tsoy.me> |
| Date: Sat, 29 Feb 2020 18:18:15 +0300 |
| Subject: [PATCH] ALSA: usb-audio: Add support for MOTU MicroBook IIc |
| |
| commit 2edb84e3047b93da2f2b234219cdc304df042d9e upstream. |
| |
| MicroBook IIc operates in UAC2 mode by default. This patch addresses |
| several issues with it: |
| |
| - MicroBook II and IIc shares the same USB ID. We can distinguish them |
| by interface class. |
| - MaxPacketsOnly attribute is erroneously set in endpoint descriptors. |
| As a result this card produces noise with all sample rates other than |
| 96 KHz. This also causes issues like IOMMU page faults and other |
| problems with host controller. |
| - Sample rate changes takes more than 2 seconds for this device. Clock |
| validity request returns false during that period, so the clock validity |
| quirk is required. |
| |
| Signed-off-by: Alexander Tsoy <alexander@tsoy.me> |
| Link: https://lore.kernel.org/r/20200229151815.14199-1-alexander@tsoy.me |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/sound/usb/clock.c b/sound/usb/clock.c |
| index a48313dfa967..b118cf97607f 100644 |
| --- a/sound/usb/clock.c |
| +++ b/sound/usb/clock.c |
| @@ -151,16 +151,15 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i |
| return ret; |
| } |
| |
| -/* |
| - * Assume the clock is valid if clock source supports only one single sample |
| - * rate, the terminal is connected directly to it (there is no clock selector) |
| - * and clock type is internal. This is to deal with some Denon DJ controllers |
| - * that always reports that clock is invalid. |
| - */ |
| static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, |
| struct audioformat *fmt, |
| int source_id) |
| { |
| + bool ret = false; |
| + int count; |
| + unsigned char data; |
| + struct usb_device *dev = chip->dev; |
| + |
| if (fmt->protocol == UAC_VERSION_2) { |
| struct uac_clock_source_descriptor *cs_desc = |
| snd_usb_find_clock_source(chip->ctrl_intf, source_id); |
| @@ -168,13 +167,51 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip, |
| if (!cs_desc) |
| return false; |
| |
| - return (fmt->nr_rates == 1 && |
| - (fmt->clock & 0xff) == cs_desc->bClockID && |
| - (cs_desc->bmAttributes & 0x3) != |
| - UAC_CLOCK_SOURCE_TYPE_EXT); |
| + /* |
| + * Assume the clock is valid if clock source supports only one |
| + * single sample rate, the terminal is connected directly to it |
| + * (there is no clock selector) and clock type is internal. |
| + * This is to deal with some Denon DJ controllers that always |
| + * reports that clock is invalid. |
| + */ |
| + if (fmt->nr_rates == 1 && |
| + (fmt->clock & 0xff) == cs_desc->bClockID && |
| + (cs_desc->bmAttributes & 0x3) != |
| + UAC_CLOCK_SOURCE_TYPE_EXT) |
| + return true; |
| + } |
| + |
| + /* |
| + * MOTU MicroBook IIc |
| + * Sample rate changes takes more than 2 seconds for this device. Clock |
| + * validity request returns false during that period. |
| + */ |
| + if (chip->usb_id == USB_ID(0x07fd, 0x0004)) { |
| + count = 0; |
| + |
| + while ((!ret) && (count < 50)) { |
| + int err; |
| + |
| + msleep(100); |
| + |
| + err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, |
| + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
| + UAC2_CS_CONTROL_CLOCK_VALID << 8, |
| + snd_usb_ctrl_intf(chip) | (source_id << 8), |
| + &data, sizeof(data)); |
| + if (err < 0) { |
| + dev_warn(&dev->dev, |
| + "%s(): cannot get clock validity for id %d\n", |
| + __func__, source_id); |
| + return false; |
| + } |
| + |
| + ret = !!data; |
| + count++; |
| + } |
| } |
| |
| - return false; |
| + return ret; |
| } |
| |
| static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, |
| diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c |
| index 4a9fcbd235a0..7eafc387e788 100644 |
| --- a/sound/usb/pcm.c |
| +++ b/sound/usb/pcm.c |
| @@ -344,7 +344,12 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, |
| ep = 0x81; |
| ifnum = 1; |
| goto add_sync_ep_from_ifnum; |
| - case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ |
| + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II/IIc */ |
| + /* MicroBook IIc */ |
| + if (altsd->bInterfaceClass == USB_CLASS_AUDIO) |
| + return 0; |
| + |
| + /* MicroBook II */ |
| ep = 0x84; |
| ifnum = 0; |
| goto add_sync_ep_from_ifnum; |
| diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h |
| index 09484e3b7a11..d561b1c8070f 100644 |
| --- a/sound/usb/quirks-table.h |
| +++ b/sound/usb/quirks-table.h |
| @@ -3492,7 +3492,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), |
| }, |
| /* MOTU Microbook II */ |
| { |
| - USB_DEVICE(0x07fd, 0x0004), |
| + USB_DEVICE_VENDOR_SPEC(0x07fd, 0x0004), |
| .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { |
| .vendor_name = "MOTU", |
| .product_name = "MicroBookII", |
| diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c |
| index bf5083a20b6d..9d11ff742e5f 100644 |
| --- a/sound/usb/quirks.c |
| +++ b/sound/usb/quirks.c |
| @@ -1316,7 +1316,15 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, |
| case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */ |
| return snd_usb_axefx3_boot_quirk(dev); |
| case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II */ |
| - return snd_usb_motu_microbookii_boot_quirk(dev); |
| + /* |
| + * For some reason interface 3 with vendor-spec class is |
| + * detected on MicroBook IIc. |
| + */ |
| + if (get_iface_desc(intf->altsetting)->bInterfaceClass == |
| + USB_CLASS_VENDOR_SPEC && |
| + get_iface_desc(intf->altsetting)->bInterfaceNumber < 3) |
| + return snd_usb_motu_microbookii_boot_quirk(dev); |
| + break; |
| } |
| |
| return 0; |
| @@ -1764,5 +1772,13 @@ void snd_usb_audioformat_attributes_quirk(struct snd_usb_audio *chip, |
| else |
| fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; |
| break; |
| + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook IIc */ |
| + /* |
| + * MaxPacketsOnly attribute is erroneously set in endpoint |
| + * descriptors. As a result this card produces noise with |
| + * all sample rates other than 96 KHz. |
| + */ |
| + fp->attributes &= ~UAC_EP_CS_ATTR_FILL_MAX; |
| + break; |
| } |
| } |
| -- |
| 2.27.0 |
| |