Commit 73ac9f5e authored by Alexander Tsoy's avatar Alexander Tsoy Committed by Takashi Iwai
Browse files

ALSA: usb-audio: Add boot quirk for MOTU M Series



Add delay to make sure that audio urbs are not sent too early.
Otherwise the device hangs. Windows driver makes ~2s delay, so use
about the same time delay value.

snd_usb_apply_boot_quirk() is called 3 times for my MOTU M4, which
is an overkill. Thus a quirk that is called only once is implemented.

Also send two vendor-specific control messages before and after
the delay. This behaviour is blindly copied from the Windows driver.

Signed-off-by: default avatarAlexander Tsoy <alexander@tsoy.me>
Link: https://lore.kernel.org/r/20200112102358.18085-1-alexander@tsoy.me


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 791a485f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -600,6 +600,10 @@ static int usb_audio_probe(struct usb_interface *intf,
		}
	}
	if (! chip) {
		err = snd_usb_apply_boot_quirk_once(dev, intf, quirk, id);
		if (err < 0)
			return err;

		/* it's a fresh one.
		 * now look for an empty slot and create a new card instance
		 */
+38 −0
Original line number Diff line number Diff line
@@ -1113,6 +1113,31 @@ free_buf:
	return err;
}

static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
{
	int ret;

	if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
		return -EINVAL;
	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
			      1, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			      0x0, 0, NULL, 0, 1000);

	if (ret < 0)
		return ret;

	msleep(2000);

	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
			      1, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			      0x20, 0, NULL, 0, 1000);

	if (ret < 0)
		return ret;

	return 0;
}

/*
 * Setup quirks
 */
@@ -1297,6 +1322,19 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
	return 0;
}

int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
				  struct usb_interface *intf,
				  const struct snd_usb_audio_quirk *quirk,
				  unsigned int id)
{
	switch (id) {
	case USB_ID(0x07fd, 0x0008): /* MOTU M Series */
		return snd_usb_motu_m_series_boot_quirk(dev);
	}

	return 0;
}

/*
 * check if the device uses big-endian samples
 */
+5 −0
Original line number Diff line number Diff line
@@ -20,6 +20,11 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
			     const struct snd_usb_audio_quirk *quirk,
			     unsigned int usb_id);

int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
				  struct usb_interface *intf,
				  const struct snd_usb_audio_quirk *quirk,
				  unsigned int usb_id);

void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
			      struct audioformat *fmt);