File: /usr/src/linux/drivers/sound/v_midi.c

1     /*
2      * sound/v_midi.c
3      *
4      * The low level driver for the Sound Blaster DS chips.
5      *
6      *
7      * Copyright (C) by Hannu Savolainen 1993-1996
8      *
9      * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10      * Version 2 (June 1991). See the "COPYING" file distributed with this software
11      * for more info.
12      * ??
13      *
14      * Changes
15      *	Alan Cox		Modularisation, changed memory allocations
16      *	Christoph Hellwig	Adapted to module_init/module_exit
17      *
18      * Status
19      *	Untested
20      */
21     
22     #include <linux/init.h>
23     #include <linux/module.h>
24     
25     #include "sound_config.h"
26     
27     #include "v_midi.h"
28     
29     static vmidi_devc *v_devc[2] = { NULL, NULL};
30     static int midi1,midi2;
31     static void *midi_mem = NULL;
32     
33     /*
34      * The DSP channel can be used either for input or output. Variable
35      * 'sb_irq_mode' will be set when the program calls read or write first time
36      * after open. Current version doesn't support mode changes without closing
37      * and reopening the device. Support for this feature may be implemented in a
38      * future version of this driver.
39      */
40     
41     
42     void            (*midi_input_intr) (int dev, unsigned char data);
43     
44     static int v_midi_open (int dev, int mode,
45     	      void            (*input) (int dev, unsigned char data),
46     	      void            (*output) (int dev)
47     )
48     {
49     	vmidi_devc *devc = midi_devs[dev]->devc;
50     	unsigned long flags;
51     
52     	if (devc == NULL)
53     		return -(ENXIO);
54     
55     	save_flags (flags);
56     	cli();
57     	if (devc->opened)
58     	{
59     		restore_flags (flags);
60     		return -(EBUSY);
61     	}
62     	devc->opened = 1;
63     	restore_flags (flags);
64     
65     	devc->intr_active = 1;
66     
67     	if (mode & OPEN_READ)
68     	{
69     		devc->input_opened = 1;
70     		devc->midi_input_intr = input;
71     	}
72     
73     	return 0;
74     }
75     
76     static void v_midi_close (int dev)
77     {
78     	vmidi_devc *devc = midi_devs[dev]->devc;
79     	unsigned long flags;
80     
81     	if (devc == NULL)
82     		return;
83     
84     	save_flags (flags);
85     	cli ();
86     	devc->intr_active = 0;
87     	devc->input_opened = 0;
88     	devc->opened = 0;
89     	restore_flags (flags);
90     }
91     
92     static int v_midi_out (int dev, unsigned char midi_byte)
93     {
94     	vmidi_devc *devc = midi_devs[dev]->devc;
95     	vmidi_devc *pdevc = midi_devs[devc->pair_mididev]->devc;
96     
97     	if (devc == NULL)
98     		return -(ENXIO);
99     
100     	if (pdevc->input_opened > 0){
101     		if (MIDIbuf_avail(pdevc->my_mididev) > 500)
102     			return 0;
103     		pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
104     	}
105     	return 1;
106     }
107     
108     static inline int v_midi_start_read (int dev)
109     {
110     	return 0;
111     }
112     
113     static int v_midi_end_read (int dev)
114     {
115     	vmidi_devc *devc = midi_devs[dev]->devc;
116     	if (devc == NULL)
117     		return -ENXIO;
118     
119     	devc->intr_active = 0;
120     	return 0;
121     }
122     
123     /* why -EPERM and not -EINVAL?? */
124     
125     static inline int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
126     {
127     	return -EPERM;
128     }
129     
130     
131     #define MIDI_SYNTH_NAME	"Loopback MIDI"
132     #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
133     
134     #include "midi_synth.h"
135     
136     static struct midi_operations v_midi_operations =
137     {
138     	owner:		THIS_MODULE,
139     	info:		{"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
140     	converter:	&std_midi_synth,
141     	in_info:	{0},
142     	open:		v_midi_open,
143     	close:		v_midi_close,
144     	ioctl:		v_midi_ioctl,
145     	outputc:	v_midi_out,
146     	start_read:	v_midi_start_read,
147     	end_read:	v_midi_end_read,
148     };
149     
150     static struct midi_operations v_midi_operations2 =
151     {
152     	owner:		THIS_MODULE,
153     	info:		{"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
154     	converter:	&std_midi_synth,
155     	in_info:	{0},
156     	open:		v_midi_open,
157     	close:		v_midi_close,
158     	ioctl:		v_midi_ioctl,
159     	outputc:	v_midi_out,
160     	start_read:	v_midi_start_read,
161     	end_read:	v_midi_end_read,
162     };
163     
164     /*
165      *	We kmalloc just one of these - it makes life simpler and the code
166      *	cleaner and the memory handling far more efficient
167      */
168      
169     struct vmidi_memory
170     {
171     	/* Must be first */
172     	struct midi_operations m_ops[2];
173     	struct synth_operations s_ops[2];
174     	struct vmidi_devc v_ops[2];
175     };
176     
177     static void __init attach_v_midi (struct address_info *hw_config)
178     {
179     	struct vmidi_memory *m;
180     	/* printk("Attaching v_midi device.....\n"); */
181     
182     	midi1 = sound_alloc_mididev();
183     	if (midi1 == -1)
184     	{
185     		printk(KERN_ERR "v_midi: Too many midi devices detected\n");
186     		return;
187     	}
188     	
189     	m=(struct vmidi_memory *)kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
190     	if (m == NULL)
191     	{
192     		printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
193     		sound_unload_mididev(midi1);
194     		return;
195     	}
196     	
197     	midi_mem = m;
198     	
199     	midi_devs[midi1] = &m->m_ops[0];
200     	
201     
202     	midi2 = sound_alloc_mididev();
203     	if (midi2 == -1)
204     	{
205     		printk (KERN_ERR "v_midi: Too many midi devices detected\n");
206     		kfree(m);
207     		sound_unload_mididev(midi1);
208     		return;
209     	}
210     
211     	midi_devs[midi2] = &m->m_ops[1];
212     
213     	/* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
214     
215     	/* for MIDI-1 */
216     	v_devc[0] = &m->v_ops[0];
217     	memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
218     		sizeof (struct midi_operations));
219     
220     	v_devc[0]->my_mididev = midi1;
221     	v_devc[0]->pair_mididev = midi2;
222     	v_devc[0]->opened = v_devc[0]->input_opened = 0;
223     	v_devc[0]->intr_active = 0;
224     	v_devc[0]->midi_input_intr = NULL;
225     
226     	midi_devs[midi1]->devc = v_devc[0];
227     
228     	midi_devs[midi1]->converter = &m->s_ops[0];
229     	std_midi_synth.midi_dev = midi1;
230     	memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
231     		sizeof (struct synth_operations));
232     	midi_devs[midi1]->converter->id = "V_MIDI 1";
233     
234     	/* for MIDI-2 */
235     	v_devc[1] = &m->v_ops[1];
236     
237     	memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
238     		sizeof (struct midi_operations));
239     
240     	v_devc[1]->my_mididev = midi2;
241     	v_devc[1]->pair_mididev = midi1;
242     	v_devc[1]->opened = v_devc[1]->input_opened = 0;
243     	v_devc[1]->intr_active = 0;
244     	v_devc[1]->midi_input_intr = NULL;
245     
246     	midi_devs[midi2]->devc = v_devc[1];
247     	midi_devs[midi2]->converter = &m->s_ops[1];
248     
249     	std_midi_synth.midi_dev = midi2;
250     	memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
251     		sizeof (struct synth_operations));
252     	midi_devs[midi2]->converter->id = "V_MIDI 2";
253     
254     	sequencer_init();
255     	/* printk("Attached v_midi device\n"); */
256     }
257     
258     static inline int __init probe_v_midi(struct address_info *hw_config)
259     {
260     	return(1);	/* always OK */
261     }
262     
263     
264     static void __exit unload_v_midi(struct address_info *hw_config)
265     {
266     	sound_unload_mididev(midi1);
267     	sound_unload_mididev(midi2);
268     	kfree(midi_mem);
269     }
270     
271     static struct address_info cfg; /* dummy */
272     
273     static int __init init_vmidi(void)
274     {
275     	printk("MIDI Loopback device driver\n");
276     	if (!probe_v_midi(&cfg))
277     		return -ENODEV;
278     	attach_v_midi(&cfg);
279     
280     	return 0;
281     }
282     
283     static void __exit cleanup_vmidi(void)
284     {
285     	unload_v_midi(&cfg);
286     }
287     
288     module_init(init_vmidi);
289     module_exit(cleanup_vmidi);
290