/*
* f_midi.c -- USB MIDI class function driver
*
* Copyright (C) 2006 Thumtronics Pty Ltd.
* Developed for Thumtronics by Grey Innovation
* Ben Williamson <ben.williamson@greyinnovation.com>
*
* Rewritten for the composite framework
* Copyright (C) 2011 Daniel Mack <zonque@gmail.com>
*
* Based on drivers/usb/gadget/f_audio.c,
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
* and drivers/usb/gadget/midi.c,
* Copyright (C) 2006 Thumtronics Pty Ltd.
* Ben Williamson <ben.williamson@greyinnovation.com>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kfifo.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
#include "u_f.h"
#include "u_midi.h"
MODULE_AUTHOR("Ben Williamson");
MODULE_LICENSE("GPL v2");
static const char f_midi_shortname[] = "f_midi";
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.
* USB -> OUT endpoint -> rawmidi
* USB <- IN endpoint <- rawmidi
*/
struct gmidi_in_port {
struct f_midi *midi;
int active;
uint8_t cable;
uint8_t state;
#define STATE_UNKNOWN 0
#define STATE_1PARAM 1
#define STATE_2PARAM_1 2
#define STATE_2PARAM_2 3
#define STATE_SYSEX_0 4
#define STATE_SYSEX_1 5
#define STATE_SYSEX_2 6
uint8_t data[2];
};
struct f_midi {
struct usb_function func;
struct usb_gadget *gadget;
struct usb_ep *in_ep, *out_ep;
struct snd_card *card;
struct snd_rawmidi *rmidi;
u8 ms_id;
struct snd_rawmidi_substream *in_substream[MAX_PORTS];
struct snd_rawmidi_substream *out_substream[MAX_PORTS];
struct gmidi_in_port *in_port[MAX_PORTS];
unsigned long out_triggered;
struct tasklet_struct tasklet;
unsigned int in_ports;
unsigned int out_ports;
int index;
char *id;
unsigned int buflen, qlen;
/* This fifo is used as a buffer ring for pre-allocated IN usb_requests */
DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);
unsigned int in_last_port;
};
static inline struct f_midi *func_to_midi(struct usb_function *f)
{
return container_of(f, struct f_midi, func);
}
static void f_midi_transmit(struct f_midi *midi);
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
/* .bNumEndpoints = DYNAMIC */
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
/* .iInterface = DYNAMIC */
};
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct uac1_ac_header_descriptor_1 ac_header_desc = {