[PATCH 2/2] midi streaming substream names from jack names A number of devices have named substreams which are hard to remember / decypher from <device> MIDI n names. Eg. Korg puts a pass through on one substream and iConnectivity devices name the connections.

From: George Harker
Date: Fri Feb 26 2021 - 16:28:13 EST


This makes it easier to connect to the correct device. Devices which
handle naming through quirks are unaffected by this change.

Addresses TODO comment in sound/usb/midi.c

Signed-off-by: George Harker <george@xxxxxxxxxxxxxxxxxxxxx>
---
sound/usb/midi.c | 103 ++++++++++++++++++++++++++++++++++++++++++++---
sound/usb/midi.h | 2 +
2 files changed, 100 insertions(+), 5 deletions(-)

diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 610cf54ee..9efda4b06 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1740,12 +1740,68 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,
}
}

+static struct usb_midi_in_jack_descriptor *find_usb_in_jack_descriptor(
+ struct usb_host_interface *hostif, uint8_t jack_id)
+{
+ unsigned char *extra = hostif->extra;
+ int extralen = hostif->extralen;
+
+ while (extralen > 4) {
+ struct usb_midi_in_jack_descriptor *injd =
+ (struct usb_midi_in_jack_descriptor *)extra;
+
+ if (injd->bLength > 4 &&
+ injd->bDescriptorType == USB_DT_CS_INTERFACE &&
+ injd->bDescriptorSubtype == UAC_MIDI_IN_JACK &&
+ injd->bJackID == jack_id)
+ return injd;
+ if (!extra[0])
+ break;
+ extralen -= extra[0];
+ extra += extra[0];
+ }
+ return NULL;
+}
+
+static struct usb_midi_out_jack_descriptor *find_usb_out_jack_descriptor(
+ struct usb_host_interface *hostif, uint8_t jack_id)
+{
+ unsigned char *extra = hostif->extra;
+ int extralen = hostif->extralen;
+
+ while (extralen > 4) {
+ struct usb_midi_out_jack_descriptor *outjd =
+ (struct usb_midi_out_jack_descriptor *)extra;
+
+ if (outjd->bLength > 4 &&
+ outjd->bDescriptorType == USB_DT_CS_INTERFACE &&
+ outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK &&
+ outjd->bJackID == jack_id)
+ return outjd;
+ if (!extra[0])
+ break;
+ extralen -= extra[0];
+ extra += extra[0];
+ }
+ return NULL;
+}
+
static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
- int stream, int number,
+ int stream, int number, int jack_id,
struct snd_rawmidi_substream **rsubstream)
{
struct port_info *port_info;
const char *name_format;
+ struct usb_interface *intf;
+ struct usb_host_interface *hostif;
+ struct usb_midi_in_jack_descriptor *injd;
+ struct usb_midi_out_jack_descriptor *outjd;
+ uint8_t jack_name_buf[32];
+ uint8_t *default_jack_name = "MIDI";
+ uint8_t *jack_name = default_jack_name;
+ uint8_t iJack;
+ size_t sz;
+ int res;

struct snd_rawmidi_substream *substream =
snd_usbmidi_find_substream(umidi, stream, number);
@@ -1755,11 +1811,36 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
return;
}

- /* TODO: read port name from jack descriptor */
+ intf = umidi->iface;
+ if (intf && jack_id >= 0) {
+ hostif = intf->cur_altsetting;
+ iJack = 0;
+ if (stream != SNDRV_RAWMIDI_STREAM_OUTPUT) {
+ /* in jacks connect to outs */
+ outjd = find_usb_out_jack_descriptor(hostif, jack_id);
+ if (outjd) {
+ sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins);
+ iJack = *(((uint8_t *) outjd) + sz - sizeof(uint8_t));
+ }
+ } else {
+ /* and out jacks connect to ins */
+ injd = find_usb_in_jack_descriptor(hostif, jack_id);
+ if (injd)
+ iJack = injd->iJack;
+ }
+ if (iJack != 0) {
+ res = usb_string(umidi->dev, iJack, jack_name_buf,
+ ARRAY_SIZE(jack_name_buf));
+ if (res)
+ jack_name = jack_name_buf;
+ }
+ }
+
port_info = find_port_info(umidi, number);
- name_format = port_info ? port_info->name : "%s MIDI %d";
+ name_format = port_info ? port_info->name :
+ (jack_name != default_jack_name ? "%s %s" : "%s %s %d");
snprintf(substream->name, sizeof(substream->name),
- name_format, umidi->card->shortname, number + 1);
+ name_format, umidi->card->shortname, jack_name, number + 1);

*rsubstream = substream;
}
@@ -1794,6 +1875,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi,
snd_usbmidi_init_substream(umidi,
SNDRV_RAWMIDI_STREAM_OUTPUT,
out_ports,
+ endpoints[i].assoc_out_jacks[j],
&umidi->endpoints[i].out->ports[j].substream);
++out_ports;
}
@@ -1801,6 +1883,7 @@ static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi,
snd_usbmidi_init_substream(umidi,
SNDRV_RAWMIDI_STREAM_INPUT,
in_ports,
+ endpoints[i].assoc_in_jacks[j],
&umidi->endpoints[i].in->ports[j].substream);
++in_ports;
}
@@ -1846,7 +1929,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi,
struct usb_host_endpoint *hostep;
struct usb_endpoint_descriptor *ep;
struct usb_ms_endpoint_descriptor *ms_ep;
- int i, epidx;
+ int i, j, epidx;

intf = umidi->iface;
if (!intf)
@@ -1895,6 +1978,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi,
endpoints[epidx].out_interval = 1;
endpoints[epidx].out_cables =
(1 << ms_ep->bNumEmbMIDIJack) - 1;
+ for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j)
+ endpoints[epidx].assoc_out_jacks[j] = ms_ep->baAssocJackID[j];
+ for (; j < ARRAY_SIZE(endpoints[epidx].assoc_out_jacks); ++j)
+ endpoints[epidx].assoc_out_jacks[j] = -1;
dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
} else {
@@ -1912,6 +1999,10 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi,
endpoints[epidx].in_interval = 1;
endpoints[epidx].in_cables =
(1 << ms_ep->bNumEmbMIDIJack) - 1;
+ for (j = 0; j < ms_ep->bNumEmbMIDIJack; ++j)
+ endpoints[epidx].assoc_in_jacks[j] = ms_ep->baAssocJackID[j];
+ for (; j < ARRAY_SIZE(endpoints[epidx].assoc_in_jacks); ++j)
+ endpoints[epidx].assoc_in_jacks[j] = -1;
dev_dbg(&umidi->dev->dev, "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
}
@@ -2228,11 +2319,13 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi,
snd_usbmidi_init_substream(umidi,
SNDRV_RAWMIDI_STREAM_OUTPUT,
cable,
+ -1 /* prevent trying to find jack */,
&umidi->endpoints[cable & 1].out->ports[cable].substream);
if (endpoint->in_cables & (1 << cable))
snd_usbmidi_init_substream(umidi,
SNDRV_RAWMIDI_STREAM_INPUT,
cable,
+ -1 /* prevent trying to find jack */,
&umidi->endpoints[0].in->ports[cable].substream);
}
return 0;
diff --git a/sound/usb/midi.h b/sound/usb/midi.h
index 8c38aec22..3f153195c 100644
--- a/sound/usb/midi.h
+++ b/sound/usb/midi.h
@@ -13,6 +13,8 @@ struct snd_usb_midi_endpoint_info {
uint8_t in_interval;
uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */
+ int16_t assoc_in_jacks[16];
+ int16_t assoc_out_jacks[16];
};

/* for QUIRK_MIDI_YAMAHA, data is NULL */
--
2.20.1