mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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


  parent reply	other threads:[~2026-10-19 17:46 UTC|newest]

Thread overview: 14+ 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

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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®