[PATCH] USB: gadget: fix MIDI gadget jack allocation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The dynamic jack allocation of the MIDI gadget currently links all
external jacks to one single instance of an embedded jack. According to
chapter 3.3.1 of the USB MIDI 1.0 spec, this is only valid if these
streams always carry the same data stream.

Also, with the current implementation, Windows 7(tm) will blue-screen
instantly once a device featuring more than one input and output MIDI
port connected.

While at it, and because it grew again by this change, allocate the
temporary function pointer list on the heap, not on the stack.

Signed-off-by: Daniel Mack <zonque@xxxxxxxxx>
Cc: Greg Kroah-Hartman <gregkh@xxxxxxx>
Cc: Felipe Balbi <balbi@xxxxxx>
---
 drivers/usb/gadget/f_midi.c |  139 ++++++++++++++++++++----------------------
 1 files changed, 66 insertions(+), 73 deletions(-)

diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
index 67b2229..b5ad4e1 100644
--- a/drivers/usb/gadget/f_midi.c
+++ b/drivers/usb/gadget/f_midi.c
@@ -95,7 +95,6 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req);
 
 DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
 DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
-DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16);
 DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
 
 /* B.3.1  Standard AC Interface Descriptor */
@@ -140,26 +139,6 @@ static struct usb_ms_header_descriptor ms_header_desc __initdata = {
 	/* .wTotalLength =	DYNAMIC */
 };
 
-/* B.4.3  Embedded MIDI IN Jack Descriptor */
-static struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
-	.bLength =	      USB_DT_MIDI_IN_SIZE,
-	.bDescriptorType =      USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =   USB_MS_MIDI_IN_JACK,
-	.bJackType =	    USB_MS_EMBEDDED,
-	/* .bJackID =		DYNAMIC */
-};
-
-/* B.4.4  Embedded MIDI OUT Jack Descriptor */
-static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = {
-	/* .bLength =		DYNAMIC */
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
-	.bJackType =		USB_MS_EMBEDDED,
-	/* .bJackID =		DYNAMIC */
-	/* .bNrInputPins =	DYNAMIC */
-	/* .pins =		DYNAMIC */
-};
-
 /* B.5.1  Standard Bulk OUT Endpoint Descriptor */
 static struct usb_endpoint_descriptor bulk_out_desc = {
 	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
@@ -758,9 +737,11 @@ fail:
 static int __init
 f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 {
-	struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12];
+	struct usb_descriptor_header **midi_function;
 	struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
+	struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS];
 	struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
+	struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS];
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_midi *midi = func_to_midi(f);
 	int status, n, jack = 1, i = 0;
@@ -798,6 +779,15 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 		goto fail;
 	midi->out_ep->driver_data = cdev;	/* claim */
 
+	/* allocate temporary function list */
+	midi_function = (struct usb_descriptor_header **)
+				kzalloc(sizeof(midi_function) *
+					((MAX_PORTS * 4) + 9), GFP_KERNEL);
+	if (!midi_function) {
+		status = -ENOMEM;
+		goto fail;
+	}
+
 	/*
 	 * construct the function's descriptor set. As the number of
 	 * input and output MIDI ports is configurable, we have to do
@@ -811,73 +801,74 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 
 	/* calculate the header's wTotalLength */
 	n = USB_DT_MS_HEADER_SIZE
-		+ (1 + midi->in_ports) * USB_DT_MIDI_IN_SIZE
-		+ (1 + midi->out_ports) * USB_DT_MIDI_OUT_SIZE(1);
+		+ (midi->in_ports + midi->out_ports) *
+			(USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1));
 	ms_header_desc.wTotalLength = cpu_to_le16(n);
 
 	midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc;
 
-	/* we have one embedded IN jack */
-	jack_in_emb_desc.bJackID = jack++;
-	midi_function[i++] = (struct usb_descriptor_header *) &jack_in_emb_desc;
-
-	/* and a dynamic amount of external IN jacks */
-	for (n = 0; n < midi->in_ports; n++) {
-		struct usb_midi_in_jack_descriptor *ext = &jack_in_ext_desc[n];
-
-		ext->bLength =			USB_DT_MIDI_IN_SIZE;
-		ext->bDescriptorType =		USB_DT_CS_INTERFACE;
-		ext->bDescriptorSubtype =	USB_MS_MIDI_IN_JACK;
-		ext->bJackType =		USB_MS_EXTERNAL;
-		ext->bJackID =			jack++;
-		ext->iJack =			0;
-
-		midi_function[i++] = (struct usb_descriptor_header *) ext;
-	}
-
-	/* one embedded OUT jack ... */
-	jack_out_emb_desc.bLength = USB_DT_MIDI_OUT_SIZE(midi->in_ports);
-	jack_out_emb_desc.bJackID = jack++;
-	jack_out_emb_desc.bNrInputPins = midi->in_ports;
-	/* ... which referencess all external IN jacks */
+	/* configure the external IN jacks, each linked to an embedded OUT jack */
 	for (n = 0; n < midi->in_ports; n++) {
-		jack_out_emb_desc.pins[n].baSourceID = jack_in_ext_desc[n].bJackID;
-		jack_out_emb_desc.pins[n].baSourcePin =	1;
+		struct usb_midi_in_jack_descriptor *in_ext = &jack_in_ext_desc[n];
+		struct usb_midi_out_jack_descriptor_1 *out_emb = &jack_out_emb_desc[n];
+
+		in_ext->bLength			= USB_DT_MIDI_IN_SIZE;
+		in_ext->bDescriptorType		= USB_DT_CS_INTERFACE;
+		in_ext->bDescriptorSubtype	= USB_MS_MIDI_IN_JACK;
+		in_ext->bJackType		= USB_MS_EXTERNAL;
+		in_ext->bJackID			= jack++;
+		in_ext->iJack			= 0;
+		midi_function[i++] = (struct usb_descriptor_header *) in_ext;
+
+		out_emb->bLength		= USB_DT_MIDI_OUT_SIZE(1);
+		out_emb->bDescriptorType	= USB_DT_CS_INTERFACE;
+		out_emb->bDescriptorSubtype	= USB_MS_MIDI_OUT_JACK;
+		out_emb->bJackType		= USB_MS_EMBEDDED;
+		out_emb->bJackID		= jack++;
+		out_emb->bNrInputPins		= 1;
+		out_emb->pins[0].baSourcePin	= 1;
+		out_emb->pins[0].baSourceID	= in_ext->bJackID;
+		out_emb->iJack			= 0;
+		midi_function[i++] = (struct usb_descriptor_header *) out_emb;
+
+		/* link it to the endpoint */
+		ms_in_desc.baAssocJackID[n] = out_emb->bJackID;
 	}
 
-	midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc;
-
-	/* and multiple external OUT jacks ... */
+	/* configure the external OUT jacks, each linked to an embedded IN jack */
 	for (n = 0; n < midi->out_ports; n++) {
-		struct usb_midi_out_jack_descriptor_1 *ext = &jack_out_ext_desc[n];
-		int m;
-
-		ext->bLength =			USB_DT_MIDI_OUT_SIZE(1);
-		ext->bDescriptorType =		USB_DT_CS_INTERFACE;
-		ext->bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK;
-		ext->bJackType =		USB_MS_EXTERNAL;
-		ext->bJackID =			jack++;
-		ext->bNrInputPins =		1;
-		ext->iJack =			0;
-		/* ... which all reference the same embedded IN jack */
-		for (m = 0; m < midi->out_ports; m++) {
-			ext->pins[m].baSourceID =	jack_in_emb_desc.bJackID;
-			ext->pins[m].baSourcePin =	1;
-		}
-
-		midi_function[i++] = (struct usb_descriptor_header *) ext;
+		struct usb_midi_in_jack_descriptor *in_emb = &jack_in_emb_desc[n];
+		struct usb_midi_out_jack_descriptor_1 *out_ext = &jack_out_ext_desc[n];
+
+		in_emb->bLength			= USB_DT_MIDI_IN_SIZE;
+		in_emb->bDescriptorType		= USB_DT_CS_INTERFACE;
+		in_emb->bDescriptorSubtype	= USB_MS_MIDI_IN_JACK;
+		in_emb->bJackType		= USB_MS_EMBEDDED;
+		in_emb->bJackID			= jack++;
+		in_emb->iJack			= 0;
+		midi_function[i++] = (struct usb_descriptor_header *) in_emb;
+
+		out_ext->bLength =		USB_DT_MIDI_OUT_SIZE(1);
+		out_ext->bDescriptorType =	USB_DT_CS_INTERFACE;
+		out_ext->bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK;
+		out_ext->bJackType =		USB_MS_EXTERNAL;
+		out_ext->bJackID =		jack++;
+		out_ext->bNrInputPins =		1;
+		out_ext->iJack =		0;
+		out_ext->pins[0].baSourceID =	in_emb->bJackID;
+		out_ext->pins[0].baSourcePin =	1;
+		midi_function[i++] = (struct usb_descriptor_header *) out_ext;
+
+		/* link it to the endpoint */
+		ms_out_desc.baAssocJackID[n] = in_emb->bJackID;
 	}
 
 	/* configure the endpoint descriptors ... */
 	ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports);
 	ms_out_desc.bNumEmbMIDIJack = midi->in_ports;
-	for (n = 0; n < midi->in_ports; n++)
-		ms_out_desc.baAssocJackID[n] = jack_in_emb_desc.bJackID;
 
 	ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports);
 	ms_in_desc.bNumEmbMIDIJack = midi->out_ports;
-	for (n = 0; n < midi->out_ports; n++)
-		ms_in_desc.baAssocJackID[n] = jack_out_emb_desc.bJackID;
 
 	/* ... and add them to the list */
 	midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;
@@ -901,6 +892,8 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 		f->descriptors = usb_copy_descriptors(midi_function);
 	}
 
+	kfree(midi_function);
+
 	return 0;
 
 fail:
-- 
1.7.6.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux