Commit c8933c3f authored by Daniel Mack's avatar Daniel Mack Committed by Felipe Balbi

USB: gadget: f_midi: allow a dynamic number of input and output ports

The code in the MIDI gadget was already sort of prepared for multi-port
configuration, so the streaming logic itself didn't need much tweaking.
However, the descriptors change when the number of ports do, and so some
rework of the the preparation algorithms were necessary.

Successfully tested on Linux and Max OS X hosts for both input and
output streams.
Signed-off-by: default avatarDaniel Mack <zonque@gmail.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 2672eea5
...@@ -39,6 +39,13 @@ MODULE_LICENSE("GPL v2"); ...@@ -39,6 +39,13 @@ MODULE_LICENSE("GPL v2");
static const char f_midi_shortname[] = "f_midi"; static const char f_midi_shortname[] = "f_midi";
static const char f_midi_longname[] = "MIDI Gadget"; static const char f_midi_longname[] = "MIDI Gadget";
/*
* We can only handle 16 cables on one single endpoint, as cable numbers are
* stored in 4-bit fields. And as the interface currently only holds one
* single endpoint, this is the maximum number of ports we can allow.
*/
#define MAX_PORTS 16
/* /*
* This is a gadget, and the IN/OUT naming is from the host's perspective. * This is a gadget, and the IN/OUT naming is from the host's perspective.
* USB -> OUT endpoint -> rawmidi * USB -> OUT endpoint -> rawmidi
...@@ -47,7 +54,7 @@ static const char f_midi_longname[] = "MIDI Gadget"; ...@@ -47,7 +54,7 @@ static const char f_midi_longname[] = "MIDI Gadget";
struct gmidi_in_port { struct gmidi_in_port {
struct f_midi *midi; struct f_midi *midi;
int active; int active;
uint8_t cable; /* cable number << 4 */ uint8_t cable;
uint8_t state; uint8_t state;
#define STATE_UNKNOWN 0 #define STATE_UNKNOWN 0
#define STATE_1PARAM 1 #define STATE_1PARAM 1
...@@ -65,15 +72,15 @@ struct f_midi { ...@@ -65,15 +72,15 @@ struct f_midi {
struct usb_ep *in_ep, *out_ep; struct usb_ep *in_ep, *out_ep;
struct snd_card *card; struct snd_card *card;
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *in_substream;
struct snd_rawmidi_substream *out_substream;
/* For the moment we only support one port in struct snd_rawmidi_substream *in_substream[MAX_PORTS];
each direction, but in_port is kept as a struct snd_rawmidi_substream *out_substream[MAX_PORTS];
separate struct so we can have more later. */ struct gmidi_in_port *in_port[MAX_PORTS];
struct gmidi_in_port in_port;
unsigned long out_triggered; unsigned long out_triggered;
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
unsigned int in_ports;
unsigned int out_ports;
int index; int index;
char *id; char *id;
unsigned int buflen, qlen; unsigned int buflen, qlen;
...@@ -88,7 +95,8 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); ...@@ -88,7 +95,8 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req);
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16);
DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
/* B.3.1 Standard AC Interface Descriptor */ /* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc __initdata = { static struct usb_interface_descriptor ac_interface_desc __initdata = {
...@@ -129,62 +137,27 @@ static struct usb_ms_header_descriptor ms_header_desc __initdata = { ...@@ -129,62 +137,27 @@ static struct usb_ms_header_descriptor ms_header_desc __initdata = {
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER, .bDescriptorSubtype = USB_MS_HEADER,
.bcdMSC = cpu_to_le16(0x0100), .bcdMSC = cpu_to_le16(0x0100),
.wTotalLength = cpu_to_le16(USB_DT_MS_HEADER_SIZE /* .wTotalLength = DYNAMIC */
+ 2*USB_DT_MIDI_IN_SIZE
+ 2*USB_DT_MIDI_OUT_SIZE(1)),
};
#define JACK_IN_EMB 1
#define JACK_IN_EXT 2
#define JACK_OUT_EMB 3
#define JACK_OUT_EXT 4
/* B.4.3 MIDI IN Jack Descriptors */
static const 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 = JACK_IN_EMB,
}; };
static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = { /* B.4.3 Embedded MIDI IN Jack Descriptor */
.bLength = USB_DT_MIDI_IN_SIZE, static struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
.bDescriptorType = USB_DT_CS_INTERFACE, .bLength = USB_DT_MIDI_IN_SIZE,
.bDescriptorSubtype = USB_MS_MIDI_IN_JACK, .bDescriptorType = USB_DT_CS_INTERFACE,
.bJackType = USB_MS_EXTERNAL, .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
.bJackID = JACK_IN_EXT, .bJackType = USB_MS_EMBEDDED,
/* .bJackID = DYNAMIC */
}; };
/* B.4.4 MIDI OUT Jack Descriptors */ /* B.4.4 Embedded MIDI OUT Jack Descriptor */
static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = { static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = {
.bLength = USB_DT_MIDI_OUT_SIZE(1), /* .bLength = DYNAMIC */
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
.bJackType = USB_MS_EMBEDDED, .bJackType = USB_MS_EMBEDDED,
.bJackID = JACK_OUT_EMB, /* .bJackID = DYNAMIC */
.bNrInputPins = 1, /* .bNrInputPins = DYNAMIC */
.pins = { /* .pins = DYNAMIC */
[0] = {
.baSourceID = JACK_IN_EXT,
.baSourcePin = 1,
}
}
};
static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
.bLength = USB_DT_MIDI_OUT_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
.bJackType = USB_MS_EXTERNAL,
.bJackID = JACK_OUT_EXT,
.bNrInputPins = 1,
.pins = {
[0] = {
.baSourceID = JACK_IN_EMB,
.baSourcePin = 1,
}
}
}; };
/* B.5.1 Standard Bulk OUT Endpoint Descriptor */ /* B.5.1 Standard Bulk OUT Endpoint Descriptor */
...@@ -196,14 +169,12 @@ static struct usb_endpoint_descriptor bulk_out_desc = { ...@@ -196,14 +169,12 @@ static struct usb_endpoint_descriptor bulk_out_desc = {
}; };
/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = { static struct usb_ms_endpoint_descriptor_16 ms_out_desc = {
.bLength = USB_DT_MS_ENDPOINT_SIZE(1), /* .bLength = DYNAMIC */
.bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubtype = USB_MS_GENERAL, .bDescriptorSubtype = USB_MS_GENERAL,
.bNumEmbMIDIJack = 1, /* .bNumEmbMIDIJack = DYNAMIC */
.baAssocJackID = { /* .baAssocJackID = DYNAMIC */
[0] = JACK_IN_EMB,
}
}; };
/* B.6.1 Standard Bulk IN Endpoint Descriptor */ /* B.6.1 Standard Bulk IN Endpoint Descriptor */
...@@ -215,33 +186,12 @@ static struct usb_endpoint_descriptor bulk_in_desc = { ...@@ -215,33 +186,12 @@ static struct usb_endpoint_descriptor bulk_in_desc = {
}; };
/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = { static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
.bLength = USB_DT_MS_ENDPOINT_SIZE(1), /* .bLength = DYNAMIC */
.bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubtype = USB_MS_GENERAL, .bDescriptorSubtype = USB_MS_GENERAL,
.bNumEmbMIDIJack = 1, /* .bNumEmbMIDIJack = DYNAMIC */
.baAssocJackID = { /* .baAssocJackID = DYNAMIC */
[0] = JACK_OUT_EMB,
}
};
static struct usb_descriptor_header *midi_function[] __initdata = {
(struct usb_descriptor_header *)&ac_interface_desc,
(struct usb_descriptor_header *)&ac_header_desc,
(struct usb_descriptor_header *)&ms_interface_desc,
(struct usb_descriptor_header *)&ms_header_desc,
(struct usb_descriptor_header *)&jack_in_emb_desc,
(struct usb_descriptor_header *)&jack_in_ext_desc,
(struct usb_descriptor_header *)&jack_out_emb_desc,
(struct usb_descriptor_header *)&jack_out_ext_desc,
/* If you add more jacks, update ms_header_desc.wTotalLength */
(struct usb_descriptor_header *)&bulk_out_desc,
(struct usb_descriptor_header *)&ms_out_desc,
(struct usb_descriptor_header *)&bulk_in_desc,
(struct usb_descriptor_header *)&ms_in_desc,
NULL,
}; };
/* string IDs are assigned dynamically */ /* string IDs are assigned dynamically */
...@@ -296,16 +246,16 @@ static void f_midi_read_data(struct usb_ep *ep, int cable, ...@@ -296,16 +246,16 @@ static void f_midi_read_data(struct usb_ep *ep, int cable,
uint8_t *data, int length) uint8_t *data, int length)
{ {
struct f_midi *midi = ep->driver_data; struct f_midi *midi = ep->driver_data;
/* cable is ignored, because for now we only have one. */ struct snd_rawmidi_substream *substream = midi->out_substream[cable];
if (!midi->out_substream) if (!substream)
/* Nobody is listening - throw it on the floor. */ /* Nobody is listening - throw it on the floor. */
return; return;
if (!test_bit(midi->out_substream->number, &midi->out_triggered)) if (!test_bit(cable, &midi->out_triggered))
return; return;
snd_rawmidi_receive(midi->out_substream, data, length); snd_rawmidi_receive(substream, data, length);
} }
static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req) static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
...@@ -514,7 +464,7 @@ static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0, ...@@ -514,7 +464,7 @@ static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0,
static void f_midi_transmit_byte(struct usb_request *req, static void f_midi_transmit_byte(struct usb_request *req,
struct gmidi_in_port *port, uint8_t b) struct gmidi_in_port *port, uint8_t b)
{ {
uint8_t p0 = port->cable; uint8_t p0 = port->cable << 4;
if (b >= 0xf8) { if (b >= 0xf8) {
f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0); f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
...@@ -612,7 +562,7 @@ static void f_midi_transmit_byte(struct usb_request *req, ...@@ -612,7 +562,7 @@ static void f_midi_transmit_byte(struct usb_request *req,
static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
{ {
struct usb_ep *ep = midi->in_ep; struct usb_ep *ep = midi->in_ep;
struct gmidi_in_port *port = &midi->in_port; int i;
if (!ep) if (!ep)
return; return;
...@@ -627,10 +577,16 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) ...@@ -627,10 +577,16 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
req->length = 0; req->length = 0;
req->complete = f_midi_complete; req->complete = f_midi_complete;
if (port->active) { for (i = 0; i < MAX_PORTS; i++) {
struct gmidi_in_port *port = midi->in_port[i];
struct snd_rawmidi_substream *substream = midi->in_substream[i];
if (!port || !port->active || !substream)
continue;
while (req->length + 3 < midi->buflen) { while (req->length + 3 < midi->buflen) {
uint8_t b; uint8_t b;
if (snd_rawmidi_transmit(midi->in_substream, &b, 1) != 1) { if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
port->active = 0; port->active = 0;
break; break;
} }
...@@ -654,9 +610,12 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream) ...@@ -654,9 +610,12 @@ static int f_midi_in_open(struct snd_rawmidi_substream *substream)
{ {
struct f_midi *midi = substream->rmidi->private_data; struct f_midi *midi = substream->rmidi->private_data;
if (!midi->in_port[substream->number])
return -EINVAL;
VDBG(midi, "%s()\n", __func__); VDBG(midi, "%s()\n", __func__);
midi->in_substream = substream; midi->in_substream[substream->number] = substream;
midi->in_port.state = STATE_UNKNOWN; midi->in_port[substream->number]->state = STATE_UNKNOWN;
return 0; return 0;
} }
...@@ -672,8 +631,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) ...@@ -672,8 +631,11 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{ {
struct f_midi *midi = substream->rmidi->private_data; struct f_midi *midi = substream->rmidi->private_data;
if (!midi->in_port[substream->number])
return;
VDBG(midi, "%s() %d\n", __func__, up); VDBG(midi, "%s() %d\n", __func__, up);
midi->in_port.active = up; midi->in_port[substream->number]->active = up;
if (up) if (up)
tasklet_hi_schedule(&midi->tasklet); tasklet_hi_schedule(&midi->tasklet);
} }
...@@ -682,8 +644,11 @@ static int f_midi_out_open(struct snd_rawmidi_substream *substream) ...@@ -682,8 +644,11 @@ static int f_midi_out_open(struct snd_rawmidi_substream *substream)
{ {
struct f_midi *midi = substream->rmidi->private_data; struct f_midi *midi = substream->rmidi->private_data;
if (!substream->number >= MAX_PORTS)
return -EINVAL;
VDBG(midi, "%s()\n", __func__); VDBG(midi, "%s()\n", __func__);
midi->out_substream = substream; midi->out_substream[substream->number] = substream;
return 0; return 0;
} }
...@@ -725,8 +690,6 @@ static int f_midi_register_card(struct f_midi *midi) ...@@ -725,8 +690,6 @@ static int f_midi_register_card(struct f_midi *midi)
struct snd_card *card; struct snd_card *card;
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
int err; int err;
int out_ports = 1;
int in_ports = 1;
static struct snd_device_ops ops = { static struct snd_device_ops ops = {
.dev_free = f_midi_snd_free, .dev_free = f_midi_snd_free,
}; };
...@@ -749,11 +712,9 @@ static int f_midi_register_card(struct f_midi *midi) ...@@ -749,11 +712,9 @@ static int f_midi_register_card(struct f_midi *midi)
strcpy(card->shortname, f_midi_shortname); strcpy(card->shortname, f_midi_shortname);
/* Set up rawmidi */ /* Set up rawmidi */
midi->in_port.midi = midi;
midi->in_port.active = 0;
snd_component_add(card, "MIDI"); snd_component_add(card, "MIDI");
err = snd_rawmidi_new(card, card->longname, 0, err = snd_rawmidi_new(card, card->longname, 0,
out_ports, in_ports, &rmidi); midi->out_ports, midi->in_ports, &rmidi);
if (err < 0) { if (err < 0) {
ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err);
goto fail; goto fail;
...@@ -797,9 +758,12 @@ static int f_midi_register_card(struct f_midi *midi) ...@@ -797,9 +758,12 @@ static int f_midi_register_card(struct f_midi *midi)
static int __init static int __init
f_midi_bind(struct usb_configuration *c, struct usb_function *f) f_midi_bind(struct usb_configuration *c, struct usb_function *f)
{ {
struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12];
struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct f_midi *midi = func_to_midi(f); struct f_midi *midi = func_to_midi(f);
int status; int status, n, jack = 1, i = 0;
/* maybe allocate device-global string ID */ /* maybe allocate device-global string ID */
if (midi_string_defs[0].id == 0) { if (midi_string_defs[0].id == 0) {
...@@ -834,6 +798,94 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -834,6 +798,94 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
goto fail; goto fail;
midi->out_ep->driver_data = cdev; /* claim */ midi->out_ep->driver_data = cdev; /* claim */
/*
* construct the function's descriptor set. As the number of
* input and output MIDI ports is configurable, we have to do
* it that way.
*/
/* add the headers - these are always the same */
midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc;
/* 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);
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 */
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;
}
midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc;
/* and multiple external OUT jacks ... */
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;
}
/* 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;
midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;
midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc;
midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
midi_function[i++] = NULL;
/* /*
* support all relevant hardware speeds... we expect that when * support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at * hardware is dual speed, all bulk-capable endpoints work at
...@@ -876,11 +928,17 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) ...@@ -876,11 +928,17 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
*/ */
int __init f_midi_bind_config(struct usb_configuration *c, int __init f_midi_bind_config(struct usb_configuration *c,
int index, char *id, int index, char *id,
unsigned int in_ports,
unsigned int out_ports,
unsigned int buflen, unsigned int buflen,
unsigned int qlen) unsigned int qlen)
{ {
struct f_midi *midi; struct f_midi *midi;
int status; int status, i;
/* sanity check */
if (in_ports > MAX_PORTS || out_ports > MAX_PORTS)
return -EINVAL;
/* allocate and initialize one new instance */ /* allocate and initialize one new instance */
midi = kzalloc(sizeof *midi, GFP_KERNEL); midi = kzalloc(sizeof *midi, GFP_KERNEL);
...@@ -889,10 +947,25 @@ int __init f_midi_bind_config(struct usb_configuration *c, ...@@ -889,10 +947,25 @@ int __init f_midi_bind_config(struct usb_configuration *c,
goto fail; goto fail;
} }
for (i = 0; i < in_ports; i++) {
struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port) {
status = -ENOMEM;
goto fail;
}
port->midi = midi;
port->active = 0;
port->cable = i;
midi->in_port[i] = port;
}
midi->gadget = c->cdev->gadget; midi->gadget = c->cdev->gadget;
tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
/* set up ALSA midi devices */ /* set up ALSA midi devices */
midi->in_ports = in_ports;
midi->out_ports = out_ports;
status = f_midi_register_card(midi); status = f_midi_register_card(midi);
if (status < 0) if (status < 0)
goto setup_fail; goto setup_fail;
......
...@@ -66,6 +66,14 @@ static unsigned int qlen = 32; ...@@ -66,6 +66,14 @@ static unsigned int qlen = 32;
module_param(qlen, uint, S_IRUGO); module_param(qlen, uint, S_IRUGO);
MODULE_PARM_DESC(qlen, "USB read request queue length"); MODULE_PARM_DESC(qlen, "USB read request queue length");
static unsigned int in_ports = 1;
module_param(in_ports, uint, S_IRUGO);
MODULE_PARM_DESC(in_ports, "Number of MIDI input ports");
static unsigned int out_ports = 1;
module_param(out_ports, uint, S_IRUGO);
MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
/* Thanks to Grey Innovation for donating this product ID. /* Thanks to Grey Innovation for donating this product ID.
* *
* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
...@@ -124,7 +132,9 @@ static struct usb_configuration midi_config = { ...@@ -124,7 +132,9 @@ static struct usb_configuration midi_config = {
static int __init midi_bind_config(struct usb_configuration *c) static int __init midi_bind_config(struct usb_configuration *c)
{ {
return f_midi_bind_config(c, index, id, buflen, qlen); return f_midi_bind_config(c, index, id,
in_ports, out_ports,
buflen, qlen);
} }
static int __init midi_bind(struct usb_composite_dev *cdev) static int __init midi_bind(struct usb_composite_dev *cdev)
......
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