⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gmidi.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * gmidi.c -- USB MIDI Gadget Driver * * Copyright (C) 2006 Thumtronics Pty Ltd. * Developed for Thumtronics by Grey Innovation * Ben Williamson <ben.williamson@greyinnovation.com> * * This software is distributed under the terms of the GNU General Public * License ("GPL") version 2, as published by the Free Software Foundation. * * This code is based in part on: * * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell. * USB Audio driver, Copyright (C) 2002 by Takashi Iwai. * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch. * * Refer to the USB Device Class Definition for MIDI Devices: * http://www.usb.org/developers/devclass_docs/midi10.pdf *//* #define VERBOSE_DEBUG */#include <linux/kernel.h>#include <linux/utsname.h>#include <linux/device.h>#include <sound/driver.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 "gadget_chips.h"MODULE_AUTHOR("Ben Williamson");MODULE_LICENSE("GPL v2");#define DRIVER_VERSION "25 Jul 2006"static const char shortname[] = "g_midi";static const char longname[] = "MIDI Gadget";static int index = SNDRV_DEFAULT_IDX1;static char *id = SNDRV_DEFAULT_STR1;module_param(index, int, 0444);MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");module_param(id, charp, 0444);MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");/* Some systems will want different product identifers published in the * device descriptor, either numbers or strings or both.  These string * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */static ushort idVendor;module_param(idVendor, ushort, S_IRUGO);MODULE_PARM_DESC(idVendor, "USB Vendor ID");static ushort idProduct;module_param(idProduct, ushort, S_IRUGO);MODULE_PARM_DESC(idProduct, "USB Product ID");static ushort bcdDevice;module_param(bcdDevice, ushort, S_IRUGO);MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");static char *iManufacturer;module_param(iManufacturer, charp, S_IRUGO);MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");static char *iProduct;module_param(iProduct, charp, S_IRUGO);MODULE_PARM_DESC(iProduct, "USB Product string");static char *iSerialNumber;module_param(iSerialNumber, charp, S_IRUGO);MODULE_PARM_DESC(iSerialNumber, "SerialNumber");/* * this version autoconfigures as much as possible, * which is reasonable for most "bulk-only" drivers. */static const char *EP_IN_NAME;static const char *EP_OUT_NAME;/* big enough to hold our biggest descriptor */#define USB_BUFSIZ 256/* 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 gmidi_device* dev;	int active;	uint8_t cable;		/* cable number << 4 */	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 gmidi_device {	spinlock_t		lock;	struct usb_gadget	*gadget;	struct usb_request	*req;		/* for control responses */	u8			config;	struct usb_ep		*in_ep, *out_ep;	struct snd_card		*card;	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	   each direction, but in_port is kept as a	   separate struct so we can have more later. */	struct gmidi_in_port	in_port;	unsigned long		out_triggered;	struct tasklet_struct	tasklet;};static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);#define DBG(d, fmt, args...) \	dev_dbg(&(d)->gadget->dev , fmt , ## args)#define VDBG(d, fmt, args...) \	dev_vdbg(&(d)->gadget->dev , fmt , ## args)#define ERROR(d, fmt, args...) \	dev_err(&(d)->gadget->dev , fmt , ## args)#define WARN(d, fmt, args...) \	dev_warn(&(d)->gadget->dev , fmt , ## args)#define INFO(d, fmt, args...) \	dev_info(&(d)->gadget->dev , fmt , ## args)static unsigned buflen = 256;static unsigned qlen = 32;module_param(buflen, uint, S_IRUGO);module_param(qlen, uint, S_IRUGO);/* Thanks to Grey Innovation for donating this product ID. * * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!! * Instead:  allocate your own, using normal USB-IF procedures. */#define DRIVER_VENDOR_NUM	0x17b3		/* Grey Innovation */#define DRIVER_PRODUCT_NUM	0x0004		/* Linux-USB "MIDI Gadget" *//* * DESCRIPTORS ... most are static, but strings and (full) * configuration descriptors are built on demand. */#define STRING_MANUFACTURER	25#define STRING_PRODUCT		42#define STRING_SERIAL		101#define STRING_MIDI_GADGET	250/* We only have the one configuration, it's number 1. */#define	GMIDI_CONFIG		1/* We have two interfaces- AudioControl and MIDIStreaming */#define GMIDI_AC_INTERFACE	0#define GMIDI_MS_INTERFACE	1#define GMIDI_NUM_INTERFACES	2DECLARE_USB_AC_HEADER_DESCRIPTOR(1);DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);/* B.1  Device Descriptor */static struct usb_device_descriptor device_desc = {	.bLength =		USB_DT_DEVICE_SIZE,	.bDescriptorType =	USB_DT_DEVICE,	.bcdUSB =		__constant_cpu_to_le16(0x0200),	.bDeviceClass =		USB_CLASS_PER_INTERFACE,	.idVendor =		__constant_cpu_to_le16(DRIVER_VENDOR_NUM),	.idProduct =		__constant_cpu_to_le16(DRIVER_PRODUCT_NUM),	.iManufacturer =	STRING_MANUFACTURER,	.iProduct =		STRING_PRODUCT,	.bNumConfigurations =	1,};/* B.2  Configuration Descriptor */static struct usb_config_descriptor config_desc = {	.bLength =		USB_DT_CONFIG_SIZE,	.bDescriptorType =	USB_DT_CONFIG,	/* compute wTotalLength on the fly */	.bNumInterfaces =	GMIDI_NUM_INTERFACES,	.bConfigurationValue =	GMIDI_CONFIG,	.iConfiguration =	STRING_MIDI_GADGET,	/*	 * FIXME: When embedding this driver in a device,	 * these need to be set to reflect the actual	 * power properties of the device. Is it selfpowered?	 */	.bmAttributes =		USB_CONFIG_ATT_ONE,	.bMaxPower =		1,};/* B.3.1  Standard AC Interface Descriptor */static const struct usb_interface_descriptor ac_interface_desc = {	.bLength =		USB_DT_INTERFACE_SIZE,	.bDescriptorType =	USB_DT_INTERFACE,	.bInterfaceNumber =	GMIDI_AC_INTERFACE,	.bNumEndpoints =	0,	.bInterfaceClass =	USB_CLASS_AUDIO,	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,	.iInterface =		STRING_MIDI_GADGET,};/* B.3.2  Class-Specific AC Interface Descriptor */static const struct usb_ac_header_descriptor_1 ac_header_desc = {	.bLength =		USB_DT_AC_HEADER_SIZE(1),	.bDescriptorType =	USB_DT_CS_INTERFACE,	.bDescriptorSubtype =	USB_MS_HEADER,	.bcdADC =		__constant_cpu_to_le16(0x0100),	.wTotalLength =		USB_DT_AC_HEADER_SIZE(1),	.bInCollection =	1,	.baInterfaceNr = {		[0] =		GMIDI_MS_INTERFACE,	}};/* B.4.1  Standard MS Interface Descriptor */static const struct usb_interface_descriptor ms_interface_desc = {	.bLength =		USB_DT_INTERFACE_SIZE,	.bDescriptorType =	USB_DT_INTERFACE,	.bInterfaceNumber =	GMIDI_MS_INTERFACE,	.bNumEndpoints =	2,	.bInterfaceClass =	USB_CLASS_AUDIO,	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,	.iInterface =		STRING_MIDI_GADGET,};/* B.4.2  Class-Specific MS Interface Descriptor */static const struct usb_ms_header_descriptor ms_header_desc = {	.bLength =		USB_DT_MS_HEADER_SIZE,	.bDescriptorType =	USB_DT_CS_INTERFACE,	.bDescriptorSubtype =	USB_MS_HEADER,	.bcdMSC =		__constant_cpu_to_le16(0x0100),	.wTotalLength =		USB_DT_MS_HEADER_SIZE				+ 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 = {	.bLength =		USB_DT_MIDI_IN_SIZE,	.bDescriptorType =	USB_DT_CS_INTERFACE,	.bDescriptorSubtype =	USB_MS_MIDI_IN_JACK,	.bJackType =		USB_MS_EXTERNAL,	.bJackID =		JACK_IN_EXT,};/* B.4.4  MIDI OUT Jack Descriptors */static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {	.bLength =		USB_DT_MIDI_OUT_SIZE(1),	.bDescriptorType =	USB_DT_CS_INTERFACE,	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,	.bJackType =		USB_MS_EMBEDDED,	.bJackID =		JACK_OUT_EMB,	.bNrInputPins =		1,	.pins = {		[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 */static struct usb_endpoint_descriptor bulk_out_desc = {	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_OUT,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,};/* B.5.2  Class-specific MS Bulk OUT Endpoint Descriptor */static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {	.bLength =		USB_DT_MS_ENDPOINT_SIZE(1),	.bDescriptorType =	USB_DT_CS_ENDPOINT,	.bDescriptorSubtype =	USB_MS_GENERAL,	.bNumEmbMIDIJack =	1,	.baAssocJackID = {		[0] =		JACK_IN_EMB,	}};/* B.6.1  Standard Bulk IN Endpoint Descriptor */static struct usb_endpoint_descriptor bulk_in_desc = {	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,	.bDescriptorType =	USB_DT_ENDPOINT,	.bEndpointAddress =	USB_DIR_IN,	.bmAttributes =		USB_ENDPOINT_XFER_BULK,};/* B.6.2  Class-specific MS Bulk IN Endpoint Descriptor */static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {	.bLength =		USB_DT_MS_ENDPOINT_SIZE(1),	.bDescriptorType =	USB_DT_CS_ENDPOINT,	.bDescriptorSubtype =	USB_MS_GENERAL,	.bNumEmbMIDIJack =	1,	.baAssocJackID = {		[0] =		JACK_OUT_EMB,	}};static const struct usb_descriptor_header *gmidi_function [] = {	(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,};static char manufacturer[50];static char product_desc[40] = "MIDI Gadget";static char serial_number[20];/* static strings, in UTF-8 */static struct usb_string strings [] = {	{ STRING_MANUFACTURER, manufacturer, },	{ STRING_PRODUCT, product_desc, },	{ STRING_SERIAL, serial_number, },	{ STRING_MIDI_GADGET, longname, },	{  }			/* end of list */};static struct usb_gadget_strings stringtab = {	.language	= 0x0409,	/* en-us */	.strings	= strings,};static int config_buf(struct usb_gadget *gadget,		u8 *buf, u8 type, unsigned index){	int len;	/* only one configuration */	if (index != 0) {		return -EINVAL;	}	len = usb_gadget_config_buf(&config_desc,			buf, USB_BUFSIZ, gmidi_function);	if (len < 0) {		return len;	}	((struct usb_config_descriptor *)buf)->bDescriptorType = type;	return len;}static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length){	struct usb_request	*req;	req = usb_ep_alloc_request(ep, GFP_ATOMIC);	if (req) {		req->length = length;		req->buf = kmalloc(length, GFP_ATOMIC);		if (!req->buf) {			usb_ep_free_request(ep, req);			req = NULL;		}	}	return req;}static void free_ep_req(struct usb_ep *ep, struct usb_request *req){	kfree(req->buf);	usb_ep_free_request(ep, req);}static const uint8_t gmidi_cin_length[] = {	0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1};/* * Receives a chunk of MIDI data. */static void gmidi_read_data(struct usb_ep *ep, int cable,				   uint8_t *data, int length){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -