linux/sound/usb/midi.c

/*
 * usbmidi.c - ALSA USB MIDI driver
 *
 * Copyright (c) 2002-2009 Clemens Ladisch
 * All rights reserved.
 *
 * Based on the OSS usb-midi driver by NAGANO Daisuke,
 *          NetBSD's umidi driver by Takuya SHIOZAKI,
 *          the "USB Device Class Definition for MIDI Devices" by Roland
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed and/or modified under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
#include <linux/module.h>

#include <sound/core.h>
#include <sound/control.h>
#include <sound/rawmidi.h>
#include <sound/asequencer.h>
#include "usbaudio.h"
#include "midi.h"
#include "power.h"
#include "helper.h"

/*
 * define this to log all USB packets
 */
/* #define DUMP_PACKETS */

/*
 * how long to wait after some USB errors, so that hub_wq can disconnect() us
 * without too many spurious errors
 */
#define ERROR_DELAY_JIFFIES

#define OUTPUT_URBS
#define INPUT_URBS


MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();

struct snd_usb_midi_in_endpoint;
struct snd_usb_midi_out_endpoint;
struct snd_usb_midi_endpoint;

struct usb_protocol_ops {};

struct snd_usb_midi {};

struct snd_usb_midi_out_endpoint {};

struct snd_usb_midi_in_endpoint {};

static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep);

static const uint8_t snd_usbmidi_cin_length[] =;

/*
 * Submits the URB, with error handling.
 */
static int snd_usbmidi_submit_urb(struct urb *urb, gfp_t flags)
{}

/*
 * Error handling for URB completion functions.
 */
static int snd_usbmidi_urb_error(const struct urb *urb)
{}

/*
 * Receives a chunk of MIDI data.
 */
static void snd_usbmidi_input_data(struct snd_usb_midi_in_endpoint *ep,
				   int portidx, uint8_t *data, int length)
{}

#ifdef DUMP_PACKETS
static void dump_urb(const char *type, const u8 *data, int length)
{
	snd_printk(KERN_DEBUG "%s packet: [", type);
	for (; length > 0; ++data, --length)
		printk(KERN_CONT " %02x", *data);
	printk(KERN_CONT " ]\n");
}
#else
#define dump_urb(type, data, length)
#endif

/*
 * Processes the data read from the device.
 */
static void snd_usbmidi_in_urb_complete(struct urb *urb)
{}

static void snd_usbmidi_out_urb_complete(struct urb *urb)
{}

/*
 * This is called when some data should be transferred to the device
 * (from one or more substreams).
 */
static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint *ep)
{}

static void snd_usbmidi_out_work(struct work_struct *work)
{}

/* called after transfers had been interrupted due to some USB error */
static void snd_usbmidi_error_timer(struct timer_list *t)
{}

/* helper function to send static data that may not DMA-able */
static int send_bulk_static_data(struct snd_usb_midi_out_endpoint *ep,
				 const void *data, int len)
{}

/*
 * Standard USB MIDI protocol: see the spec.
 * Midiman protocol: like the standard protocol, but the control byte is the
 * fourth byte in each packet, and uses length instead of CIN.
 */

static void snd_usbmidi_standard_input(struct snd_usb_midi_in_endpoint *ep,
				       uint8_t *buffer, int buffer_length)
{}

static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint *ep,
				      uint8_t *buffer, int buffer_length)
{}

/*
 * Buggy M-Audio device: running status on input results in a packet that has
 * the data bytes but not the status byte and that is marked with CIN 4.
 */
static void snd_usbmidi_maudio_broken_running_status_input(
					struct snd_usb_midi_in_endpoint *ep,
					uint8_t *buffer, int buffer_length)
{}

/*
 * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4
 * but the previously seen CIN, but still with three data bytes.
 */
static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
				     uint8_t *buffer, int buffer_length)
{}

/*
 * CME protocol: like the standard protocol, but SysEx commands are sent as a
 * single USB packet preceded by a 0x0F byte.
 */
static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep,
				  uint8_t *buffer, int buffer_length)
{}

/*
 * Adds one USB MIDI packet to the output buffer.
 */
static void snd_usbmidi_output_standard_packet(struct urb *urb, uint8_t p0,
					       uint8_t p1, uint8_t p2,
					       uint8_t p3)
{}

/*
 * Adds one Midiman packet to the output buffer.
 */
static void snd_usbmidi_output_midiman_packet(struct urb *urb, uint8_t p0,
					      uint8_t p1, uint8_t p2,
					      uint8_t p3)
{}

/*
 * Converts MIDI commands to USB MIDI packets.
 */
static void snd_usbmidi_transmit_byte(struct usbmidi_out_port *port,
				      uint8_t b, struct urb *urb)
{}

static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep,
					struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_standard_ops =;

static const struct usb_protocol_ops snd_usbmidi_midiman_ops =;

static const
struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops =;

static const struct usb_protocol_ops snd_usbmidi_cme_ops =;

static const struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops =;

/*
 * AKAI MPD16 protocol:
 *
 * For control port (endpoint 1):
 * ==============================
 * One or more chunks consisting of first byte of (0x10 | msg_len) and then a
 * SysEx message (msg_len=9 bytes long).
 *
 * For data port (endpoint 2):
 * ===========================
 * One or more chunks consisting of first byte of (0x20 | msg_len) and then a
 * MIDI message (msg_len bytes long)
 *
 * Messages sent: Active Sense, Note On, Poly Pressure, Control Change.
 */
static void snd_usbmidi_akai_input(struct snd_usb_midi_in_endpoint *ep,
				   uint8_t *buffer, int buffer_length)
{}

#define MAX_AKAI_SYSEX_LEN

static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep,
				    struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_akai_ops =;

/*
 * Novation USB MIDI protocol: number of data bytes is in the first byte
 * (when receiving) (+1!) or in the second byte (when sending); data begins
 * at the third byte.
 */

static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint *ep,
				       uint8_t *buffer, int buffer_length)
{}

static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint *ep,
					struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_novation_ops =;

/*
 * "raw" protocol: just move raw MIDI bytes from/to the endpoint
 */

static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint *ep,
				  uint8_t *buffer, int buffer_length)
{}

static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint *ep,
				   struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_raw_ops =;

/*
 * FTDI protocol: raw MIDI bytes, but input packets have two modem status bytes.
 */

static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint *ep,
				   uint8_t *buffer, int buffer_length)
{}

static const struct usb_protocol_ops snd_usbmidi_ftdi_ops =;

static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep,
				     uint8_t *buffer, int buffer_length)
{}

static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep,
				      struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_122l_ops =;

/*
 * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching.
 */

static void snd_usbmidi_emagic_init_out(struct snd_usb_midi_out_endpoint *ep)
{}

static void snd_usbmidi_emagic_finish_out(struct snd_usb_midi_out_endpoint *ep)
{}

static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint *ep,
				     uint8_t *buffer, int buffer_length)
{}

static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint *ep,
				      struct urb *urb)
{}

static const struct usb_protocol_ops snd_usbmidi_emagic_ops =;


static void update_roland_altsetting(struct snd_usb_midi *umidi)
{}

static int substream_open(struct snd_rawmidi_substream *substream, int dir,
			  int open)
{}

static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
{}

static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
{}

static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream,
				       int up)
{}

static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
{}

static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
{}

static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
{}

static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream,
				      int up)
{}

static const struct snd_rawmidi_ops snd_usbmidi_output_ops =;

static const struct snd_rawmidi_ops snd_usbmidi_input_ops =;

static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb,
				unsigned int buffer_length)
{}

/*
 * Frees an input endpoint.
 * May be called when ep hasn't been initialized completely.
 */
static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint *ep)
{}

/*
 * Creates an input endpoint.
 */
static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi *umidi,
					  struct snd_usb_midi_endpoint_info *ep_info,
					  struct snd_usb_midi_endpoint *rep)
{}

/*
 * Frees an output endpoint.
 * May be called when ep hasn't been initialized completely.
 */
static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
{}

static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
{}

/*
 * Creates an output endpoint, and initializes output ports.
 */
static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi,
					   struct snd_usb_midi_endpoint_info *ep_info,
					   struct snd_usb_midi_endpoint *rep)
{}

/*
 * Frees everything.
 */
static void snd_usbmidi_free(struct snd_usb_midi *umidi)
{}

/*
 * Unlinks all URBs (must be done before the usb_device is deleted).
 */
void snd_usbmidi_disconnect(struct list_head *p)
{}
EXPORT_SYMBOL();

static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi)
{}

static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_midi *umidi,
								int stream,
								int number)
{}

/*
 * This list specifies names for ports that do not fit into the standard
 * "(product) MIDI (n)" schema because they aren't external MIDI ports,
 * such as internal control or synthesizer ports.
 */
static struct port_info {} snd_usbmidi_port_info[] =;

static struct port_info *find_port_info(struct snd_usb_midi *umidi, int number)
{}

static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number,
				      struct snd_seq_port_info *seq_port_info)
{}

/* return iJack for the corresponding jackID */
static int find_usb_ijack(struct usb_host_interface *hostif, uint8_t jack_id)
{}

static void snd_usbmidi_init_substream(struct snd_usb_midi *umidi,
				       int stream, int number, int jack_id,
				       struct snd_rawmidi_substream **rsubstream)
{}

/*
 * Creates the endpoints and their ports.
 */
static int snd_usbmidi_create_endpoints(struct snd_usb_midi *umidi,
					struct snd_usb_midi_endpoint_info *endpoints)
{}

static struct usb_ms_endpoint_descriptor *find_usb_ms_endpoint_descriptor(
					struct usb_host_endpoint *hostep)
{}

/*
 * Returns MIDIStreaming device capabilities.
 */
static int snd_usbmidi_get_ms_info(struct snd_usb_midi *umidi,
				   struct snd_usb_midi_endpoint_info *endpoints)
{}

static int roland_load_info(struct snd_kcontrol *kcontrol,
			    struct snd_ctl_elem_info *info)
{}

static int roland_load_get(struct snd_kcontrol *kcontrol,
			   struct snd_ctl_elem_value *value)
{}

static int roland_load_put(struct snd_kcontrol *kcontrol,
			   struct snd_ctl_elem_value *value)
{}

static const struct snd_kcontrol_new roland_load_ctl =;

/*
 * On Roland devices, use the second alternate setting to be able to use
 * the interrupt input endpoint.
 */
static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi *umidi)
{}

/*
 * Try to find any usable endpoints in the interface.
 */
static int snd_usbmidi_detect_endpoints(struct snd_usb_midi *umidi,
					struct snd_usb_midi_endpoint_info *endpoint,
					int max_endpoints)
{}

/*
 * Detects the endpoints for one-port-per-endpoint protocols.
 */
static int snd_usbmidi_detect_per_port_endpoints(struct snd_usb_midi *umidi,
						 struct snd_usb_midi_endpoint_info *endpoints)
{}

/*
 * Detects the endpoints and ports of Yamaha devices.
 */
static int snd_usbmidi_detect_yamaha(struct snd_usb_midi *umidi,
				     struct snd_usb_midi_endpoint_info *endpoint)
{}

/*
 * Detects the endpoints and ports of Roland devices.
 */
static int snd_usbmidi_detect_roland(struct snd_usb_midi *umidi,
				     struct snd_usb_midi_endpoint_info *endpoint)
{}

/*
 * Creates the endpoints and their ports for Midiman devices.
 */
static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi,
						struct snd_usb_midi_endpoint_info *endpoint)
{}

static const struct snd_rawmidi_global_ops snd_usbmidi_ops =;

static int snd_usbmidi_create_rawmidi(struct snd_usb_midi *umidi,
				      int out_ports, int in_ports)
{}

/*
 * Temporarily stop input.
 */
void snd_usbmidi_input_stop(struct list_head *p)
{}
EXPORT_SYMBOL();

static void snd_usbmidi_input_start_ep(struct snd_usb_midi *umidi,
				       struct snd_usb_midi_in_endpoint *ep)
{}

/*
 * Resume input after a call to snd_usbmidi_input_stop().
 */
void snd_usbmidi_input_start(struct list_head *p)
{}
EXPORT_SYMBOL();

/*
 * Prepare for suspend. Typically called from the USB suspend callback.
 */
void snd_usbmidi_suspend(struct list_head *p)
{}
EXPORT_SYMBOL();

/*
 * Resume. Typically called from the USB resume callback.
 */
void snd_usbmidi_resume(struct list_head *p)
{}
EXPORT_SYMBOL();

/*
 * Creates and registers everything needed for a MIDI streaming interface.
 */
int __snd_usbmidi_create(struct snd_card *card,
			 struct usb_interface *iface,
			 struct list_head *midi_list,
			 const struct snd_usb_audio_quirk *quirk,
			 unsigned int usb_id,
			 unsigned int *num_rawmidis)
{}
EXPORT_SYMBOL();