]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: usb-audio: rotate standard MIDI output port scan
authorCássio Gabriel <cassiogabrielcontato@gmail.com>
Mon, 23 Mar 2026 13:46:24 +0000 (10:46 -0300)
committerTakashi Iwai <tiwai@suse.de>
Fri, 27 Mar 2026 13:40:24 +0000 (14:40 +0100)
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>
Link: https://patch.msgid.link/20260323-usbmidi-port-fairness-v1-1-2d68e97592a1@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/midi.c

index a8bddc90c0ed6bba8b7a46d131d50c0c39a0d183..0a5b8941ebdaaf327944ed2e4b80946a33e1dba8 100644 (file)
@@ -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 = {