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

📄 usb-midi.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  usb-midi.c  --  USB-MIDI driver  Copyright (C) 2001       NAGANO Daisuke <breeze.nagano@nifty.ne.jp>  This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2, or (at your option)  any later version.  This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.  You should have received a copy of the GNU General Public License  along with this program; if not, write to the Free Software  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  This driver is based on:    - 'Universal Serial Bus Device Class Definition for MIDI Device'    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c    - alsa/lowlevel/pci/cs64xx.c    - umidi.c for NetBSD *//* ------------------------------------------------------------------------- */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/usb.h>#include <linux/poll.h>#include <linux/sound.h>#include <linux/init.h>#include <asm/semaphore.h>#include "usb-midi.h"/* ------------------------------------------------------------------------- *//* More verbose on syslog */#undef MIDI_DEBUG#define MIDI_IN_BUFSIZ 1024#define HAVE_SUPPORT_USB_MIDI_CLASS#undef HAVE_SUPPORT_ALSA/* ------------------------------------------------------------------------- */static int singlebyte = 0;MODULE_PARM(singlebyte,"i");MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");static int maxdevices = 4;MODULE_PARM(maxdevices,"i");MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");static int uvendor     = -1;MODULE_PARM(uvendor,"i");MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");static int uproduct    = -1;MODULE_PARM(uproduct,"i");MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");static int uinterface  = -1;MODULE_PARM(uinterface,"i");MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");static int ualt        = -1;MODULE_PARM(ualt,"i");MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");static int umin        = -1;MODULE_PARM(umin,"i");MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");static int umout       = -1;MODULE_PARM(umout,"i");MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");static int ucable      = -1;MODULE_PARM(ucable,"i");MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");/** Note -- the usb_string() returns only Latin-1 characters. * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or * unicode16LE-to-JIS routine is needed to wrap around usb_get_string(). **/static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/MODULE_PARM(ulangid,"h");MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");MODULE_DESCRIPTION("USB-MIDI driver");MODULE_LICENSE("GPL");/* ------------------------------------------------------------------------- *//** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/#define MS_DESCRIPTOR_UNDEFINED	0#define MS_HEADER		1#define MIDI_IN_JACK		2#define MIDI_OUT_JACK		3/* Spec reads: ELEMENT */#define ELEMENT_DESCRIPTOR   	4#define MS_HEADER_LENGTH	7/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/#define DESCRIPTOR_UNDEFINED	0/* Spec reads: MS_GENERAL */#define MS_GENERAL_ENDPOINT	1/** MIDIStreaming MIDI IN and OUT Jack Types **/#define JACK_TYPE_UNDEFINED	0/* Spec reads: EMBEDDED */#define EMBEDDED_JACK		1/* Spec reads: EXTERNAL */#define EXTERNAL_JACK		2/* structure summary        usb_midi_state     usb_device       |         |      *|        *|       per ep     in_ep     out_ep       |         |      *|        *|       per cable      min       mout       |         |       (cable to device pairing magic)       |         |       usb_midi_dev      dev_id (major,minor) == file->private_data*//* usb_midi_state: corresponds to a USB-MIDI module */struct usb_midi_state {	struct list_head   mididev;		struct usb_device *usbdev;		struct list_head   midiDevList;	struct list_head   inEndpointList;	struct list_head   outEndpointList;		spinlock_t         lock;		unsigned int       count; /* usage counter */};/* midi_out_endpoint: corresponds to an output endpoint */struct midi_out_endpoint {	struct list_head  list;		struct usb_device *usbdev;	int                endpoint;	spinlock_t         lock;	wait_queue_head_t  wait;		unsigned char     *buf;	int                bufWrPtr;	int                bufSize;		struct urb       *urb;};/* midi_in_endpoint: corresponds to an input endpoint */struct midi_in_endpoint {	struct list_head   list;	struct usb_device *usbdev;	int                endpoint;	spinlock_t         lock;	wait_queue_head_t  wait;	struct usb_mididev *cables[16];	// cables open for read	int                 readers;	// number of cables open for read	struct urb        *urb;	unsigned char     *recvBuf;	int                recvBufSize;	int                urbSubmitted;	//FIXME: == readers > 0};/* usb_mididev: corresponds to a logical device */struct usb_mididev {	struct list_head       list;	struct usb_midi_state *midi;	int                    dev_midi;	mode_t                 open_mode;	struct {		struct midi_in_endpoint *ep;		int              cableId;		// as we are pushing data from usb_bulk_read to usb_midi_read,// we need a larger, cyclic buffer here.		unsigned char    buf[MIDI_IN_BUFSIZ];		int              bufRdPtr;		int              bufWrPtr;		int              bufRemains;	} min;	struct {		struct midi_out_endpoint *ep;		int              cableId;				unsigned char    buf[3];		int              bufPtr;		int              bufRemains;				int              isInExclusive;		unsigned char    lastEvent;	} mout;	int singlebyte;};/** Map the high nybble of MIDI voice messages to number of Message bytes. * High nyble ranges from 0x8 to 0xe */static int remains_80e0[] = {	3,	/** 0x8X Note Off **/	3,	/** 0x9X Note On **/	3,	/** 0xAX Poly-key pressure **/	3,	/** 0xBX Control Change **/	2,	/** 0xCX Program Change **/	2,	/** 0xDX Channel pressure **/	3 	/** 0xEX PitchBend Change **/};/** Map the messages to a number of Message bytes. * **/static int remains_f0f6[] = {	0,	/** 0xF0 **/	2,	/** 0XF1 **/	3,	/** 0XF2 **/	2,	/** 0XF3 **/	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/	1	/** 0XF6 **/};/** Map the messages to a CIN (Code Index Number). * **/static int cin_f0ff[] = {	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */	2,	/** 0xF1 **/	3,	/** 0xF2 **/	2,	/** 0xF3 **/	2,	/** 0xF4 **/	2,	/** 0xF5 **/	5,	/** 0xF6 **/	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/	5,	/** 0xF8 **/	5,	/** 0xF9 **/	5,	/** 0xFA **/	5,	/** 0xFB **/	5,	/** 0xFC **/	5,	/** 0xFD **/	5,	/** 0xFE **/	5	/** 0xFF **/};/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0) * to the number of bytes of valid MIDI data. * * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0. * **/static int cin_to_len[] = {	0, 0, 2, 3,	3, 1, 2, 3,	3, 3, 3, 3,	2, 2, 3, 1};/* ------------------------------------------------------------------------- */static struct list_head mididevs = LIST_HEAD_INIT(mididevs);static DECLARE_MUTEX(open_sem);static DECLARE_WAIT_QUEUE_HEAD(open_wait);/* ------------------------------------------------------------------------- */static void usb_write_callback(struct urb *urb, struct pt_regs *regs){	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;	if ( waitqueue_active( &ep->wait ) )		wake_up_interruptible( &ep->wait );}static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len ){	struct usb_device *d;	int pipe;	int ret = 0;	int status;	int maxretry = 50;		DECLARE_WAITQUEUE(wait,current);	init_waitqueue_head(&ep->wait);	d = ep->usbdev;	pipe = usb_sndbulkpipe(d, ep->endpoint);	usb_fill_bulk_urb( ep->urb, d, pipe, (unsigned char*)buf, len,		       usb_write_callback, ep );	status = usb_submit_urb(ep->urb, GFP_KERNEL);    	if (status) {		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);		ret = -EIO;		goto error;	}	add_wait_queue( &ep->wait, &wait );	set_current_state( TASK_INTERRUPTIBLE );	while( ep->urb->status == -EINPROGRESS ) {		if ( maxretry-- < 0 ) {			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");			ret = -ETIME;			break;		}		interruptible_sleep_on_timeout( &ep->wait, 10 );	}	set_current_state( TASK_RUNNING );	remove_wait_queue( &ep->wait, &wait );error:	return ret;}/** Copy data from URB to In endpoint buf. * Discard if CIN == 0 or CIN = 1. * * **/static void usb_bulk_read(struct urb *urb, struct pt_regs *regs){	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);	unsigned char *data = urb->transfer_buffer;	int i, j, wake;	if ( !ep->urbSubmitted ) {		return;	}	if ( (urb->status == 0) && (urb->actual_length > 0) ) {		wake = 0;		spin_lock( &ep->lock );		for(j = 0; j < urb->actual_length; j += 4) {			int cin = (data[j]>>0)&0xf;			int cab = (data[j]>>4)&0xf;			struct usb_mididev *cable = ep->cables[cab];			if ( cable ) {				int len = cin_to_len[cin]; /** length of MIDI data **/				for (i = 0; i < len; i++) {					cable->min.buf[cable->min.bufWrPtr] = data[1+i+j];					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)						cable->min.bufRemains += 1;					else /** need to drop data **/						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;					wake = 1;				}			}		}		spin_unlock ( &ep->lock );		if ( wake ) {			wake_up( &ep->wait );		}	}	/* urb->dev must be reinitialized on 2.4.x kernels */	urb->dev = ep->usbdev;	urb->actual_length = 0;	usb_submit_urb(urb, GFP_ATOMIC);}/* ------------------------------------------------------------------------- *//* This routine must be called with spin_lock *//** Wrapper around usb_write(). *  This routine must be called with spin_lock held on ep. *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write(); **/static int flush_midi_buffer( struct midi_out_endpoint *ep ){	int ret=0;	if ( ep->bufWrPtr > 0 ) {		ret = usb_write( ep, ep->buf, ep->bufWrPtr );		ep->bufWrPtr = 0;	}	return ret;}/* ------------------------------------------------------------------------- *//** Given a MIDI Event, determine size of data to be attached to  * USB-MIDI packet. * Returns 1, 2 or 3. * Called by midiWrite(); * Uses remains_80e0 and remains_f0f6; **/static int get_remains(int event){	int ret;	if ( event  < 0x80 ) {		ret = 1;	} else if ( event < 0xf0 ) {		ret = remains_80e0[((event-0x80)>>4)&0x0f];	} else if ( event < 0xf7 ) {		ret = remains_f0f6[event-0xf0];	} else {		ret = 1;	}	return ret;}/** Given the output MIDI data in the output buffer, computes a reasonable  * CIN. * Called by putOneMidiEvent(). **/static int get_CIN( struct usb_mididev *m ){	int cin;	if ( m->mout.buf[0] == 0xf7 ) {		cin = 5;	}	else if ( m->mout.buf[1] == 0xf7 ) {		cin = 6;	}	else if ( m->mout.buf[2] == 0xf7 ) {		cin = 7;	}	else {		if ( m->mout.isInExclusive == 1 ) {			cin = 4;		} else if ( m->mout.buf[0] < 0x80 ) {			/** One byte that we know nothing about. **/			cin = 0xF; 		} else if ( m->mout.buf[0] < 0xf0 ) {			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/			cin = (m->mout.buf[0]>>4)&0x0f; 		}		else {			/** Special lookup table exists for real-time events. **/			cin = cin_f0ff[m->mout.buf[0]-0xf0];		}	}	return cin;}/* ------------------------------------------------------------------------- *//** Move data to USB endpoint buffer. * **/static int put_one_midi_event(struct usb_mididev *m){	int cin;	unsigned long flags;	struct midi_out_endpoint *ep = m->mout.ep;	int ret=0;	cin = get_CIN( m );	if ( cin > 0x0f || cin < 0 ) {		return -EINVAL;	}	spin_lock_irqsave( &ep->lock, flags );	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];	if ( ep->bufWrPtr >= ep->bufSize ) {		ret = flush_midi_buffer( ep );	}	spin_unlock_irqrestore( &ep->lock, flags);	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;	m->mout.bufPtr = 0;	return ret;}/** Write the MIDI message v on the midi device. *  Called by usb_midi_write(); *  Responsible for packaging a MIDI data stream into USB-MIDI packets. **/static int midi_write( struct usb_mididev *m, int v ){	unsigned long flags;	struct midi_out_endpoint *ep = m->mout.ep;	int ret=0;	unsigned char c = (unsigned char)v;	unsigned char sysrt_buf[4];

⌨️ 快捷键说明

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