Merge tag 'sound-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[sfrench/cifs-2.6.git] / sound / usb / implicit.c
index 11a85e66aa96de6992cf08909d80947a38ab0141..590a0dbba7a216569916fbfd80a7022ec747099b 100644 (file)
@@ -21,6 +21,7 @@ enum {
        IMPLICIT_FB_NONE,
        IMPLICIT_FB_GENERIC,
        IMPLICIT_FB_FIXED,
+       IMPLICIT_FB_BOTH,       /* generic playback + capture (for BOSS) */
 };
 
 struct snd_usb_implicit_fb_match {
@@ -36,6 +37,9 @@ struct snd_usb_implicit_fb_match {
 #define IMPLICIT_FB_FIXED_DEV(vend, prod, ep, ifnum) \
        { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_FIXED, .ep_num = (ep),\
            .iface = (ifnum) }
+#define IMPLICIT_FB_BOTH_DEV(vend, prod, ep, ifnum) \
+       { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_BOTH, .ep_num = (ep),\
+           .iface = (ifnum) }
 #define IMPLICIT_FB_SKIP_DEV(vend, prod) \
        { .id = USB_ID(vend, prod), .type = IMPLICIT_FB_NONE }
 
@@ -70,30 +74,11 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
          .type = IMPLICIT_FB_FIXED,
          .ep_num = 0x84, .iface = 0 },         /* MOTU MicroBook II */
 
-       /* No quirk for playback but with capture quirk (see below) */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x0130),   /* BOSS BR-80 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x0171),   /* BOSS RC-505 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x0185),   /* BOSS GP-10 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x0189),   /* BOSS GT-100v2 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d6),   /* BOSS GT-1 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x01d8),   /* BOSS Katana */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x01e5),   /* BOSS GT-001 */
-       IMPLICIT_FB_SKIP_DEV(0x0582, 0x0203),   /* BOSS AD-10 */
-
        {} /* terminator */
 };
 
 /* Implicit feedback quirk table for capture: only FIXED type */
 static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x0130, 0x0d, 0x01), /* BOSS BR-80 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x0171, 0x0d, 0x01), /* BOSS RC-505 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x0185, 0x0d, 0x01), /* BOSS GP-10 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x0189, 0x0d, 0x01), /* BOSS GT-100v2 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d6, 0x0d, 0x01), /* BOSS GT-1 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x01d8, 0x0d, 0x01), /* BOSS Katana */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x01e5, 0x0d, 0x01), /* BOSS GT-001 */
-       IMPLICIT_FB_FIXED_DEV(0x0582, 0x0203, 0x0d, 0x01), /* BOSS AD-10 */
-
        {} /* terminator */
 };
 
@@ -151,44 +136,93 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip,
                                       ifnum, alts);
 }
 
-/* Like the function above, but specific to Roland with vendor class and hack */
+static bool roland_sanity_check_iface(struct usb_host_interface *alts)
+{
+       if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+           (alts->desc.bInterfaceSubClass != 2 &&
+            alts->desc.bInterfaceProtocol != 2) ||
+           alts->desc.bNumEndpoints < 1)
+               return false;
+       return true;
+}
+
+/* Like the UAC2 case above, but specific to Roland with vendor class and hack */
 static int add_roland_implicit_fb(struct snd_usb_audio *chip,
                                  struct audioformat *fmt,
-                                 unsigned int ifnum,
-                                 unsigned int altsetting)
+                                 struct usb_host_interface *alts)
 {
-       struct usb_host_interface *alts;
        struct usb_endpoint_descriptor *epd;
 
-       alts = snd_usb_get_host_interface(chip, ifnum, altsetting);
-       if (!alts)
+       if (!roland_sanity_check_iface(alts))
                return 0;
-       if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
-           (alts->desc.bInterfaceSubClass != 2 &&
-            alts->desc.bInterfaceProtocol != 2) ||
-           alts->desc.bNumEndpoints < 1)
+       /* only when both streams are with ASYNC type */
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_is_isoc_out(epd) ||
+           (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
+               return 0;
+
+       /* check capture EP */
+       alts = snd_usb_get_host_interface(chip,
+                                         alts->desc.bInterfaceNumber + 1,
+                                         alts->desc.bAlternateSetting);
+       if (!alts || !roland_sanity_check_iface(alts))
                return 0;
        epd = get_endpoint(alts, 0);
        if (!usb_endpoint_is_isoc_in(epd) ||
-           (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
-                                       USB_ENDPOINT_USAGE_IMPLICIT_FB)
+           (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
                return 0;
+       chip->playback_first = 1;
        return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
-                                      ifnum, alts);
+                                      alts->desc.bInterfaceNumber, alts);
 }
 
-/* Playback and capture EPs on Pioneer devices share the same iface/altset,
- * but they don't seem working with the implicit fb mode well, hence we
- * just return as if the sync were already set up.
+/* capture quirk for Roland device; always full-duplex */
+static int add_roland_capture_quirk(struct snd_usb_audio *chip,
+                                   struct audioformat *fmt,
+                                   struct usb_host_interface *alts)
+{
+       struct usb_endpoint_descriptor *epd;
+
+       if (!roland_sanity_check_iface(alts))
+               return 0;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_is_isoc_in(epd) ||
+           (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
+               return 0;
+
+       alts = snd_usb_get_host_interface(chip,
+                                         alts->desc.bInterfaceNumber - 1,
+                                         alts->desc.bAlternateSetting);
+       if (!alts || !roland_sanity_check_iface(alts))
+               return 0;
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_is_isoc_out(epd))
+               return 0;
+       return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
+                                      alts->desc.bInterfaceNumber, alts);
+}
+
+/* Playback and capture EPs on Pioneer devices share the same iface/altset
+ * for the implicit feedback operation
  */
-static int skip_pioneer_sync_ep(struct snd_usb_audio *chip,
-                               struct audioformat *fmt,
-                               struct usb_host_interface *alts)
+static bool is_pioneer_implicit_fb(struct snd_usb_audio *chip,
+                                  struct usb_host_interface *alts)
+
 {
        struct usb_endpoint_descriptor *epd;
 
+       if (USB_ID_VENDOR(chip->usb_id) != 0x2b73 &&
+           USB_ID_VENDOR(chip->usb_id) != 0x08e4)
+               return false;
+       if (alts->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+               return false;
        if (alts->desc.bNumEndpoints != 2)
-               return 0;
+               return false;
+
+       epd = get_endpoint(alts, 0);
+       if (!usb_endpoint_is_isoc_out(epd) ||
+           (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
+               return false;
 
        epd = get_endpoint(alts, 1);
        if (!usb_endpoint_is_isoc_in(epd) ||
@@ -197,8 +231,9 @@ static int skip_pioneer_sync_ep(struct snd_usb_audio *chip,
             USB_ENDPOINT_USAGE_DATA &&
             (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
             USB_ENDPOINT_USAGE_IMPLICIT_FB))
-               return 0;
-       return 1; /* don't handle with the implicit fb, just skip sync EP */
+               return false;
+
+       return true;
 }
 
 static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
@@ -278,6 +313,18 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
                }
        }
 
+       /* Special handling for devices with capture quirks */
+       p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts);
+       if (p) {
+               switch (p->type) {
+               case IMPLICIT_FB_FIXED:
+                       return 0; /* no quirk */
+               case IMPLICIT_FB_BOTH:
+                       chip->playback_first = 1;
+                       return add_generic_implicit_fb(chip, fmt, alts);
+               }
+       }
+
        /* Generic UAC2 implicit feedback */
        if (attr == USB_ENDPOINT_SYNC_ASYNC &&
            alts->desc.bInterfaceClass == USB_CLASS_AUDIO &&
@@ -290,24 +337,18 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
        }
 
        /* Roland/BOSS implicit feedback with vendor spec class */
-       if (attr == USB_ENDPOINT_SYNC_ASYNC &&
-           alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
-           alts->desc.bInterfaceProtocol == 2 &&
-           alts->desc.bNumEndpoints == 1 &&
-           USB_ID_VENDOR(chip->usb_id) == 0x0582 /* Roland */) {
-               if (add_roland_implicit_fb(chip, fmt,
-                                          alts->desc.bInterfaceNumber + 1,
-                                          alts->desc.bAlternateSetting))
+       if (USB_ID_VENDOR(chip->usb_id) == 0x0582) {
+               if (add_roland_implicit_fb(chip, fmt, alts) > 0)
                        return 1;
        }
 
        /* Pioneer devices with vendor spec class */
-       if (attr == USB_ENDPOINT_SYNC_ASYNC &&
-           alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
-           (USB_ID_VENDOR(chip->usb_id) == 0x2b73 || /* Pioneer */
-            USB_ID_VENDOR(chip->usb_id) == 0x08e4    /* Pioneer */)) {
-               if (skip_pioneer_sync_ep(chip, fmt, alts))
-                       return 1;
+       if (is_pioneer_implicit_fb(chip, alts)) {
+               chip->playback_first = 1;
+               return add_implicit_fb_sync_ep(chip, fmt,
+                                              get_endpoint(alts, 1)->bEndpointAddress,
+                                              1, alts->desc.bInterfaceNumber,
+                                              alts);
        }
 
        /* Try the generic implicit fb if available */
@@ -326,9 +367,18 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip,
        const struct snd_usb_implicit_fb_match *p;
 
        p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts);
-       if (p && p->type == IMPLICIT_FB_FIXED)
+       if (p && (p->type == IMPLICIT_FB_FIXED || p->type == IMPLICIT_FB_BOTH))
                return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
                                               p->iface, NULL);
+
+       /* Roland/BOSS need full-duplex streams */
+       if (USB_ID_VENDOR(chip->usb_id) == 0x0582) {
+               if (add_roland_capture_quirk(chip, fmt, alts) > 0)
+                       return 1;
+       }
+
+       if (is_pioneer_implicit_fb(chip, alts))
+               return 1; /* skip the quirk, also don't handle generic sync EP */
        return 0;
 }