Commit 41c25e19 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: usb-audio: More relaxed check of MIDI jack names

The USB audio driver tries to retrieve MIDI jack name strings that can
be used for rawmidi substream names and sequencer port names, but its
checking is too strict: often the firmware provides the jack info for
unexpected directions, and then we miss the info although it's
present.

In this patch, the code to extract the jack info is changed to allow
both in and out directions in a single loop.  That is, the former two
functions to obtain the descriptor pointers for jack in and out are
changed to a single function that returns iJack of the corresponding
jack ID, no matter which direction is used.  It's a code
simplification at the same time as well as the fix.

Fixes: eb596e0f ("ALSA: usb-audio: generate midi streaming substream names from jack names")
Link: https://lore.kernel.org/r/20240215153144.26047-1-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 32f03f40
...@@ -1742,50 +1742,44 @@ static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, ...@@ -1742,50 +1742,44 @@ 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( /* return iJack for the corresponding jackID */
struct usb_host_interface *hostif, uint8_t jack_id) static int find_usb_ijack(struct usb_host_interface *hostif, uint8_t jack_id)
{ {
unsigned char *extra = hostif->extra; unsigned char *extra = hostif->extra;
int extralen = hostif->extralen; int extralen = hostif->extralen;
struct usb_descriptor_header *h;
struct usb_midi_out_jack_descriptor *outjd;
struct usb_midi_in_jack_descriptor *injd;
size_t sz;
while (extralen > 4) { while (extralen > 4) {
struct usb_midi_in_jack_descriptor *injd = h = (struct usb_descriptor_header *)extra;
(struct usb_midi_in_jack_descriptor *)extra; if (h->bDescriptorType != USB_DT_CS_INTERFACE)
goto next;
outjd = (struct usb_midi_out_jack_descriptor *)h;
if (h->bLength >= sizeof(*outjd) &&
outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK &&
outjd->bJackID == jack_id) {
sz = USB_DT_MIDI_OUT_SIZE(outjd->bNrInputPins);
if (outjd->bLength < sz)
goto next;
return *(extra + sz - 1);
}
injd = (struct usb_midi_in_jack_descriptor *)h;
if (injd->bLength >= sizeof(*injd) && if (injd->bLength >= sizeof(*injd) &&
injd->bDescriptorType == USB_DT_CS_INTERFACE &&
injd->bDescriptorSubtype == UAC_MIDI_IN_JACK && injd->bDescriptorSubtype == UAC_MIDI_IN_JACK &&
injd->bJackID == jack_id) injd->bJackID == jack_id)
return injd; return injd->iJack;
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) { next:
struct usb_midi_out_jack_descriptor *outjd =
(struct usb_midi_out_jack_descriptor *)extra;
if (outjd->bLength >= sizeof(*outjd) &&
outjd->bDescriptorType == USB_DT_CS_INTERFACE &&
outjd->bDescriptorSubtype == UAC_MIDI_OUT_JACK &&
outjd->bJackID == jack_id)
return outjd;
if (!extra[0]) if (!extra[0])
break; break;
extralen -= extra[0]; extralen -= extra[0];
extra += extra[0]; extra += extra[0];
} }
return NULL; return 0;
} }
static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
...@@ -1796,13 +1790,10 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, ...@@ -1796,13 +1790,10 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
const char *name_format; const char *name_format;
struct usb_interface *intf; struct usb_interface *intf;
struct usb_host_interface *hostif; 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 jack_name_buf[32];
uint8_t *default_jack_name = "MIDI"; uint8_t *default_jack_name = "MIDI";
uint8_t *jack_name = default_jack_name; uint8_t *jack_name = default_jack_name;
uint8_t iJack; uint8_t iJack;
size_t sz;
int res; int res;
struct snd_rawmidi_substream *substream = struct snd_rawmidi_substream *substream =
...@@ -1816,21 +1807,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi, ...@@ -1816,21 +1807,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
intf = umidi->iface; intf = umidi->iface;
if (intf && jack_id >= 0) { if (intf && jack_id >= 0) {
hostif = intf->cur_altsetting; hostif = intf->cur_altsetting;
iJack = 0; iJack = find_usb_ijack(hostif, jack_id);
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);
if (outjd->bLength >= sz)
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) { if (iJack != 0) {
res = usb_string(umidi->dev, iJack, jack_name_buf, res = usb_string(umidi->dev, iJack, jack_name_buf,
ARRAY_SIZE(jack_name_buf)); ARRAY_SIZE(jack_name_buf));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment