|
@@ -20,6 +20,7 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
|
|
+#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/device.h>
|
|
#include <linux/device.h>
|
|
|
|
|
|
@@ -33,6 +34,7 @@
|
|
#include <linux/usb/midi.h>
|
|
#include <linux/usb/midi.h>
|
|
|
|
|
|
#include "u_f.h"
|
|
#include "u_f.h"
|
|
|
|
+#include "u_midi.h"
|
|
|
|
|
|
MODULE_AUTHOR("Ben Williamson");
|
|
MODULE_AUTHOR("Ben Williamson");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_LICENSE("GPL v2");
|
|
@@ -99,7 +101,7 @@ DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
|
|
DECLARE_USB_MS_ENDPOINT_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 = {
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
/* .bInterfaceNumber = DYNAMIC */
|
|
/* .bInterfaceNumber = DYNAMIC */
|
|
@@ -110,7 +112,7 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
|
|
};
|
|
};
|
|
|
|
|
|
/* B.3.2 Class-Specific AC Interface Descriptor */
|
|
/* B.3.2 Class-Specific AC Interface Descriptor */
|
|
-static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
|
|
|
|
|
|
+static struct uac1_ac_header_descriptor_1 ac_header_desc = {
|
|
.bLength = UAC_DT_AC_HEADER_SIZE(1),
|
|
.bLength = UAC_DT_AC_HEADER_SIZE(1),
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubtype = USB_MS_HEADER,
|
|
.bDescriptorSubtype = USB_MS_HEADER,
|
|
@@ -121,7 +123,7 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
|
|
};
|
|
};
|
|
|
|
|
|
/* B.4.1 Standard MS Interface Descriptor */
|
|
/* B.4.1 Standard MS Interface Descriptor */
|
|
-static struct usb_interface_descriptor ms_interface_desc __initdata = {
|
|
|
|
|
|
+static struct usb_interface_descriptor ms_interface_desc = {
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bLength = USB_DT_INTERFACE_SIZE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
.bDescriptorType = USB_DT_INTERFACE,
|
|
/* .bInterfaceNumber = DYNAMIC */
|
|
/* .bInterfaceNumber = DYNAMIC */
|
|
@@ -132,7 +134,7 @@ static struct usb_interface_descriptor ms_interface_desc __initdata = {
|
|
};
|
|
};
|
|
|
|
|
|
/* B.4.2 Class-Specific MS Interface Descriptor */
|
|
/* B.4.2 Class-Specific MS Interface Descriptor */
|
|
-static struct usb_ms_header_descriptor ms_header_desc __initdata = {
|
|
|
|
|
|
+static struct usb_ms_header_descriptor ms_header_desc = {
|
|
.bLength = USB_DT_MS_HEADER_SIZE,
|
|
.bLength = USB_DT_MS_HEADER_SIZE,
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorType = USB_DT_CS_INTERFACE,
|
|
.bDescriptorSubtype = USB_MS_HEADER,
|
|
.bDescriptorSubtype = USB_MS_HEADER,
|
|
@@ -387,6 +389,7 @@ static void f_midi_disable(struct usb_function *f)
|
|
usb_ep_disable(midi->out_ep);
|
|
usb_ep_disable(midi->out_ep);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef USBF_MIDI_INCLUDED
|
|
static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
{
|
|
{
|
|
struct usb_composite_dev *cdev = f->config->cdev;
|
|
struct usb_composite_dev *cdev = f->config->cdev;
|
|
@@ -409,6 +412,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
usb_free_all_descriptors(f);
|
|
usb_free_all_descriptors(f);
|
|
kfree(midi);
|
|
kfree(midi);
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
|
|
|
|
static int f_midi_snd_free(struct snd_device *device)
|
|
static int f_midi_snd_free(struct snd_device *device)
|
|
{
|
|
{
|
|
@@ -729,8 +733,7 @@ fail:
|
|
|
|
|
|
/* MIDI function driver setup/binding */
|
|
/* MIDI function driver setup/binding */
|
|
|
|
|
|
-static int __init
|
|
|
|
-f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
|
|
|
|
|
+static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
|
{
|
|
{
|
|
struct usb_descriptor_header **midi_function;
|
|
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_ext_desc[MAX_PORTS];
|
|
@@ -741,6 +744,14 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
|
|
struct f_midi *midi = func_to_midi(f);
|
|
struct f_midi *midi = func_to_midi(f);
|
|
int status, n, jack = 1, i = 0;
|
|
int status, n, jack = 1, i = 0;
|
|
|
|
|
|
|
|
+#ifndef USBF_MIDI_INCLUDED
|
|
|
|
+ midi->gadget = cdev->gadget;
|
|
|
|
+ tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
|
|
|
|
+ status = f_midi_register_card(midi);
|
|
|
|
+ if (status < 0)
|
|
|
|
+ goto fail_register;
|
|
|
|
+
|
|
|
|
+#endif
|
|
/* 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) {
|
|
status = usb_string_id(c->cdev);
|
|
status = usb_string_id(c->cdev);
|
|
@@ -897,6 +908,10 @@ fail_f_midi:
|
|
kfree(midi_function);
|
|
kfree(midi_function);
|
|
usb_free_descriptors(f->hs_descriptors);
|
|
usb_free_descriptors(f->hs_descriptors);
|
|
fail:
|
|
fail:
|
|
|
|
+#ifndef USBF_MIDI_INCLUDED
|
|
|
|
+ f_midi_unregister_card(midi);
|
|
|
|
+fail_register:
|
|
|
|
+#endif
|
|
/* we might as well release our claims on endpoints */
|
|
/* we might as well release our claims on endpoints */
|
|
if (midi->out_ep)
|
|
if (midi->out_ep)
|
|
midi->out_ep->driver_data = NULL;
|
|
midi->out_ep->driver_data = NULL;
|
|
@@ -908,6 +923,7 @@ fail:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef USBF_MIDI_INCLUDED
|
|
/**
|
|
/**
|
|
* f_midi_bind_config - add USB MIDI function to a configuration
|
|
* f_midi_bind_config - add USB MIDI function to a configuration
|
|
* @c: the configuration to supcard the USB audio function
|
|
* @c: the configuration to supcard the USB audio function
|
|
@@ -997,3 +1013,122 @@ fail:
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#else
|
|
|
|
+
|
|
|
|
+static void f_midi_free_inst(struct usb_function_instance *f)
|
|
|
|
+{
|
|
|
|
+ struct f_midi_opts *opts;
|
|
|
|
+
|
|
|
|
+ opts = container_of(f, struct f_midi_opts, func_inst);
|
|
|
|
+
|
|
|
|
+ kfree(opts);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct usb_function_instance *f_midi_alloc_inst(void)
|
|
|
|
+{
|
|
|
|
+ struct f_midi_opts *opts;
|
|
|
|
+
|
|
|
|
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
|
|
|
|
+ if (!opts)
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
+ opts->func_inst.free_func_inst = f_midi_free_inst;
|
|
|
|
+
|
|
|
|
+ return &opts->func_inst;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void f_midi_free(struct usb_function *f)
|
|
|
|
+{
|
|
|
|
+ struct f_midi *midi;
|
|
|
|
+ struct f_midi_opts *opts;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ midi = func_to_midi(f);
|
|
|
|
+ opts = container_of(f->fi, struct f_midi_opts, func_inst);
|
|
|
|
+ kfree(midi->id);
|
|
|
|
+ for (i = opts->in_ports - 1; i >= 0; --i)
|
|
|
|
+ kfree(midi->in_port[i]);
|
|
|
|
+ kfree(midi);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|
|
|
+{
|
|
|
|
+ struct usb_composite_dev *cdev = f->config->cdev;
|
|
|
|
+ struct f_midi *midi = func_to_midi(f);
|
|
|
|
+ struct snd_card *card;
|
|
|
|
+
|
|
|
|
+ DBG(cdev, "unbind\n");
|
|
|
|
+
|
|
|
|
+ /* just to be sure */
|
|
|
|
+ f_midi_disable(f);
|
|
|
|
+
|
|
|
|
+ card = midi->card;
|
|
|
|
+ midi->card = NULL;
|
|
|
|
+ if (card)
|
|
|
|
+ snd_card_free(card);
|
|
|
|
+
|
|
|
|
+ usb_free_all_descriptors(f);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
|
|
|
+{
|
|
|
|
+ struct f_midi *midi;
|
|
|
|
+ struct f_midi_opts *opts;
|
|
|
|
+ int status, i;
|
|
|
|
+
|
|
|
|
+ opts = container_of(fi, struct f_midi_opts, func_inst);
|
|
|
|
+ /* sanity check */
|
|
|
|
+ if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS)
|
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
+
|
|
|
|
+ /* allocate and initialize one new instance */
|
|
|
|
+ midi = kzalloc(sizeof(*midi), GFP_KERNEL);
|
|
|
|
+ if (!midi)
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < opts->in_ports; i++) {
|
|
|
|
+ struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
|
|
|
|
+
|
|
|
|
+ if (!port) {
|
|
|
|
+ status = -ENOMEM;
|
|
|
|
+ goto setup_fail;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ port->midi = midi;
|
|
|
|
+ port->active = 0;
|
|
|
|
+ port->cable = i;
|
|
|
|
+ midi->in_port[i] = port;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* set up ALSA midi devices */
|
|
|
|
+ midi->id = kstrdup(opts->id, GFP_KERNEL);
|
|
|
|
+ if (opts->id && !midi->id) {
|
|
|
|
+ status = -ENOMEM;
|
|
|
|
+ goto kstrdup_fail;
|
|
|
|
+ }
|
|
|
|
+ midi->in_ports = opts->in_ports;
|
|
|
|
+ midi->out_ports = opts->out_ports;
|
|
|
|
+ midi->index = opts->index;
|
|
|
|
+ midi->buflen = opts->buflen;
|
|
|
|
+ midi->qlen = opts->qlen;
|
|
|
|
+
|
|
|
|
+ midi->func.name = "gmidi function";
|
|
|
|
+ midi->func.strings = midi_strings;
|
|
|
|
+ midi->func.bind = f_midi_bind;
|
|
|
|
+ midi->func.unbind = f_midi_unbind;
|
|
|
|
+ midi->func.set_alt = f_midi_set_alt;
|
|
|
|
+ midi->func.disable = f_midi_disable;
|
|
|
|
+ midi->func.free_func = f_midi_free;
|
|
|
|
+
|
|
|
|
+ return &midi->func;
|
|
|
|
+
|
|
|
|
+kstrdup_fail:
|
|
|
|
+ f_midi_unregister_card(midi);
|
|
|
|
+setup_fail:
|
|
|
|
+ for (--i; i >= 0; i--)
|
|
|
|
+ kfree(midi->in_port[i]);
|
|
|
|
+ kfree(midi);
|
|
|
|
+ return ERR_PTR(status);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc);
|
|
|
|
+#endif
|