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

📄 usb-midi.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	if ( m->singlebyte != 0 ) {		/** Simple code to handle the single-byte USB-MIDI protocol. */		spin_lock_irqsave( &ep->lock, flags );		if ( ep->bufWrPtr+4 > ep->bufSize ) {			ret = flush_midi_buffer( ep );			if ( !ret ) {				spin_unlock_irqrestore( &ep->lock, flags );				return ret;			}		}		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */		ep->buf[ep->bufWrPtr++] = c;		ep->buf[ep->bufWrPtr++] = 0;		ep->buf[ep->bufWrPtr++] = 0;		if ( ep->bufWrPtr >= ep->bufSize ) {			ret = flush_midi_buffer( ep );		}		spin_unlock_irqrestore( &ep->lock, flags );		return ret;	}	/** Normal USB-MIDI protocol begins here. */	if ( c > 0xf7 ) {	/* system: Realtime messages */		/** Realtime messages are written IMMEDIATELY. */		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;		sysrt_buf[1] = c;		sysrt_buf[2] = 0;		sysrt_buf[3] = 0;		spin_lock_irqsave( &ep->lock, flags );		ret = usb_write( ep, sysrt_buf, 4 );		spin_unlock_irqrestore( &ep->lock, flags );		/* m->mout.lastEvent = 0; */		return ret;	}	if ( c >= 0x80 ) {		if ( c < 0xf0 ) {			m->mout.lastEvent = c;			m->mout.isInExclusive = 0;			m->mout.bufRemains = get_remains(c);		} else if ( c == 0xf0 ) {			/* m->mout.lastEvent = 0; */			m->mout.isInExclusive = 1;			m->mout.bufRemains = get_remains(c);		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {			/* m->mout.lastEvent = 0; */			m->mout.isInExclusive = 0;			m->mout.bufRemains = 1;		} else if ( c > 0xf0 ) {			/* m->mout.lastEvent = 0; */			m->mout.isInExclusive = 0;			m->mout.bufRemains = get_remains(c);		}    	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {		if ( m->mout.lastEvent == 0 ) {			return 0; /* discard, waiting for the first event */		}		/** track status **/		m->mout.buf[0] = m->mout.lastEvent;		m->mout.bufPtr = 1;		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;	}  	m->mout.buf[m->mout.bufPtr++] = c;	m->mout.bufRemains--;	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {		ret = put_one_midi_event(m);	}	return ret;}/* ------------------------------------------------------------------------- *//** Basic operation on /dev/midiXX as registered through struct file_operations. * *  Basic contract: Used to change the current read/write position in a file. *  On success, the non-negative position is reported. *  On failure, the negative of an error code is reported. * *  Because a MIDIStream is not a file, all seek operations are doomed to fail. * **/static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin){	/** Tell user you cannot seek on a PIPE-like device. **/	return -ESPIPE;}/** Basic operation on /dev/midiXX as registered through struct file_operations. * * Basic contract: Block until count bytes have been read or an error occurs. * **/static ssize_t usb_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos){	struct usb_mididev *m = (struct usb_mididev *)file->private_data;	struct midi_in_endpoint *ep = m->min.ep;	ssize_t ret;	DECLARE_WAITQUEUE(wait, current);	if ( !access_ok(VERIFY_READ, buffer, count) ) {		return -EFAULT;	}	if ( count == 0 ) {		return 0;	}	add_wait_queue( &ep->wait, &wait );	ret = 0;	while( count > 0 ) {		int cnt;		int d = (int)count;		cnt = m->min.bufRemains;		if ( cnt > d ) {			cnt = d;		}		if ( cnt <= 0 ) {			if ( file->f_flags & O_NONBLOCK ) {				if (!ret) 					ret = -EAGAIN;				break;			}			__set_current_state(TASK_INTERRUPTIBLE);			schedule();			if (signal_pending(current)) {				if(!ret)					ret=-ERESTARTSYS;				break;			}			continue;		}		{			int i;			unsigned long flags; /* used to synchronize access to the endpoint */			spin_lock_irqsave( &ep->lock, flags );			for (i = 0; i < cnt; i++) {				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {					if ( !ret )						ret = -EFAULT;					break;				}				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;				m->min.bufRemains -= 1;			}			spin_unlock_irqrestore( &ep->lock, flags );		}		count-=cnt;		buffer+=cnt;		ret+=cnt;		break;	}	remove_wait_queue( &ep->wait, &wait );	set_current_state(TASK_RUNNING);	return ret;}/** Basic operation on /dev/midiXX as registered through struct file_operations. * *  Basic Contract: Take MIDI data byte-by-byte and pass it to *  writeMidi() which packages MIDI data into USB-MIDI stream. *  Then flushMidiData() is called to ensure all bytes have been written *  in a timely fashion. * **/static ssize_t usb_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos){	struct usb_mididev *m = (struct usb_mididev *)file->private_data;	ssize_t ret;	unsigned long int flags;	if ( !access_ok(VERIFY_READ, buffer, count) ) {		return -EFAULT;	}	if ( count == 0 ) {		return 0;	}	ret = 0;	while( count > 0 ) {		unsigned char c;		if (copy_from_user((unsigned char *)&c, buffer, 1)) {			if ( ret == 0 )				ret = -EFAULT;			break;		}		if( midi_write(m, (int)c) ) {			if ( ret == 0 )				ret = -EFAULT;			break;		}		count--;		buffer++;		ret++;	}	spin_lock_irqsave( &m->mout.ep->lock, flags );	if ( flush_midi_buffer(m->mout.ep) < 0 ) {		ret = -EFAULT;	}	spin_unlock_irqrestore( &m->mout.ep->lock, flags );	return ret;}/** Basic operation on /dev/midiXX as registered through struct file_operations. * * Basic contract:  Wait (spin) until ready to read or write on the file. * **/static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait){	struct usb_mididev *m = (struct usb_mididev *)file->private_data;	struct midi_in_endpoint *iep = m->min.ep;	struct midi_out_endpoint *oep = m->mout.ep;	unsigned long flags;	unsigned int mask = 0;  	if ( file->f_mode & FMODE_READ ) {		poll_wait( file, &iep->wait, wait );		spin_lock_irqsave( &iep->lock, flags );		if ( m->min.bufRemains > 0 )			mask |= POLLIN | POLLRDNORM;		spin_unlock_irqrestore( &iep->lock, flags );	}	if ( file->f_mode & FMODE_WRITE ) {		poll_wait( file, &oep->wait, wait );		spin_lock_irqsave( &oep->lock, flags );		if ( oep->bufWrPtr < oep->bufSize )			mask |= POLLOUT | POLLWRNORM;		spin_unlock_irqrestore( &oep->lock, flags );	}	return mask;}/** Basic operation on /dev/midiXX as registered through struct file_operations. * * Basic contract: This is always the first operation performed on the * device node. If no method is defined, the open succeeds without any * notification given to the module. * **/static int usb_midi_open(struct inode *inode, struct file *file){	int minor = iminor(inode);	DECLARE_WAITQUEUE(wait, current);	struct list_head      *devs, *mdevs;	struct usb_midi_state *s;	struct usb_mididev    *m;	unsigned long flags;	int succeed = 0;#if 0	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);#endif	for(;;) {		down(&open_sem);		for (devs = mididevs.next; devs != &mididevs; devs = devs->next) {			s = list_entry(devs, struct usb_midi_state, mididev);			for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) {				m = list_entry(mdevs, struct usb_mididev, list);				if ( !((m->dev_midi ^ minor) & ~0xf) )					goto device_found;			}		}		up(&open_sem);		return -ENODEV;	device_found:		if ( !s->usbdev ) {			up(&open_sem);			return -EIO;		}		if ( !(m->open_mode & file->f_mode) ) {			break;		}		if ( file->f_flags & O_NONBLOCK ) {			up(&open_sem);			return -EBUSY;		}		__set_current_state(TASK_INTERRUPTIBLE);		add_wait_queue( &open_wait, &wait );		up(&open_sem);		schedule();		remove_wait_queue( &open_wait, &wait );		if ( signal_pending(current) ) {			return -ERESTARTSYS;		}	}	file->private_data = m;	spin_lock_irqsave( &s->lock, flags );	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {		//FIXME: intented semantics unclear here		m->min.bufRdPtr       = 0;		m->min.bufWrPtr       = 0;		m->min.bufRemains     = 0;		spin_lock_init(&m->min.ep->lock);		m->mout.bufPtr        = 0;		m->mout.bufRemains    = 0;		m->mout.isInExclusive = 0;		m->mout.lastEvent     = 0;		spin_lock_init(&m->mout.ep->lock);	}	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {		unsigned long int flagsep;		spin_lock_irqsave( &m->min.ep->lock, flagsep );		m->min.ep->cables[m->min.cableId] = m;		m->min.ep->readers += 1;		m->min.bufRdPtr       = 0;		m->min.bufWrPtr       = 0;		m->min.bufRemains     = 0;		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );		if ( !(m->min.ep->urbSubmitted)) {			/* urb->dev must be reinitialized on 2.4.x kernels */			m->min.ep->urb->dev = m->min.ep->usbdev;			if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) {				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");			}			m->min.ep->urbSubmitted = 1;		}		m->open_mode |= FMODE_READ;		succeed = 1;	}	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {		m->mout.bufPtr        = 0;		m->mout.bufRemains    = 0;		m->mout.isInExclusive = 0;		m->mout.lastEvent     = 0;		m->open_mode |= FMODE_WRITE;		succeed = 1;	}	spin_unlock_irqrestore( &s->lock, flags );	s->count++;	up(&open_sem);	/** Changed to prevent extra increments to USE_COUNT. **/	if (!succeed) {		return -EBUSY;	}#if 0	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);#endif	return nonseekable_open(inode, file); /** Success. **/}/** Basic operation on /dev/midiXX as registered through struct file_operations. * *  Basic contract: Close an opened file and deallocate anything we allocated. *  Like open(), this can be missing. If open set file->private_data, *  release() must clear it. * **/static int usb_midi_release(struct inode *inode, struct file *file){	struct usb_mididev *m = (struct usb_mididev *)file->private_data;	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;#if 0	printk(KERN_INFO "usb-midi: Close.\n");#endif	down(&open_sem);	if ( m->open_mode & FMODE_WRITE ) {		m->open_mode &= ~FMODE_WRITE;		usb_unlink_urb( m->mout.ep->urb );	}	if ( m->open_mode & FMODE_READ ) {	        unsigned long int flagsep;	        spin_lock_irqsave( &m->min.ep->lock, flagsep );                m->min.ep->cables[m->min.cableId] = NULL; // discard cable                m->min.ep->readers -= 1;		m->open_mode &= ~FMODE_READ;		if ( m->min.ep->readers == 0 &&                     m->min.ep->urbSubmitted ) {			m->min.ep->urbSubmitted = 0;			usb_unlink_urb(m->min.ep->urb);		}	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );	}	s->count--;	up(&open_sem);	wake_up(&open_wait);	file->private_data = NULL;	return 0;}static struct file_operations usb_midi_fops = {	.owner =	THIS_MODULE,	.llseek =	usb_midi_llseek,	.read =		usb_midi_read,	.write =	usb_midi_write,	.poll =		usb_midi_poll,	.open =		usb_midi_open,	.release =	usb_midi_release,};/* ------------------------------------------------------------------------- *//** Returns filled midi_in_endpoint structure or null on failure. * * Parameters: *	d        - a usb_device *	endPoint - An usb endpoint in the range 0 to 15. * Called by allocUsbMidiDev(); * **/static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint ){	struct midi_in_endpoint *ep;	int bufSize;	int pipe;	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */	pipe =  usb_rcvbulkpipe( d, endPoint );	bufSize = usb_maxpacket( d, pipe, usb_pipein(pipe) );	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);	if ( !ep ) {		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");		return NULL;	}	memset( ep, 0, sizeof(struct midi_in_endpoint) );//      this sets cables[] and readers to 0, too.//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable//      ep->readers = 0;	ep->endpoint = endPoint;	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);	if ( !ep->recvBuf ) {		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");		kfree(ep);		return NULL;	}	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */	if ( !ep->urb ) {		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");		kfree(ep->recvBuf);		kfree(ep);		return NULL;	}	usb_fill_bulk_urb( ep->urb, d, 		       usb_rcvbulkpipe(d, endPoint),		       (unsigned char *)ep->recvBuf, bufSize,		       usb_bulk_read, ep );	/* ep->bufRdPtr     = 0; */	/* ep->bufWrPtr     = 0; */	/* ep->bufRemains   = 0; */	/* ep->urbSubmitted = 0; */	ep->recvBufSize  = bufSize;	init_waitqueue_head(&ep->wait);	return ep;}static int remove_midi_in_endpoint( struct midi_in_endpoint *min ){	usb_unlink_urb( min->urb );	usb_free_urb( min->urb );	kfree( min->recvBuf );	kfree( min );	return 0;}/** Returns filled midi_out_endpoint structure or null on failure. * * Parameters: *	d        - a usb_device *	endPoint - An usb endpoint in the range 0 to 15. * Called by allocUsbMidiDev(); * **/static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint ){	struct midi_out_endpoint *ep = NULL;	int pipe;	int bufSize;	endPoint &= 0x0f;	pipe =  usb_sndbulkpipe( d, endPoint );	bufSize = usb_maxpacket( d, pipe, usb_pipeout(pipe) );	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);	if ( !ep ) {		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");		return NULL;	}	memset( ep, 0, sizeof(struct midi_out_endpoint) );	ep->endpoint = endPoint;	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);	if ( !ep->buf ) {

⌨️ 快捷键说明

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