* [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support
@ 2026-09-03 23:16 Hanh Kieu
2026-09-04 3:59 ` Geraldo Nascimento
0 siblings, 1 reply; 5+ messages in thread
From: Hanh Kieu @ 2026-09-03 23:16 UTC (permalink / raw)
To: perex, tiwai; +Cc: linux-sound, linux-kernel
The Pioneer DJ DDJ-SZ exposes its audio interface as USB vendor-specific
class (0xFF) rather than USB Audio Class, so it needs a quirks-table
entry like its sibling Pioneer devices (DJM-750, DJM-850, DJM-900NXS2,
DJM-450, DJM-V10) already have.
The device presents 10 channels of S24_3LE audio in both directions,
fixed at 44.1kHz, on interface 0 altsetting 1: playback on endpoint
0x01, capture on endpoint 0x82. The unit contains its own analog mixer,
and each playback channel pair feeds one of its physical channel strips:
0/1, 2/3, 4/5 and 6/7 feed strips 1-4 respectively, and 8/9 feed the
booth output. The master output is produced in analog by that mixer and
is not carried over USB at all. On the capture side, channels 8/9 are
the mic input; capture channels 0-7 are not yet mapped to specific
physical inputs.
Implicit feedback needs no quirk flag here: is_pioneer_implicit_fb() in
implicit.c already covers vendor 0x08e4 with a vendor-spec class
interface and two endpoints, and the driver duly reports endpoint 0x82
as the playback sync endpoint.
Activation reuses the existing pioneer_djm_set_format_quirk() used by
the DJM-750/850/900NXS2/450/V10 (SET_INTERFACE to altsetting 1, then a
UAC-shaped SET_CUR sample-rate control transfer) with this device's own
captured wIndex (0x0082). Unlike those devices, the DDJ-SZ additionally
needs a vendor "arm" sequence before its capture path produces real
audio -- without it, capture opens and runs with no USB/ALSA errors
but delivers silence (a hard zero on every channel) rather than any
error, so this is easy to miss. The arm sequence is six vendor control
transfers (bmRequestType=0x40, bRequest=3, varying wValue/wIndex, each
followed by a bmRequestType=0xc0, bRequest=0 status read), replicated
byte-for-byte from a USB capture of the official Windows driver.
All of the above -- endpoint numbers, format, channel mapping, and the
arm sequence bytes -- were determined by capturing and decoding real USB
traffic from the Windows driver (USBPcap + Wireshark) during
enumeration, playback, and mic recording, then verifying the format
hypothesis against actual de-interleaved payload data rather than
packet-size arithmetic alone. Both playback and capture have been
verified working with real audio, not just clean enumeration.
Signed-off-by: Hanh Kieu <hhkieu@gmail.com>
---
sound/usb/quirks-table.h | 47 +++++++++++++++++++++++++++++++
sound/usb/quirks.c | 60 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 107 insertions(+)
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index a1a33f11d..2da8cbe3e 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3731,6 +3731,53 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ /*
+ * Pioneer DJ DDJ-SZ
+ * 10 channels playback & 10 channels capture @ 44.1kHz S24LE
+ */
+ USB_DEVICE_VENDOR_SPEC(0x08e4, 0x0191),
+ QUIRK_DRIVER_INFO {
+ QUIRK_DATA_COMPOSITE {
+ {
+ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+ {
+ QUIRK_DATA_AUDIOFORMAT(0) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x82,
+ .ep_idx = 1,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC|
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_44100,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 44100 }
+ }
+ },
+ QUIRK_COMPOSITE_END
+ }
+ }
+},
{
/*
* Pioneer DJ DJM-750MK2
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 4936d66f9..f09599c0d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1767,6 +1767,62 @@ static void set_format_emu_quirk(struct snd_usb_substream *subs,
subs->pkt_offset_adj = (emu_samplerate_id >= EMU_QUIRK_SR_176400HZ) ? 4 : 0;
}
+/*
+ * The DDJ-SZ needs a vendor "arm" sequence before its capture path
+ * produces real audio; without it capture runs with no USB or ALSA error
+ * but delivers a hard zero on every channel. The sequence is replicated
+ * byte-for-byte from a USB capture of the Windows driver: each write is
+ * followed by a status read whose content is a fixed value regardless of
+ * what was written, but the read is replicated too, since it is unclear
+ * whether the device requires it to process the preceding write.
+ *
+ * This runs from snd_usb_set_format_quirk(), i.e. on every format setup
+ * rather than once per device. Re-arming is harmless in practice and
+ * keeps the device armed if it is reset behind our back.
+ */
+static void ddj_sz_arm_quirk(struct usb_device *dev)
+{
+ static const struct {
+ u16 value;
+ u16 index;
+ u8 read_len;
+ } cmds[] = {
+ { 0x0100, 0x8002, 6 },
+ { 0x0200, 0x8002, 6 },
+ { 0x0303, 0x8002, 6 },
+ { 0x0403, 0x8002, 6 },
+ { 0x050a, 0x8002, 6 },
+ { 0x0000, 0x8003, 2 },
+ };
+ u8 buf[6];
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 3,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE,
+ cmds[i].value, cmds[i].index, NULL, 0);
+ if (err < 0)
+ goto err_out;
+
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0,
+ USB_DIR_IN | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE,
+ 0x0000, cmds[i].index, buf,
+ cmds[i].read_len);
+ if (err < 0)
+ goto err_out;
+ }
+
+ return;
+
+err_out:
+ dev_warn(&dev->dev,
+ "DDJ-SZ: arm sequence step %u failed (%d), capture may be silent\n",
+ i, err);
+}
+
static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs,
u16 windex)
{
@@ -1948,6 +2004,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
case USB_ID(0x08e4, 0x0163): /* Pioneer DJM-850 */
pioneer_djm_set_format_quirk(subs, 0x0086);
break;
+ case USB_ID(0x08e4, 0x0191): /* Pioneer DDJ-SZ */
+ ddj_sz_arm_quirk(subs->dev);
+ pioneer_djm_set_format_quirk(subs, 0x0082);
+ break;
case USB_ID(0x0dba, 0x5000):
mbox3_set_format_quirk(subs, fmt); /* Digidesign Mbox 3 */
break;
base-commit: 4c4e4be4edd5dbf5f7f6a3ef4fc0c243f2d01b3c
--
2.47.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support
2026-09-03 23:16 [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support Hanh Kieu
@ 2026-09-04 3:59 ` Geraldo Nascimento
2026-09-04 18:20 ` Hanh Kieu
0 siblings, 1 reply; 5+ messages in thread
From: Geraldo Nascimento @ 2026-09-04 3:59 UTC (permalink / raw)
To: Hanh Kieu; +Cc: perex, tiwai, linux-sound, linux-kernel
Hi everyone,
On Thu, Sep 3, 2026 at 8:18 PM Hanh Kieu <hhkieu@gmail.com> wrote:
>
> The Pioneer DJ DDJ-SZ exposes its audio interface as USB vendor-specific
> class (0xFF) rather than USB Audio Class, so it needs a quirks-table
> entry like its sibling Pioneer devices (DJM-750, DJM-850, DJM-900NXS2,
> DJM-450, DJM-V10) already have.
>
> The device presents 10 channels of S24_3LE audio in both directions,
> fixed at 44.1kHz, on interface 0 altsetting 1: playback on endpoint
> 0x01, capture on endpoint 0x82. The unit contains its own analog mixer,
> and each playback channel pair feeds one of its physical channel strips:
> 0/1, 2/3, 4/5 and 6/7 feed strips 1-4 respectively, and 8/9 feed the
> booth output. The master output is produced in analog by that mixer and
> is not carried over USB at all. On the capture side, channels 8/9 are
> the mic input; capture channels 0-7 are not yet mapped to specific
> physical inputs.
>
> Implicit feedback needs no quirk flag here: is_pioneer_implicit_fb() in
> implicit.c already covers vendor 0x08e4 with a vendor-spec class
> interface and two endpoints, and the driver duly reports endpoint 0x82
> as the playback sync endpoint.
Are you sure is_pioneer_implicit_fb() isn't returning false and you're
picking up on a generic sync ep instead?
You should double-check that function is returning true or false because it
will return false when USB_ENDPOINT_USAGE_IMPLICIT_FB isn't
set on bmAttributes of a Isochronous IN EP.
Thanks,
Geraldo Nascimento
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support
2026-09-04 3:59 ` Geraldo Nascimento
@ 2026-09-04 18:20 ` Hanh Kieu
2026-09-05 3:30 ` Geraldo Nascimento
0 siblings, 1 reply; 5+ messages in thread
From: Hanh Kieu @ 2026-09-04 18:20 UTC (permalink / raw)
To: geraldogabriel, perex, tiwai; +Cc: linux-sound, linux-kernel
Geraldo Nascimento wrote:
> Are you sure is_pioneer_implicit_fb() isn't returning false and you're
> picking up on a generic sync ep instead?
>
> You should double-check that function is returning true or false because
> it will return false when USB_ENDPOINT_USAGE_IMPLICIT_FB isn't
> set on bmAttributes of a Isochronous IN EP.
Good catch, thanks -- I checked against the real device rather than
assuming.
lsusb -v on the DDJ-SZ shows both endpoints (0x01 OUT, 0x82 IN) as
Isochronous / Asynchronous with Usage Type = Data (bmAttributes = 0x05).
is_pioneer_implicit_fb() accepts the capture endpoint's usage being
either USB_ENDPOINT_USAGE_DATA or USB_ENDPOINT_USAGE_IMPLICIT_FB, not
IMPLICIT_FB exclusively, so Data usage does pass that check.
I also traced snd_usb_parse_implicit_fb_quirk()'s dispatch order for
this device to make sure nothing generic intercepts first: no fixed or
capture quirk-table entry matches 08e4:0191, it isn't UAC2
(bInterfaceClass is vendor-spec, not USB_CLASS_AUDIO), and it isn't the
Roland vendor ID. So is_pioneer_implicit_fb() is the function actually
being reached and returning true for this device, not a coincidental
generic fallback.
Happy to add a comment near the quirk-table entry noting the real
bmAttributes value if that would help future readers.
Thanks,
Hanh Kieu
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support
2026-09-04 18:20 ` Hanh Kieu
@ 2026-09-05 3:30 ` Geraldo Nascimento
[not found] ` <CAEWo5SpV6eyHo-tn+hKX4s98uCjGJg5Dz9fMkoWNDNqgofJ5og@mail.gmail.com>
0 siblings, 1 reply; 5+ messages in thread
From: Geraldo Nascimento @ 2026-09-05 3:30 UTC (permalink / raw)
To: Hanh Kieu; +Cc: perex, tiwai, linux-sound, linux-kernel
Hi Hanh,
On Fri, Sep 4, 2026 at 3:20 PM Hanh Kieu <hhkieu@gmail.com> wrote:
>
> Geraldo Nascimento wrote:
> > Are you sure is_pioneer_implicit_fb() isn't returning false and you're
> > picking up on a generic sync ep instead?
> >
> > You should double-check that function is returning true or false because
> > it will return false when USB_ENDPOINT_USAGE_IMPLICIT_FB isn't
> > set on bmAttributes of a Isochronous IN EP.
>
> Good catch, thanks -- I checked against the real device rather than
> assuming.
Thanks.
>
> lsusb -v on the DDJ-SZ shows both endpoints (0x01 OUT, 0x82 IN) as
> Isochronous / Asynchronous with Usage Type = Data (bmAttributes = 0x05).
> is_pioneer_implicit_fb() accepts the capture endpoint's usage being
> either USB_ENDPOINT_USAGE_DATA or USB_ENDPOINT_USAGE_IMPLICIT_FB, not
> IMPLICIT_FB exclusively, so Data usage does pass that check.
Thanks for this report.
The code snippet in question is in the body of is_pioneer_implicit_fb()
in sound/usb/implicit.c:
epd = get_endpoint(alts, 1);
if (!usb_endpoint_is_isoc_in(epd) ||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC ||
((epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_DATA &&
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
USB_ENDPOINT_USAGE_IMPLICIT_FB))
return false;
In my opinion the logical AND at the end of the if condition is short-circuited
by doing that inequality comparison between USB_ENDPOINT_USAGE_DATA
and the result of the bitwise AND between bmAttributes and
USB_ENDPOINT_USAGE_MASK, because 0x05 & 0x30 == 0x00.
When that first condition evaluates to false C never bothers to check the other
half of the logical AND, for logical and practical reasons.
What I'm not sure of is that's the kind of check we want for Pioneer implicit fb
matching... Takashi will have to be the judge here, but I think it is
not intended
behavior that this function picks up implicit fb without
USB_ENDPOINT_USAGE_IMPLICIT_FB being set. The fact is does so probably
means that code in implicit.c needs a bit of improvement.
>
> I also traced snd_usb_parse_implicit_fb_quirk()'s dispatch order for
> this device to make sure nothing generic intercepts first: no fixed or
> capture quirk-table entry matches 08e4:0191, it isn't UAC2
> (bInterfaceClass is vendor-spec, not USB_CLASS_AUDIO), and it isn't the
> Roland vendor ID. So is_pioneer_implicit_fb() is the function actually
> being reached and returning true for this device, not a coincidental
> generic fallback.
Again, thanks for your due dilligence, and for all your work, it's looking
good.
Thanks,
Geraldo Nascimento
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-05 6:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-03 23:16 [PATCH] ALSA: usb-audio: add Pioneer DJ DDJ-SZ support Hanh Kieu
2026-09-04 3:59 ` Geraldo Nascimento
2026-09-04 18:20 ` Hanh Kieu
2026-09-05 3:30 ` Geraldo Nascimento
[not found] ` <CAEWo5SpV6eyHo-tn+hKX4s98uCjGJg5Dz9fMkoWNDNqgofJ5og@mail.gmail.com>
2026-09-05 6:19 ` Geraldo Nascimento
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox