ALSA: usb-audio: Add boot quirk for MOTU M Series
authorAlexander Tsoy <alexander@tsoy.me>
Sun, 12 Jan 2020 10:23:58 +0000 (13:23 +0300)
committerTakashi Iwai <tiwai@suse.de>
Mon, 13 Jan 2020 09:47:56 +0000 (10:47 +0100)
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: Alexander Tsoy <alexander@tsoy.me>
Link: https://lore.kernel.org/r/20200112102358.18085-1-alexander@tsoy.me
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/card.c
sound/usb/quirks.c
sound/usb/quirks.h

index 9f743eb..2f582ac 100644 (file)
@@ -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
                 */
index 11159fc..3a5242e 100644 (file)
@@ -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
  */
index a80e0dd..df03558 100644 (file)
@@ -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);