[PATCH] ALSA: usb-audio: rotate standard MIDI output port scan

Cássio Gabriel posted 1 patch 1 week, 4 days ago
sound/usb/midi.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
[PATCH] ALSA: usb-audio: rotate standard MIDI output port scan
Posted by Cássio Gabriel 1 week, 4 days ago
snd_usbmidi_standard_output() iterates output ports in ascending order
and drains each active port until the URB is full. On interfaces where
multiple USB-MIDI cables share one endpoint, sustained traffic on a
lower-numbered port can consume every refill before higher-numbered
ports are even examined.

That behavior dates back to the original implementation and still
applies with the current multi-URB output path. snd_usbmidi_do_output()
can refill several idle URBs in one pass, but each refill restarts the
scan at port 0, so a busy lower-numbered port can keep higher-numbered
ports from making progress at all.

Use ep->current_port as the starting point of the scan and advance it
after each URB fill. This keeps the existing packet formatting and
per-port state handling intact while preventing persistent starvation of
higher-numbered ports.

Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
---
 sound/usb/midi.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index a8bddc90c0ed..0a5b8941ebda 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -699,15 +699,18 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port *port,
 static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep,
 					struct urb *urb)
 {
-	int p;
+	int port0 = ep->current_port;
+	int i;
+
+	for (i = 0; i < 0x10; ++i) {
+		int portnum = (port0 + i) & 15;
+		struct usbmidi_out_port *port = &ep->ports[portnum];
 
-	/* FIXME: lower-numbered ports can starve higher-numbered ports */
-	for (p = 0; p < 0x10; ++p) {
-		struct usbmidi_out_port *port = &ep->ports[p];
 		if (!port->active)
 			continue;
 		while (urb->transfer_buffer_length + 3 < ep->max_transfer) {
 			uint8_t b;
+
 			if (snd_rawmidi_transmit(port->substream, &b, 1) != 1) {
 				port->active = 0;
 				break;
@@ -715,6 +718,7 @@ static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep,
 			snd_usbmidi_transmit_byte(port, b, urb);
 		}
 	}
+	ep->current_port = (port0 + 1) & 15;
 }
 
 static const struct usb_protocol_ops snd_usbmidi_standard_ops = {

---
base-commit: b3c48fa1fb397b490101785ddd87caf2e5513a66
change-id: 20260323-usbmidi-port-fairness-4301533ef31a

Best regards,
-- 
Cássio Gabriel <cassiogabrielcontato@gmail.com>

Re: [PATCH] ALSA: usb-audio: rotate standard MIDI output port scan
Posted by Takashi Iwai 1 week ago
On Mon, 23 Mar 2026 14:46:24 +0100,
Cássio Gabriel wrote:
> 
> snd_usbmidi_standard_output() iterates output ports in ascending order
> and drains each active port until the URB is full. On interfaces where
> multiple USB-MIDI cables share one endpoint, sustained traffic on a
> lower-numbered port can consume every refill before higher-numbered
> ports are even examined.
> 
> That behavior dates back to the original implementation and still
> applies with the current multi-URB output path. snd_usbmidi_do_output()
> can refill several idle URBs in one pass, but each refill restarts the
> scan at port 0, so a busy lower-numbered port can keep higher-numbered
> ports from making progress at all.
> 
> Use ep->current_port as the starting point of the scan and advance it
> after each URB fill. This keeps the existing packet formatting and
> per-port state handling intact while preventing persistent starvation of
> higher-numbered ports.
> 
> Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>

Looks like a nice logical improvement.

Applied to for-next branch now.  Thanks.


Takashi