summaryrefslogtreecommitdiffstats
path: root/sound/usb/implicit.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/implicit.c')
-rw-r--r--sound/usb/implicit.c162
1 files changed, 106 insertions, 56 deletions
diff --git a/sound/usb/implicit.c b/sound/usb/implicit.c
index 11a85e66aa96..590a0dbba7a2 100644
--- a/sound/usb/implicit.c
+++ b/sound/usb/implicit.c
@@ -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;
}