From: Frank van de Pol <fvdpol@gmail.com>
To: tiwai@suse.de, perex@perex.cz
Cc: corbet@lwn.net, khan@linuxfoundation.org, rdunlap@infradead.org,
fvdpol@gmail.com, linux-sound@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v5 07/13] ALSA: jockey3: Coalesce several packets into one URB
Date: Mon, 19 Oct 2026 13:44:39 -0400 [thread overview]
Message-ID: <20261019174445.1931263-8-fvdpol@gmail.com> (raw)
In-Reply-To: <20261019174445.1931263-1-fvdpol@gmail.com>
Let one bulk URB carry up to eight Ploytec packets, to cut the rate of
completion interrupts.
A Ploytec packet is 512 bytes, which is the high-speed bulk maximum
packet size. A transfer of N packets is therefore the same on the wire
as N transfers of one packet, and the device cannot tell them apart.
.hw_params picks N per direction as the largest power of two whose
packets fit in one period, so a small period falls back to one packet
per URB. The transfer buffers are allocated at the maximum. Changing N
only changes the transfer length of each URB at its next resubmission;
the ring is not torn down.
Assisted-by: LLM
Signed-off-by: Frank van de Pol <fvdpol@gmail.com>
---
sound/usb/jockey3/jockey3.c | 249 +++++++++++++++++++++++++++++++-----
1 file changed, 219 insertions(+), 30 deletions(-)
diff --git a/sound/usb/jockey3/jockey3.c b/sound/usb/jockey3/jockey3.c
index d2f4714dbd8b9..74fe5676273d2 100644
--- a/sound/usb/jockey3/jockey3.c
+++ b/sound/usb/jockey3/jockey3.c
@@ -15,12 +15,14 @@
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
+#include <linux/log2.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/cleanup.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include "ploytec_proto.h"
#include "ploytec_codec.h"
@@ -145,6 +147,37 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
#define JOCKEY3_N_URBS 8
+/*
+ * Maximum Ploytec packets per URB ("N"), per direction. Several packets are
+ * coalesced into one USB bulk transfer to cut the completion-interrupt rate
+ * (rationale and measurements in re/streaming_overhead.md).
+ *
+ * The live N is not fixed: jockey3_pcm_hw_params() picks it per stream open,
+ * per direction, as the largest power of two that fits the requested period
+ * size, and stores it in struct jockey3_pcm_urb_stream's @n_shift/@n_pkts.
+ * These two values are only the *ceiling* on that choice, and the width the
+ * URB transfer buffers are allocated at (JOCKEY3_*_XFER_SIZE) -- which is why
+ * the ceiling has to be a compile-time constant. Two separate constants, not
+ * one, so the ceiling can be tuned per direction if the firmware ever turns
+ * out to accept coalescing on one direction but not the other.
+ *
+ * Changing the live N never reallocates or tears down the URB ring: only
+ * urb->transfer_buffer_length varies. PLOYTEC_PKT_SIZE (512) is exactly the
+ * USB high-speed bulk max-packet size, so an N x 512 B transfer is
+ * indistinguishable on the wire from N separate 512 B ones; the firmware
+ * cannot tell the two apart. The buffers stay allocated JOCKEY3_*_XFER_SIZE
+ * wide regardless of the N in use.
+ *
+ * A live N of 1 in both directions must be byte-for-byte identical to a
+ * driver without coalescing: every packet loop below is keyed off the live
+ * @n_pkts and degenerates to the original single-packet code path at N=1.
+ */
+#define JOCKEY3_PLAYBACK_N 8
+#define JOCKEY3_CAPTURE_N 8
+
+#define JOCKEY3_PLAYBACK_XFER_SIZE (JOCKEY3_PLAYBACK_N * PLOYTEC_PKT_SIZE)
+#define JOCKEY3_CAPTURE_XFER_SIZE (JOCKEY3_CAPTURE_N * PLOYTEC_PKT_SIZE)
+
/* Consecutive URB transport errors tolerated before a direction is given up on */
#define JOCKEY3_MAX_URB_ERRORS 8
@@ -153,7 +186,8 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
* @substream: the open ALSA substream, or NULL; @lock
* @anchor: anchor holding the submitted URBs, for stop/kill
* @urbs: the URB ring
- * @bufs: transfer buffer for each URB
+ * @bufs: transfer buffer for each URB, allocated at the maximum N; @n_pkts,
+ * not this width, governs how many bytes an URB actually transfers
* @urbs_in_flight: number of submitted URBs; diagnostic, must reach 0 after a stop
* @lock: protects the fields marked "@lock" below; IRQ-safe leaf
* @dma_off: byte offset into runtime->dma_area, i.e. the hardware pointer; @lock
@@ -171,6 +205,13 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
* re-anchor a URB after the kill has drained the anchor.
* @consec_errors: consecutive URB transport errors; @lock. Reset on any
* successful completion and by jockey3_start_urbs().
+ * @n_shift: log2 of the Ploytec packets per URB ("N") the next resubmission
+ * will carry, in [0, 3]; @lock. Set by jockey3_pcm_hw_params() from the
+ * period size and reset to the default by jockey3_pcm_close(), so an idle
+ * direction never runs at a stale N. Changing it does not tear the ring
+ * down -- the wire cannot tell one N x 512 B transfer from N separate ones
+ * -- so each URB picks up the value at its next resubmission.
+ * @n_pkts: 1 << @n_shift, mirrored for loop bounds; @lock
*/
struct jockey3_pcm_urb_stream {
struct snd_pcm_substream *substream;
@@ -186,6 +227,8 @@ struct jockey3_pcm_urb_stream {
wait_queue_head_t drain_wait;
bool stopping;
unsigned int consec_errors;
+ u8 n_shift;
+ u8 n_pkts;
};
/**
@@ -581,11 +624,12 @@ static void jockey3_capture_callback(struct urb *urb)
struct jockey3_chip *chip = urb->context;
struct jockey3_pcm_urb_stream *urb_stream = &chip->capture;
struct snd_pcm_substream *substream = NULL;
+ int n_pkts = 0;
bool period_elapsed = false;
bool data_valid = true;
bool active = false;
bool stopping;
- int ret;
+ int sp, ret;
atomic_dec(&urb_stream->urbs_in_flight);
@@ -608,11 +652,32 @@ static void jockey3_capture_callback(struct urb *urb)
if (unlikely(jockey3_is_disconnected(chip)))
return;
- if (data_valid && unlikely(urb->actual_length < PLOYTEC_PKT_SIZE)) {
- dev_err_ratelimited(&chip->intf0->dev,
- "Capture URB too small: %d; required at least %d\n",
- urb->actual_length, PLOYTEC_PKT_SIZE);
- data_valid = false;
+ /*
+ * The firmware fills a multi-packet capture URB completely rather than
+ * terminating at one 512 B packet, so the expected case is
+ * actual_length == JOCKEY3_CAPTURE_XFER_SIZE. Derive the count from
+ * what actually came back rather than assuming N, in case that
+ * changes under load or on other firmware revisions.
+ */
+ if (data_valid) {
+ n_pkts = urb->actual_length / PLOYTEC_PKT_SIZE;
+ if (unlikely(n_pkts == 0)) {
+ dev_err_ratelimited(&chip->intf0->dev,
+ "Capture URB too small: %d; required at least %d\n",
+ urb->actual_length, PLOYTEC_PKT_SIZE);
+ data_valid = false;
+ } else if (unlikely(urb->actual_length % PLOYTEC_PKT_SIZE)) {
+ /*
+ * A short trailing partial packet: use the
+ * complete ones and drop the rest, but this should
+ * not happen on firmware behaving as described above
+ * -- log it once so a change in device behavior is
+ * visible instead of silently discarded audio.
+ */
+ dev_warn_once(&chip->intf0->dev,
+ "Capture URB length %d not a multiple of %d, using %d packet(s)\n",
+ urb->actual_length, PLOYTEC_PKT_SIZE, n_pkts);
+ }
}
/* Step 1: Safely fetch the pointer and join the safe zone */
@@ -626,7 +691,9 @@ static void jockey3_capture_callback(struct urb *urb)
active = true;
substream = urb_stream->substream;
- period_elapsed = jockey3_process_in_packet(chip, urb->transfer_buffer);
+ for (sp = 0; sp < n_pkts; sp++)
+ period_elapsed |= jockey3_process_in_packet(chip,
+ urb->transfer_buffer + sp * PLOYTEC_PKT_SIZE);
}
}
@@ -653,6 +720,7 @@ static void jockey3_capture_callback(struct urb *urb)
* to an anchor jockey3_stop_urbs() has already drained.
*/
if (!urb_stream->stopping && !jockey3_is_disconnected(chip)) {
+ urb->transfer_buffer_length = urb_stream->n_pkts * PLOYTEC_PKT_SIZE;
atomic_inc(&urb_stream->urbs_in_flight);
usb_anchor_urb(urb, &urb_stream->anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -687,8 +755,14 @@ static void jockey3_silence_out_packet(u8 *buf)
*/
static void jockey3_init_out_packet(u8 *buf)
{
- buf[PLOYTEC_MIDI_OUT_OFFSET] = PLOYTEC_MIDI_IDLE_BYTE;
- buf[PLOYTEC_SYNC_BYTE_OFFSET] = PLOYTEC_SYNC_BYTE_VALUE;
+ int sp;
+
+ for (sp = 0; sp < JOCKEY3_PLAYBACK_N; sp++) {
+ u8 *sub = buf + sp * PLOYTEC_PKT_SIZE;
+
+ sub[PLOYTEC_MIDI_OUT_OFFSET] = PLOYTEC_MIDI_IDLE_BYTE;
+ sub[PLOYTEC_SYNC_BYTE_OFFSET] = PLOYTEC_SYNC_BYTE_VALUE;
+ }
}
static void jockey3_playback_callback(struct urb *urb)
@@ -697,11 +771,12 @@ static void jockey3_playback_callback(struct urb *urb)
struct jockey3_pcm_urb_stream *urb_stream = &chip->playback;
unsigned char *buf = (unsigned char *)urb->transfer_buffer;
struct snd_pcm_substream *substream = NULL;
+ unsigned int submit_pkts;
bool period_elapsed = false;
bool data_valid = true;
bool active = false;
bool stopping;
- int i, ret;
+ int i, sp, ret;
atomic_dec(&urb_stream->urbs_in_flight);
@@ -723,8 +798,21 @@ static void jockey3_playback_callback(struct urb *urb)
if (unlikely(jockey3_is_disconnected(chip)))
return;
- /* Step 1: Safely fetch the pointer and join the safe zone */
+ /*
+ * Step 1: Safely fetch the pointer and join the safe zone.
+ *
+ * @n_pkts is captured once here and reused below for the MIDI/sync
+ * loop and the resubmit's transfer_buffer_length, rather than re-read
+ * at each site: jockey3_pcm_hw_params() can change it concurrently
+ * (under the same lock), and this URB's buffer must only ever claim
+ * to carry as many freshly written packets as it actually filled
+ * this callback. Reading a larger value at resubmit than was used to
+ * fill would send stale packets left over from an earlier, larger N
+ * instead of tearing the ring down.
+ */
scoped_guard(spinlock_irqsave, &urb_stream->lock) {
+ submit_pkts = urb_stream->n_pkts;
+
if (data_valid)
urb_stream->consec_errors = 0;
@@ -734,9 +822,12 @@ static void jockey3_playback_callback(struct urb *urb)
active = true;
substream = urb_stream->substream;
- period_elapsed = jockey3_process_out_packet(chip, buf);
+ for (sp = 0; sp < submit_pkts; sp++)
+ period_elapsed |= jockey3_process_out_packet(chip,
+ buf + sp * PLOYTEC_PKT_SIZE);
} else {
- jockey3_silence_out_packet(buf);
+ for (sp = 0; sp < submit_pkts; sp++)
+ jockey3_silence_out_packet(buf + sp * PLOYTEC_PKT_SIZE);
}
}
@@ -744,12 +835,16 @@ static void jockey3_playback_callback(struct urb *urb)
* Every packet reserves one slot for a MIDI OUT byte. Nothing feeds it
* yet, so it carries the idle byte.
*/
- buf[PLOYTEC_MIDI_OUT_OFFSET] = PLOYTEC_MIDI_IDLE_BYTE;
+ for (sp = 0; sp < submit_pkts; sp++) {
+ u8 *sub = buf + sp * PLOYTEC_PKT_SIZE;
- /* Ploytec Sync byte and gap padding */
- buf[PLOYTEC_SYNC_BYTE_OFFSET] = PLOYTEC_SYNC_BYTE_VALUE;
- for (i = PLOYTEC_SYNC_BYTE_OFFSET + 1; i < PLOYTEC_PKT_SIZE; i++)
- buf[i] = 0x00;
+ sub[PLOYTEC_MIDI_OUT_OFFSET] = PLOYTEC_MIDI_IDLE_BYTE;
+
+ /* Ploytec Sync byte and gap padding */
+ sub[PLOYTEC_SYNC_BYTE_OFFSET] = PLOYTEC_SYNC_BYTE_VALUE;
+ for (i = PLOYTEC_SYNC_BYTE_OFFSET + 1; i < PLOYTEC_PKT_SIZE; i++)
+ sub[i] = 0x00;
+ }
/*
* Step 2: Safe Zone. ALSA core can't free 'substream' because
@@ -774,6 +869,7 @@ static void jockey3_playback_callback(struct urb *urb)
* to an anchor jockey3_stop_urbs() has already drained.
*/
if (!urb_stream->stopping && !jockey3_is_disconnected(chip)) {
+ urb->transfer_buffer_length = submit_pkts * PLOYTEC_PKT_SIZE;
atomic_inc(&urb_stream->urbs_in_flight);
usb_anchor_urb(urb, &urb_stream->anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -941,6 +1037,7 @@ static int jockey3_start_urbs(struct jockey3_chip *chip)
{
int i, ret, first_err = 0;
int n_playback = 0, n_capture = 0;
+ u8 playback_n_pkts, capture_n_pkts;
if (jockey3_is_disconnected(chip))
return -ENODEV;
@@ -966,7 +1063,23 @@ static int jockey3_start_urbs(struct jockey3_chip *chip)
chip->midi_consec_errors = 0;
}
+ /*
+ * Each direction's ring is armed at its own current N, which at probe is
+ * the JOCKEY3_PLAYBACK_N/JOCKEY3_CAPTURE_N default.
+ *
+ * Both are read once here rather than per iteration: they are written
+ * under the stream lock, which is not held here, so a re-load could
+ * leave URBs in the same ring armed at different lengths.
+ */
+ playback_n_pkts = READ_ONCE(chip->playback.n_pkts);
+ capture_n_pkts = READ_ONCE(chip->capture.n_pkts);
+
for (i = 0; i < JOCKEY3_N_URBS; i++) {
+ chip->playback.urbs[i]->transfer_buffer_length =
+ playback_n_pkts * PLOYTEC_PKT_SIZE;
+ chip->capture.urbs[i]->transfer_buffer_length =
+ capture_n_pkts * PLOYTEC_PKT_SIZE;
+
atomic_inc(&chip->playback.urbs_in_flight);
usb_anchor_urb(chip->playback.urbs[i], &chip->playback.anchor);
ret = usb_submit_urb(chip->playback.urbs[i], GFP_KERNEL);
@@ -1099,10 +1212,12 @@ static const struct snd_pcm_hardware jockey3_pcm_hw_playback = {
.channels_max = 4,
.buffer_bytes_max = 1024 * 1024,
/*
- * One playback URB carries one packet of 10 frames * 4 channels * 3
- * bytes = 120 bytes. A URB reports at most one elapsed period, so the
- * minimum must cover at least one packet, or a period boundary inside a
- * URB could be missed entirely.
+ * One playback URB carries a packet count chosen per open by
+ * jockey3_pcm_hw_params(), of 10 frames * 4 channels * 3 bytes = 120
+ * bytes each. period_elapsed is OR'd across the packet loop in
+ * jockey3_playback_callback(), so the minimum must cover at least one
+ * packet, the smallest a URB can ever carry (N=1), or a period boundary
+ * inside a URB could be missed entirely.
*/
.period_bytes_min = PLOYTEC_PLAYBACK_FRAMES * 4 * 3,
.period_bytes_max = 512 * 1024,
@@ -1120,9 +1235,10 @@ static const struct snd_pcm_hardware jockey3_pcm_hw_capture = {
.channels_max = 6,
.buffer_bytes_max = 1024 * 1024,
/*
- * One capture URB carries one packet of 8 frames * 6 channels * 3 bytes
- * = 144 bytes; see the playback .period_bytes_min comment above for why
- * the minimum must cover at least one packet.
+ * One capture URB carries a packet count chosen per open (see
+ * jockey3_pcm_hw_params()) of up to 8 frames * 6 channels * 3 bytes =
+ * 144 bytes each; see the playback .period_bytes_min comment above for
+ * why the minimum must cover at least one packet.
*/
.period_bytes_min = PLOYTEC_CAPTURE_FRAMES * 6 * 3,
.period_bytes_max = 512 * 1024,
@@ -1164,6 +1280,8 @@ static int jockey3_pcm_close(struct snd_pcm_substream *substream)
struct jockey3_chip *chip = snd_pcm_substream_chip(substream);
struct jockey3_pcm_urb_stream *urb_stream =
jockey3_get_pcm_urb_stream(chip, substream->stream);
+ unsigned int default_n = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ JOCKEY3_PLAYBACK_N : JOCKEY3_CAPTURE_N;
dev_dbg(&chip->intf0->dev, "PCM close stream %d\n", substream->stream);
@@ -1175,6 +1293,16 @@ static int jockey3_pcm_close(struct snd_pcm_substream *substream)
scoped_guard(spinlock_irqsave, &urb_stream->lock) {
urb_stream->substream = NULL;
urb_stream->running = false;
+
+ /*
+ * A closed direction is not covered by jockey3_pcm_hw_params()
+ * any more, so its N would otherwise sit at whatever the last
+ * open left it at -- possibly a small, period-tuned value that
+ * has nothing to do with the next stream to open it. Reset to
+ * the default here so an idle direction always runs at a safe N.
+ */
+ WRITE_ONCE(urb_stream->n_shift, ilog2(default_n));
+ WRITE_ONCE(urb_stream->n_pkts, default_n);
}
return 0;
@@ -1304,9 +1432,61 @@ static int jockey3_initialize_ploytec(struct jockey3_chip *chip, u32 *fw_version
return 0;
}
+/**
+ * jockey3_pcm_set_n() - choose and arm this direction's packets per URB
+ * @chip: driver state
+ * @substream: the substream hw_params was just called for
+ * @hw_params: the negotiated parameters
+ *
+ * Chooses how many Ploytec packets each USB bulk URB on this direction
+ * carries, called "N" below for brevity: the largest power of two with
+ * N * pkt_bytes <= period_bytes. A big period gets the full coalescing
+ * saving, a tiny one falls back to N=1 automatically via .period_bytes_min.
+ * Takes effect without tearing the URB ring down -- the firmware cannot tell
+ * an N x 512 B bulk transfer apart from N separate 512 B ones, so each URB on
+ * this direction simply picks up the new N at its own next resubmission; the
+ * ring turns over onto it within at most JOCKEY3_N_URBS completions. See
+ * re/streaming_overhead.md for the rationale and measurements.
+ */
+static void jockey3_pcm_set_n(struct jockey3_chip *chip, struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct jockey3_pcm_urb_stream *urb_stream =
+ jockey3_get_pcm_urb_stream(chip, substream->stream);
+ unsigned int period_bytes = params_period_bytes(hw_params);
+ bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ unsigned int pkt_bytes = is_playback ? PLOYTEC_PLAYBACK_FRAMES * 4 * 3 :
+ PLOYTEC_CAPTURE_FRAMES * 6 * 3;
+ unsigned int max_n = is_playback ? JOCKEY3_PLAYBACK_N : JOCKEY3_CAPTURE_N;
+ unsigned int n = max(period_bytes / pkt_bytes, 1U);
+ u8 n_shift = clamp_t(u8, ilog2(n), 0, ilog2(max_n));
+
+ scoped_guard(spinlock_irqsave, &urb_stream->lock) {
+ WRITE_ONCE(urb_stream->n_shift, n_shift);
+ WRITE_ONCE(urb_stream->n_pkts, 1 << n_shift);
+ }
+
+ dev_dbg(&chip->intf0->dev, "hw_params: %s using %u packet(s)/URB (period_bytes=%u)\n",
+ is_playback ? "playback" : "capture", 1U << n_shift, period_bytes);
+}
+
+static int jockey3_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct jockey3_chip *chip = snd_pcm_substream_chip(substream);
+
+ if (jockey3_is_disconnected(chip))
+ return -ENODEV;
+
+ jockey3_pcm_set_n(chip, substream, hw_params);
+
+ return 0;
+}
+
static const struct snd_pcm_ops jockey3_pcm_ops = {
.open = jockey3_pcm_open,
.close = jockey3_pcm_close,
+ .hw_params = jockey3_pcm_hw_params,
.prepare = jockey3_pcm_prepare,
.trigger = jockey3_pcm_trigger,
.sync_stop = jockey3_pcm_sync_stop,
@@ -1454,7 +1634,7 @@ static int jockey3_init_playback_urbs(struct jockey3_chip *chip)
int i;
for (i = 0; i < JOCKEY3_N_URBS; i++) {
- chip->playback.bufs[i] = kzalloc(PLOYTEC_PKT_SIZE, GFP_KERNEL);
+ chip->playback.bufs[i] = kzalloc(JOCKEY3_PLAYBACK_XFER_SIZE, GFP_KERNEL);
if (!chip->playback.bufs[i])
return -ENOMEM;
@@ -1466,7 +1646,7 @@ static int jockey3_init_playback_urbs(struct jockey3_chip *chip)
usb_fill_bulk_urb(chip->playback.urbs[i], dev,
usb_sndbulkpipe(dev, PLOYTEC_EP_NUM_PCM_OUT),
- chip->playback.bufs[i], PLOYTEC_PKT_SIZE,
+ chip->playback.bufs[i], JOCKEY3_PLAYBACK_XFER_SIZE,
jockey3_playback_callback, chip);
}
@@ -1479,7 +1659,7 @@ static int jockey3_init_capture_urbs(struct jockey3_chip *chip)
int i;
for (i = 0; i < JOCKEY3_N_URBS; i++) {
- chip->capture.bufs[i] = kzalloc(PLOYTEC_PKT_SIZE, GFP_KERNEL);
+ chip->capture.bufs[i] = kzalloc(JOCKEY3_CAPTURE_XFER_SIZE, GFP_KERNEL);
if (!chip->capture.bufs[i])
return -ENOMEM;
@@ -1489,7 +1669,7 @@ static int jockey3_init_capture_urbs(struct jockey3_chip *chip)
usb_fill_bulk_urb(chip->capture.urbs[i], dev,
usb_rcvbulkpipe(dev, PLOYTEC_EP_NUM_PCM_IN),
- chip->capture.bufs[i], PLOYTEC_PKT_SIZE,
+ chip->capture.bufs[i], JOCKEY3_CAPTURE_XFER_SIZE,
jockey3_capture_callback, chip);
}
@@ -1697,6 +1877,15 @@ static int jockey3_probe(struct usb_interface *intf, const struct usb_device_id
*/
atomic_set(&chip->playback.urbs_in_flight, 0);
atomic_set(&chip->capture.urbs_in_flight, 0);
+ /*
+ * Default N until the first hw_params() picks a period-tuned value
+ * (jockey3_pcm_set_n()); matches the width the URB buffers below are
+ * actually allocated at, and jockey3_init_out_packet() primes.
+ */
+ chip->playback.n_shift = ilog2(JOCKEY3_PLAYBACK_N);
+ chip->playback.n_pkts = JOCKEY3_PLAYBACK_N;
+ chip->capture.n_shift = ilog2(JOCKEY3_CAPTURE_N);
+ chip->capture.n_pkts = JOCKEY3_CAPTURE_N;
chip->xfer_buf = kmalloc(USB_XFER_BUF_SIZE, GFP_KERNEL);
if (!chip->xfer_buf) {
--
2.47.3
next prev parent reply other threads:[~2026-10-19 17:46 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 17:44 [PATCH v5 00/13] ALSA: jockey3: Add support for Reloop Jockey 3 DJ controllers Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 01/13] ALSA: jockey3: Add probe skeleton " Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 02/13] ALSA: jockey3: Start the bulk streams Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 03/13] ALSA: jockey3: Add PCM playback Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 04/13] ALSA: jockey3: Add PCM capture Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 05/13] ALSA: jockey3: Add KUnit tests for the Ploytec codec Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 06/13] ALSA: jockey3: Add optimized codec variants Frank van de Pol
2026-10-19 17:44 ` Frank van de Pol [this message]
2026-10-19 17:44 ` [PATCH v5 08/13] ALSA: jockey3: Recover a stalled stream Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 09/13] ALSA: jockey3: Add a watchdog for mid-stream stalls Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 10/13] ALSA: jockey3: Add sample rate switching Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 11/13] ALSA: jockey3: Add MIDI support Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 12/13] ALSA: jockey3: Add power management Frank van de Pol
2026-10-19 17:44 ` [PATCH v5 13/13] ALSA: jockey3: Add driver documentation Frank van de Pol
2026-10-20 13:14 ` [PATCH v5 00/13] ALSA: jockey3: Add support for Reloop Jockey 3 DJ controllers Takashi Iwai
2026-10-20 16:25 ` Frank van de Pol
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261019174445.1931263-8-fvdpol@gmail.com \
--to=fvdpol@gmail.com \
--cc=corbet@lwn.net \
--cc=khan@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=perex@perex.cz \
--cc=rdunlap@infradead.org \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.