Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c16b5e8 authored by Alexander Tsoy's avatar Alexander Tsoy Committed by Greg Kroah-Hartman
Browse files

ALSA: usb-audio: Add support for MOTU MicroBook IIc



[ Upstream commit 2edb84e3047b93da2f2b234219cdc304df042d9e ]

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: default avatarAlexander Tsoy <alexander@tsoy.me>
Link: https://lore.kernel.org/r/20200229151815.14199-1-alexander@tsoy.me


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent d70a6425
Loading
Loading
Loading
Loading
+48 −11
Original line number Diff line number Diff line
@@ -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,15 +167,53 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
		if (!cs_desc)
			return false;

		return (fmt->nr_rates == 1 &&
		/*
		 * 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);
				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 ret;
}

static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
				      struct audioformat *fmt,
				      int source_id)
+6 −1
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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",
+17 −1
Original line number Diff line number Diff line
@@ -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 */
		/*
		 * 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;
	}
}