All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: alsa-devel@alsa-project.org, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 3/7] usb: gadget: midi2: Dynamically create MIDI 1.0 altset descriptors
Date: Tue, 25 Jul 2023 08:22:02 +0200	[thread overview]
Message-ID: <20230725062206.9674-4-tiwai@suse.de> (raw)
In-Reply-To: <20230725062206.9674-1-tiwai@suse.de>

This patch extends MIDI 2.0 function driver to deal with more MIDI1
Jacks depending on the given Block configuration.

For MIDI 1.0, we take the configuration given in Function Block 0, and
create MIDI Jacks and Endpoints depending on the definition there.
That is, when more UMP Groups are defined in the Block 0, the
corresponding MIDI1 Jacks will be created.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
 drivers/usb/gadget/function/f_midi2.c | 228 ++++++++++++++++++--------
 1 file changed, 157 insertions(+), 71 deletions(-)

diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c
index c68a6fa0d237..b15d832ff441 100644
--- a/drivers/usb/gadget/function/f_midi2.c
+++ b/drivers/usb/gadget/function/f_midi2.c
@@ -151,7 +151,7 @@ static struct usb_ms20_gr_trm_block_descriptor gtb_desc = {
 };
 
 DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
-DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
+DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
 DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
 DECLARE_USB_MS20_ENDPOINT_DESCRIPTOR(32);
 
@@ -185,7 +185,7 @@ static struct usb_interface_descriptor midi2_midi1_if_desc = {
 	.bDescriptorType =	USB_DT_INTERFACE,
 	.bInterfaceNumber =	0, // to be filled
 	.bAlternateSetting =	0,
-	.bNumEndpoints =	2,
+	.bNumEndpoints =	2, // to be filled
 	.bInterfaceClass =	USB_CLASS_AUDIO,
 	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,
 	.bInterfaceProtocol =	0,
@@ -200,50 +200,6 @@ static struct usb_ms_header_descriptor midi2_midi1_class_desc = {
 	.wTotalLength =		__cpu_to_le16(0x41), // to be calculated
 };
 
-/* MIDI 1.0 IN (Embedded) Jack */
-static struct usb_midi_in_jack_descriptor midi2_midi1_in_jack1_desc = {
-	.bLength =		0x06,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_IN_JACK,
-	.bJackType =		USB_MS_EMBEDDED,
-	.bJackID =		0x01,
-	.iJack =		0,
-};
-
-/* MIDI 1.0 IN (External) Jack */
-static struct usb_midi_in_jack_descriptor midi2_midi1_in_jack2_desc = {
-	.bLength =		0x06,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_IN_JACK,
-	.bJackType =		USB_MS_EXTERNAL,
-	.bJackID =		0x02,
-	.iJack =		0,
-};
-
-/* MIDI 1.0 OUT (Embedded) Jack */
-static struct usb_midi_out_jack_descriptor_1 midi2_midi1_out_jack1_desc = {
-	.bLength =		0x09,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
-	.bJackType =		USB_MS_EMBEDDED,
-	.bJackID =		0x03,
-	.bNrInputPins =		1,
-	.pins =			{ { 0x02, 0x01 } },
-	.iJack =		0,
-};
-
-/* MIDI 1.0 OUT (External) Jack */
-static struct usb_midi_out_jack_descriptor_1 midi2_midi1_out_jack2_desc = {
-	.bLength =		0x09,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
-	.bJackType =		USB_MS_EXTERNAL,
-	.bJackID =		0x04,
-	.bNrInputPins =		1,
-	.pins =			{ { 0x01, 0x01 } },
-	.iJack =		0,
-};
-
 /* MIDI 1.0 EP OUT */
 static struct usb_endpoint_descriptor midi2_midi1_ep_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
@@ -257,8 +213,8 @@ static struct usb_ss_ep_comp_descriptor midi2_midi1_ep_out_ss_comp_desc = {
 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_ms_endpoint_descriptor_1 midi2_midi1_ep_out_class_desc = {
-	.bLength =		0x05,
+static struct usb_ms_endpoint_descriptor_16 midi2_midi1_ep_out_class_desc = {
+	.bLength =		0x05, // to be filled
 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
 	.bDescriptorSubtype =	USB_MS_GENERAL,
 	.bNumEmbMIDIJack =	1,
@@ -278,8 +234,8 @@ static struct usb_ss_ep_comp_descriptor midi2_midi1_ep_in_ss_comp_desc = {
 	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
 };
 
-static struct usb_ms_endpoint_descriptor_1 midi2_midi1_ep_in_class_desc = {
-	.bLength =		0x05,
+static struct usb_ms_endpoint_descriptor_16 midi2_midi1_ep_in_class_desc = {
+	.bLength =		0x05, // to be filled
 	.bDescriptorType =	USB_DT_CS_ENDPOINT,
 	.bDescriptorSubtype =	USB_MS_GENERAL,
 	.bNumEmbMIDIJack =	1,
@@ -337,25 +293,29 @@ static void *midi2_audio_descs[] = {
 static void *midi2_midi1_descs[] = {
 	&midi2_midi1_if_desc,
 	&midi2_midi1_class_desc,
-	&midi2_midi1_in_jack1_desc,
-	&midi2_midi1_in_jack2_desc,
-	&midi2_midi1_out_jack1_desc,
-	&midi2_midi1_out_jack2_desc,
 	NULL
 };
 
-static void *midi2_midi1_ep_descs[] = {
+static void *midi2_midi1_ep_out_descs[] = {
 	&midi2_midi1_ep_out_desc,
 	&midi2_midi1_ep_out_class_desc,
+	NULL
+};
+
+static void *midi2_midi1_ep_in_descs[] = {
 	&midi2_midi1_ep_in_desc,
 	&midi2_midi1_ep_in_class_desc,
 	NULL
 };
 
-static void *midi2_midi1_ep_ss_descs[] = {
+static void *midi2_midi1_ep_out_ss_descs[] = {
 	&midi2_midi1_ep_out_desc,
 	&midi2_midi1_ep_out_ss_comp_desc,
 	&midi2_midi1_ep_out_class_desc,
+	NULL
+};
+
+static void *midi2_midi1_ep_in_ss_descs[] = {
 	&midi2_midi1_ep_in_desc,
 	&midi2_midi1_ep_in_ss_comp_desc,
 	&midi2_midi1_ep_in_class_desc,
@@ -1197,6 +1157,11 @@ struct f_midi2_usb_config {
 	struct usb_descriptor_header **list;
 	unsigned int size;
 	unsigned int alloc;
+
+	/* MIDI 1.0 jacks */
+	unsigned char jack_in, jack_out, jack_id;
+	struct usb_midi_in_jack_descriptor jack_ins[16];
+	struct usb_midi_out_jack_descriptor_1 jack_outs[16];
 };
 
 static int append_config(struct f_midi2_usb_config *config, void *d)
@@ -1231,12 +1196,61 @@ static int append_configs(struct f_midi2_usb_config *config, void **d)
 	return 0;
 }
 
+static int append_midi1_in_jack(struct f_midi2 *midi2,
+				struct f_midi2_usb_config *config,
+				unsigned int type)
+{
+	struct usb_midi_in_jack_descriptor *jack =
+		&config->jack_ins[config->jack_in++];
+	int id = ++config->jack_id;
+	int err;
+
+	jack->bLength = 0x06;
+	jack->bDescriptorType = USB_DT_CS_INTERFACE;
+	jack->bDescriptorSubtype = USB_MS_MIDI_IN_JACK;
+	jack->bJackType = type;
+	jack->bJackID = id;
+	jack->iJack = midi2->strings[STR_GTB1].id; // TODO: better names?
+
+	err = append_config(config, jack);
+	if (err < 0)
+		return err;
+	return id;
+}
+
+static int append_midi1_out_jack(struct f_midi2 *midi2,
+				 struct f_midi2_usb_config *config,
+				 unsigned int type, unsigned int source)
+{
+	struct usb_midi_out_jack_descriptor_1 *jack =
+		&config->jack_outs[config->jack_out++];
+	int id = ++config->jack_id;
+	int err;
+
+	jack->bLength = 0x09;
+	jack->bDescriptorType = USB_DT_CS_INTERFACE;
+	jack->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK;
+	jack->bJackType = type;
+	jack->bJackID = id;
+	jack->bNrInputPins = 1;
+	jack->pins[0].baSourceID = source;
+	jack->pins[0].baSourcePin = 0x01;
+	jack->iJack = midi2->strings[STR_GTB1].id; // TODO: better names?
+
+	err = append_config(config, jack);
+	if (err < 0)
+		return err;
+	return id;
+}
+
 static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
 				      struct f_midi2_usb_config *config,
 				      int speed)
 {
-	void **midi1_eps;
-	int i, err;
+	struct f_midi2_block *blk = &midi2->midi2_eps[0].blks[0];
+	void **midi1_in_eps, **midi1_out_eps;
+	int i, jack, total;
+	int err;
 
 	switch (speed) {
 	default:
@@ -1248,7 +1262,8 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
 				cpu_to_le16(512);
 		fallthrough;
 	case USB_SPEED_FULL:
-		midi1_eps = midi2_midi1_ep_descs;
+		midi1_in_eps = midi2_midi1_ep_in_descs;
+		midi1_out_eps = midi2_midi1_ep_out_descs;
 		break;
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER_PLUS:
@@ -1257,19 +1272,85 @@ static int f_midi2_create_usb_configs(struct f_midi2 *midi2,
 		for (i = 0; i < midi2->num_eps; i++)
 			midi2_midi2_ep_out_desc[i].wMaxPacketSize =
 				cpu_to_le16(1024);
-		midi1_eps = midi2_midi1_ep_ss_descs;
+		midi1_in_eps = midi2_midi1_ep_in_ss_descs;
+		midi1_out_eps = midi2_midi1_ep_out_ss_descs;
 		break;
 	}
 
 	err = append_configs(config, midi2_audio_descs);
 	if (err < 0)
 		return err;
+
+	switch (blk->info.direction) {
+	case SNDRV_UMP_DIR_INPUT:
+	case SNDRV_UMP_DIR_OUTPUT:
+		midi2_midi1_if_desc.bNumEndpoints = 1;
+		break;
+	default:
+		midi2_midi1_if_desc.bNumEndpoints = 2;
+		break;
+	}
+
 	err = append_configs(config, midi2_midi1_descs);
 	if (err < 0)
 		return err;
-	err = append_configs(config, midi1_eps);
-	if (err < 0)
-		return err;
+
+	total = USB_DT_MS_HEADER_SIZE;
+	if (blk->info.direction != SNDRV_UMP_DIR_INPUT) {
+		midi2_midi1_ep_out_class_desc.bLength =
+			USB_DT_MS_ENDPOINT_SIZE(blk->info.num_groups);
+		total += midi2_midi1_ep_out_class_desc.bLength;
+		midi2_midi1_ep_out_class_desc.bNumEmbMIDIJack =
+			blk->info.num_groups;
+		total += blk->info.num_groups *
+			(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
+		for (i = 0; i < blk->info.num_groups; i++) {
+			jack = append_midi1_in_jack(midi2, config,
+						    USB_MS_EMBEDDED);
+			if (jack < 0)
+				return jack;
+			midi2_midi1_ep_out_class_desc.baAssocJackID[i] = jack;
+			jack = append_midi1_out_jack(midi2, config,
+						     USB_MS_EXTERNAL, jack);
+			if (jack < 0)
+				return jack;
+		}
+	}
+
+	if (blk->info.direction != SNDRV_UMP_DIR_OUTPUT) {
+		midi2_midi1_ep_in_class_desc.bLength =
+			USB_DT_MS_ENDPOINT_SIZE(blk->info.num_groups);
+		total += midi2_midi1_ep_in_class_desc.bLength;
+		midi2_midi1_ep_in_class_desc.bNumEmbMIDIJack =
+			blk->info.num_groups;
+		total += blk->info.num_groups *
+			(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
+		for (i = 0; i < blk->info.num_groups; i++) {
+			jack = append_midi1_in_jack(midi2, config,
+						    USB_MS_EXTERNAL);
+			if (jack < 0)
+				return jack;
+			jack = append_midi1_out_jack(midi2, config,
+						     USB_MS_EMBEDDED, jack);
+			if (jack < 0)
+				return jack;
+			midi2_midi1_ep_in_class_desc.baAssocJackID[i] = jack;
+		}
+	}
+
+	midi2_midi1_class_desc.wTotalLength = cpu_to_le16(total);
+
+	if (blk->info.direction != SNDRV_UMP_DIR_INPUT) {
+		err = append_configs(config, midi1_out_eps);
+		if (err < 0)
+			return err;
+	}
+	if (blk->info.direction != SNDRV_UMP_DIR_OUTPUT) {
+		err = append_configs(config, midi1_in_eps);
+		if (err < 0)
+			return err;
+	}
+
 	err = append_configs(config, midi2_midi2_descs);
 	if (err < 0)
 		return err;
@@ -1421,14 +1502,19 @@ static int f_midi2_bind(struct usb_configuration *c, struct usb_function *f)
 	midi2_audio_class_desc.baInterfaceNr[0] = status;
 
 	/* allocate instance-specific endpoints */
-	status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_in,
-				 &midi2_midi1_ep_in_desc, 0, NULL);
-	if (status)
-		goto fail;
-	status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_out,
-				 &midi2_midi1_ep_out_desc, 0, NULL);
-	if (status)
-		goto fail;
+	if (midi2->midi2_eps[0].blks[0].info.direction != SNDRV_UMP_DIR_OUTPUT) {
+		status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_in,
+					 &midi2_midi1_ep_in_desc, 0, NULL);
+		if (status)
+			goto fail;
+	}
+
+	if (midi2->midi2_eps[0].blks[0].info.direction != SNDRV_UMP_DIR_INPUT) {
+		status = f_midi2_init_ep(midi2, NULL, &midi2->midi1_ep_out,
+					 &midi2_midi1_ep_out_desc, 0, NULL);
+		if (status)
+			goto fail;
+	}
 
 	for (i = 0; i < midi2->num_eps; i++) {
 		status = f_midi2_init_midi2_ep_in(midi2, i);
-- 
2.35.3


  parent reply	other threads:[~2023-07-25  6:22 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-25  6:21 [PATCH 0/7] usb: Add USB MIDI 2.0 Gadget Function Driver Takashi Iwai
2023-07-25  6:22 ` [PATCH 1/7] usb: gadget: Add support for USB MIDI 2.0 function driver Takashi Iwai
2023-07-25  6:22 ` [PATCH 2/7] usb: gadget: midi2: Add configfs support Takashi Iwai
2023-07-25  6:22 ` Takashi Iwai [this message]
2023-07-25  6:22 ` [PATCH 4/7] usb: gadget: midi2: MIDI 1.0 interface (altset 0) support Takashi Iwai
2023-07-25  6:22 ` [PATCH 5/7] usb: gadget: midi2: Add testing documentation Takashi Iwai
2023-07-25  6:22 ` [PATCH 6/7] usb: gadget: midi2: Add "Operation Mode" control Takashi Iwai
2023-07-25  6:22 ` [PATCH 7/7] usb: gadget: midi2: More flexible MIDI 1.0 configuration Takashi Iwai
2023-07-25 16:29 ` [PATCH 0/7] usb: Add USB MIDI 2.0 Gadget Function Driver Greg Kroah-Hartman
2023-07-31 12:47 ` Symbolic Debugger
2023-08-01  4:28   ` Symbolic Debugger

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=20230725062206.9674-4-tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@alsa-project.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.