 9a303dc7ba
			
		
	
	
	9a303dc7ba
	
	
	
		
			
			Make the returns a bit more kernel standard style. Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			6.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			6.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * sound/oss/v_midi.c
 | |
|  *
 | |
|  * The low level driver for the Sound Blaster DS chips.
 | |
|  *
 | |
|  *
 | |
|  * Copyright (C) by Hannu Savolainen 1993-1996
 | |
|  *
 | |
|  * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 | |
|  * Version 2 (June 1991). See the "COPYING" file distributed with this software
 | |
|  * for more info.
 | |
|  * ??
 | |
|  *
 | |
|  * Changes
 | |
|  *	Alan Cox		Modularisation, changed memory allocations
 | |
|  *	Christoph Hellwig	Adapted to module_init/module_exit
 | |
|  *
 | |
|  * Status
 | |
|  *	Untested
 | |
|  */
 | |
| 
 | |
| #include <linux/init.h>
 | |
| #include <linux/module.h>
 | |
| #include <linux/slab.h>
 | |
| #include <linux/spinlock.h>
 | |
| #include "sound_config.h"
 | |
| 
 | |
| #include "v_midi.h"
 | |
| 
 | |
| static vmidi_devc *v_devc[2] = { NULL, NULL};
 | |
| static int midi1,midi2;
 | |
| static void *midi_mem = NULL;
 | |
| 
 | |
| /*
 | |
|  * The DSP channel can be used either for input or output. Variable
 | |
|  * 'sb_irq_mode' will be set when the program calls read or write first time
 | |
|  * after open. Current version doesn't support mode changes without closing
 | |
|  * and reopening the device. Support for this feature may be implemented in a
 | |
|  * future version of this driver.
 | |
|  */
 | |
| 
 | |
| 
 | |
| static int v_midi_open (int dev, int mode,
 | |
| 	      void            (*input) (int dev, unsigned char data),
 | |
| 	      void            (*output) (int dev)
 | |
| )
 | |
| {
 | |
| 	vmidi_devc *devc = midi_devs[dev]->devc;
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	if (devc == NULL)
 | |
| 		return -ENXIO;
 | |
| 
 | |
| 	spin_lock_irqsave(&devc->lock,flags);
 | |
| 	if (devc->opened)
 | |
| 	{
 | |
| 		spin_unlock_irqrestore(&devc->lock,flags);
 | |
| 		return -EBUSY;
 | |
| 	}
 | |
| 	devc->opened = 1;
 | |
| 	spin_unlock_irqrestore(&devc->lock,flags);
 | |
| 
 | |
| 	devc->intr_active = 1;
 | |
| 
 | |
| 	if (mode & OPEN_READ)
 | |
| 	{
 | |
| 		devc->input_opened = 1;
 | |
| 		devc->midi_input_intr = input;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void v_midi_close (int dev)
 | |
| {
 | |
| 	vmidi_devc *devc = midi_devs[dev]->devc;
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	if (devc == NULL)
 | |
| 		return;
 | |
| 
 | |
| 	spin_lock_irqsave(&devc->lock,flags);
 | |
| 	devc->intr_active = 0;
 | |
| 	devc->input_opened = 0;
 | |
| 	devc->opened = 0;
 | |
| 	spin_unlock_irqrestore(&devc->lock,flags);
 | |
| }
 | |
| 
 | |
| static int v_midi_out (int dev, unsigned char midi_byte)
 | |
| {
 | |
| 	vmidi_devc *devc = midi_devs[dev]->devc;
 | |
| 	vmidi_devc *pdevc;
 | |
| 
 | |
| 	if (devc == NULL)
 | |
| 		return -ENXIO;
 | |
| 
 | |
| 	pdevc = midi_devs[devc->pair_mididev]->devc;
 | |
| 	if (pdevc->input_opened > 0){
 | |
| 		if (MIDIbuf_avail(pdevc->my_mididev) > 500)
 | |
| 			return 0;
 | |
| 		pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
 | |
| 	}
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static inline int v_midi_start_read (int dev)
 | |
| {
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int v_midi_end_read (int dev)
 | |
| {
 | |
| 	vmidi_devc *devc = midi_devs[dev]->devc;
 | |
| 	if (devc == NULL)
 | |
| 		return -ENXIO;
 | |
| 
 | |
| 	devc->intr_active = 0;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* why -EPERM and not -EINVAL?? */
 | |
| 
 | |
| static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
 | |
| {
 | |
| 	return -EPERM;
 | |
| }
 | |
| 
 | |
| 
 | |
| #define MIDI_SYNTH_NAME	"Loopback MIDI"
 | |
| #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
 | |
| 
 | |
| #include "midi_synth.h"
 | |
| 
 | |
| static struct midi_operations v_midi_operations =
 | |
| {
 | |
| 	.owner		= THIS_MODULE,
 | |
| 	.info		= {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
 | |
| 	.converter	= &std_midi_synth,
 | |
| 	.in_info	= {0},
 | |
| 	.open		= v_midi_open,
 | |
| 	.close		= v_midi_close,
 | |
| 	.ioctl		= v_midi_ioctl,
 | |
| 	.outputc	= v_midi_out,
 | |
| 	.start_read	= v_midi_start_read,
 | |
| 	.end_read	= v_midi_end_read,
 | |
| };
 | |
| 
 | |
| static struct midi_operations v_midi_operations2 =
 | |
| {
 | |
| 	.owner		= THIS_MODULE,
 | |
| 	.info		= {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
 | |
| 	.converter	= &std_midi_synth,
 | |
| 	.in_info	= {0},
 | |
| 	.open		= v_midi_open,
 | |
| 	.close		= v_midi_close,
 | |
| 	.ioctl		= v_midi_ioctl,
 | |
| 	.outputc	= v_midi_out,
 | |
| 	.start_read	= v_midi_start_read,
 | |
| 	.end_read	= v_midi_end_read,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  *	We kmalloc just one of these - it makes life simpler and the code
 | |
|  *	cleaner and the memory handling far more efficient
 | |
|  */
 | |
|  
 | |
| struct vmidi_memory
 | |
| {
 | |
| 	/* Must be first */
 | |
| 	struct midi_operations m_ops[2];
 | |
| 	struct synth_operations s_ops[2];
 | |
| 	struct vmidi_devc v_ops[2];
 | |
| };
 | |
| 
 | |
| static void __init attach_v_midi (struct address_info *hw_config)
 | |
| {
 | |
| 	struct vmidi_memory *m;
 | |
| 	/* printk("Attaching v_midi device.....\n"); */
 | |
| 
 | |
| 	midi1 = sound_alloc_mididev();
 | |
| 	if (midi1 == -1)
 | |
| 	{
 | |
| 		printk(KERN_ERR "v_midi: Too many midi devices detected\n");
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
 | |
| 	if (m == NULL)
 | |
| 	{
 | |
| 		printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
 | |
| 		sound_unload_mididev(midi1);
 | |
| 		return;
 | |
| 	}
 | |
| 	
 | |
| 	midi_mem = m;
 | |
| 	
 | |
| 	midi_devs[midi1] = &m->m_ops[0];
 | |
| 	
 | |
| 
 | |
| 	midi2 = sound_alloc_mididev();
 | |
| 	if (midi2 == -1)
 | |
| 	{
 | |
| 		printk (KERN_ERR "v_midi: Too many midi devices detected\n");
 | |
| 		kfree(m);
 | |
| 		sound_unload_mididev(midi1);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	midi_devs[midi2] = &m->m_ops[1];
 | |
| 
 | |
| 	/* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
 | |
| 
 | |
| 	/* for MIDI-1 */
 | |
| 	v_devc[0] = &m->v_ops[0];
 | |
| 	memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
 | |
| 		sizeof (struct midi_operations));
 | |
| 
 | |
| 	v_devc[0]->my_mididev = midi1;
 | |
| 	v_devc[0]->pair_mididev = midi2;
 | |
| 	v_devc[0]->opened = v_devc[0]->input_opened = 0;
 | |
| 	v_devc[0]->intr_active = 0;
 | |
| 	v_devc[0]->midi_input_intr = NULL;
 | |
| 	spin_lock_init(&v_devc[0]->lock);
 | |
| 
 | |
| 	midi_devs[midi1]->devc = v_devc[0];
 | |
| 
 | |
| 	midi_devs[midi1]->converter = &m->s_ops[0];
 | |
| 	std_midi_synth.midi_dev = midi1;
 | |
| 	memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
 | |
| 		sizeof (struct synth_operations));
 | |
| 	midi_devs[midi1]->converter->id = "V_MIDI 1";
 | |
| 
 | |
| 	/* for MIDI-2 */
 | |
| 	v_devc[1] = &m->v_ops[1];
 | |
| 
 | |
| 	memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
 | |
| 		sizeof (struct midi_operations));
 | |
| 
 | |
| 	v_devc[1]->my_mididev = midi2;
 | |
| 	v_devc[1]->pair_mididev = midi1;
 | |
| 	v_devc[1]->opened = v_devc[1]->input_opened = 0;
 | |
| 	v_devc[1]->intr_active = 0;
 | |
| 	v_devc[1]->midi_input_intr = NULL;
 | |
| 	spin_lock_init(&v_devc[1]->lock);
 | |
| 
 | |
| 	midi_devs[midi2]->devc = v_devc[1];
 | |
| 	midi_devs[midi2]->converter = &m->s_ops[1];
 | |
| 
 | |
| 	std_midi_synth.midi_dev = midi2;
 | |
| 	memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
 | |
| 		sizeof (struct synth_operations));
 | |
| 	midi_devs[midi2]->converter->id = "V_MIDI 2";
 | |
| 
 | |
| 	sequencer_init();
 | |
| 	/* printk("Attached v_midi device\n"); */
 | |
| }
 | |
| 
 | |
| static inline int __init probe_v_midi(struct address_info *hw_config)
 | |
| {
 | |
| 	return(1);	/* always OK */
 | |
| }
 | |
| 
 | |
| 
 | |
| static void __exit unload_v_midi(struct address_info *hw_config)
 | |
| {
 | |
| 	sound_unload_mididev(midi1);
 | |
| 	sound_unload_mididev(midi2);
 | |
| 	kfree(midi_mem);
 | |
| }
 | |
| 
 | |
| static struct address_info cfg; /* dummy */
 | |
| 
 | |
| static int __init init_vmidi(void)
 | |
| {
 | |
| 	printk("MIDI Loopback device driver\n");
 | |
| 	if (!probe_v_midi(&cfg))
 | |
| 		return -ENODEV;
 | |
| 	attach_v_midi(&cfg);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void __exit cleanup_vmidi(void)
 | |
| {
 | |
| 	unload_v_midi(&cfg);
 | |
| }
 | |
| 
 | |
| module_init(init_vmidi);
 | |
| module_exit(cleanup_vmidi);
 | |
| MODULE_LICENSE("GPL");
 |