Linux Sound subsystem development
 help / color / mirror / Atom feed
From: Jonathan Seth Mainguy <jon@soh.re>
To: linux-sound@vger.kernel.org
Cc: perex@perex.cz, tiwai@suse.com, niklas@aldervall.se,
	linux-kernel@vger.kernel.org, Jonathan Seth Mainguy <jon@soh.re>
Subject: [PATCH 4/4] ALSA: usb-audio: set Roland Capture rate during stream preparation
Date: Fri, 28 Aug 2026 20:50:01 -0400	[thread overview]
Message-ID: <20260829005001.534571-5-jon@soh.re> (raw)
In-Reply-To: <20260829005001.534571-1-jon@soh.re>

Roland OCTA-CAPTURE and QUAD-CAPTURE select their hardware clock with
a vendor control request. Streaming fails when the hardware clock differs
from the rate selected for the USB endpoint.

During stream preparation, read the hardware rate and send the rate
request only when it differs from the selected endpoint rate. The control
transfer can complete before the device reports the new clock rate, so
poll readback every 25 ms and continue as soon as it matches. Forty
attempts avoid hammering the control endpoint while bounding an
unresponsive transition to one second.

Run the transaction from the existing format-setup quirk, after ALSA has
selected the endpoint rate and before data URBs are submitted. Hold the
USB-audio device mutex so playback and capture preparation cannot issue
overlapping clock changes.

Apply the quirk to:

  0582:0120  Roland OCTA-CAPTURE
  0582:012f  Roland QUAD-CAPTURE

Tested on physical OCTA-CAPTURE and QUAD-CAPTURE units. Rate changes
followed by full-duplex streaming succeeded at 44.1, 48, 96 and 192 kHz
on both. External digital clocking on the OCTA-CAPTURE was tested at all
supported rates: 44.1, 48 and 96 kHz. The OCTA-CAPTURE disables its
digital input and output at 192 kHz, so external clocking is unavailable
at that rate.

Signed-off-by: Jonathan Seth Mainguy <jon@soh.re>
---
 sound/usb/quirks.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 91938172912a..4936d66f9591 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -3,6 +3,7 @@
  */
 
 #include <linux/cleanup.h>
+#include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -1855,6 +1856,75 @@ static int rme_digiface_set_format_quirk(struct snd_usb_substream *subs)
 	return 0;
 }
 
+#define ROLAND_CAPTURE_RATE_REQUEST		3
+#define ROLAND_CAPTURE_RATE_READ_VALUE		0x0001
+#define ROLAND_CAPTURE_RATE_WRITE_VALUE		0x0008
+#define ROLAND_CAPTURE_RATE_WRITE_PREFIX	0x40
+#define ROLAND_CAPTURE_RATE_RETRIES		40
+#define ROLAND_CAPTURE_RATE_POLL_MS		25
+
+/*
+ * OCTA-CAPTURE and QUAD-CAPTURE use the same vendor request for their
+ * hardware clock.  A read returns the 24-bit little-endian rate followed by
+ * a transition-status byte.  A write carries 0x40 followed by the rate.
+ */
+static int roland_capture_read_rate(struct usb_device *dev, u32 *rate)
+{
+	u8 data[4];
+	int err;
+
+	err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+			      ROLAND_CAPTURE_RATE_REQUEST,
+			      USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      ROLAND_CAPTURE_RATE_READ_VALUE, 0,
+			      data, sizeof(data));
+	if (err != sizeof(data))
+		return err < 0 ? err : -EIO;
+
+	*rate = combine_triple(data);
+	return 0;
+}
+
+static void roland_capture_set_rate(struct snd_usb_substream *subs)
+{
+	struct snd_usb_audio *chip = subs->stream->chip;
+	struct usb_device *dev = chip->dev;
+	u32 rate = subs->data_endpoint->cur_rate;
+	u32 current_rate;
+	u8 data[4];
+	int err;
+	int i;
+
+	/* Serialize playback and capture endpoint starts during a clock change. */
+	guard(mutex)(&chip->mutex);
+	err = roland_capture_read_rate(dev, &current_rate);
+	if (!err && current_rate == rate)
+		return;
+
+	data[0] = ROLAND_CAPTURE_RATE_WRITE_PREFIX;
+	data[1] = rate;
+	data[2] = rate >> 8;
+	data[3] = rate >> 16;
+	err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+			      ROLAND_CAPTURE_RATE_REQUEST,
+			      USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      ROLAND_CAPTURE_RATE_WRITE_VALUE, 0,
+			      data, sizeof(data));
+	if (err != sizeof(data)) {
+		usb_audio_warn(chip, "cannot set Roland sample rate to %u Hz: %d\n",
+			       rate, err < 0 ? err : -EIO);
+		return;
+	}
+
+	for (i = 0; i < ROLAND_CAPTURE_RATE_RETRIES; i++) {
+		err = roland_capture_read_rate(dev, &current_rate);
+		if (!err && current_rate == rate)
+			return;
+		msleep(ROLAND_CAPTURE_RATE_POLL_MS);
+	}
+	usb_audio_warn(chip, "Roland sample rate did not reach %u Hz\n", rate);
+}
+
 void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 			      const struct audioformat *fmt)
 {
@@ -1885,6 +1955,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
 	case USB_ID(0x2a39, 0x3fa0): /* RME Digiface USB (alternate) */
 		rme_digiface_set_format_quirk(subs);
 		break;
+	case USB_ID(0x0582, 0x0120): /* Roland OCTA-CAPTURE */
+	case USB_ID(0x0582, 0x012f): /* Roland QUAD-CAPTURE */
+		roland_capture_set_rate(subs);
+		break;
 	}
 }
 
-- 
2.55.0


  parent reply	other threads:[~2026-08-29  0:51 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-29  0:49 [PATCH 0/4] ALSA: usb-audio: support Roland Capture sample rates Jonathan Seth Mainguy
2026-08-29  0:49 ` [PATCH 1/4] ALSA: usb-audio: add Roland OCTA-CAPTURE multirate support Jonathan Seth Mainguy
2026-08-29  0:49 ` [PATCH 2/4] ALSA: usb-audio: expose OCTA-CAPTURE control MIDI cables Jonathan Seth Mainguy
2026-08-29  0:50 ` [PATCH 3/4] ALSA: usb-audio: add Roland QUAD-CAPTURE multirate support Jonathan Seth Mainguy
2026-08-29  0:50 ` Jonathan Seth Mainguy [this message]
2026-08-31  8:30 ` [PATCH 0/4] ALSA: usb-audio: support Roland Capture sample rates Takashi Iwai

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=20260829005001.534571-5-jon@soh.re \
    --to=jon@soh.re \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=niklas@aldervall.se \
    --cc=perex@perex.cz \
    --cc=tiwai@suse.com \
    /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