• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * sound/oss/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 #include <linux/slab.h>
25 #include <linux/spinlock.h>
26 #include "sound_config.h"
27 
28 #include "v_midi.h"
29 
30 static vmidi_devc *v_devc[2] = { NULL, NULL};
31 static int midi1,midi2;
32 static void *midi_mem = NULL;
33 
34 /*
35  * The DSP channel can be used either for input or output. Variable
36  * 'sb_irq_mode' will be set when the program calls read or write first time
37  * after open. Current version doesn't support mode changes without closing
38  * and reopening the device. Support for this feature may be implemented in a
39  * future version of this driver.
40  */
41 
42 
v_midi_open(int dev,int mode,void (* input)(int dev,unsigned char data),void (* output)(int dev))43 static int v_midi_open (int dev, int mode,
44 	      void            (*input) (int dev, unsigned char data),
45 	      void            (*output) (int dev)
46 )
47 {
48 	vmidi_devc *devc = midi_devs[dev]->devc;
49 	unsigned long flags;
50 
51 	if (devc == NULL)
52 		return -(ENXIO);
53 
54 	spin_lock_irqsave(&devc->lock,flags);
55 	if (devc->opened)
56 	{
57 		spin_unlock_irqrestore(&devc->lock,flags);
58 		return -(EBUSY);
59 	}
60 	devc->opened = 1;
61 	spin_unlock_irqrestore(&devc->lock,flags);
62 
63 	devc->intr_active = 1;
64 
65 	if (mode & OPEN_READ)
66 	{
67 		devc->input_opened = 1;
68 		devc->midi_input_intr = input;
69 	}
70 
71 	return 0;
72 }
73 
v_midi_close(int dev)74 static void v_midi_close (int dev)
75 {
76 	vmidi_devc *devc = midi_devs[dev]->devc;
77 	unsigned long flags;
78 
79 	if (devc == NULL)
80 		return;
81 
82 	spin_lock_irqsave(&devc->lock,flags);
83 	devc->intr_active = 0;
84 	devc->input_opened = 0;
85 	devc->opened = 0;
86 	spin_unlock_irqrestore(&devc->lock,flags);
87 }
88 
v_midi_out(int dev,unsigned char midi_byte)89 static int v_midi_out (int dev, unsigned char midi_byte)
90 {
91 	vmidi_devc *devc = midi_devs[dev]->devc;
92 	vmidi_devc *pdevc;
93 
94 	if (devc == NULL)
95 		return -ENXIO;
96 
97 	pdevc = midi_devs[devc->pair_mididev]->devc;
98 	if (pdevc->input_opened > 0){
99 		if (MIDIbuf_avail(pdevc->my_mididev) > 500)
100 			return 0;
101 		pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
102 	}
103 	return 1;
104 }
105 
v_midi_start_read(int dev)106 static inline int v_midi_start_read (int dev)
107 {
108 	return 0;
109 }
110 
v_midi_end_read(int dev)111 static int v_midi_end_read (int dev)
112 {
113 	vmidi_devc *devc = midi_devs[dev]->devc;
114 	if (devc == NULL)
115 		return -ENXIO;
116 
117 	devc->intr_active = 0;
118 	return 0;
119 }
120 
121 /* why -EPERM and not -EINVAL?? */
122 
v_midi_ioctl(int dev,unsigned cmd,void __user * arg)123 static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
124 {
125 	return -EPERM;
126 }
127 
128 
129 #define MIDI_SYNTH_NAME	"Loopback MIDI"
130 #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
131 
132 #include "midi_synth.h"
133 
134 static struct midi_operations v_midi_operations =
135 {
136 	.owner		= THIS_MODULE,
137 	.info		= {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
138 	.converter	= &std_midi_synth,
139 	.in_info	= {0},
140 	.open		= v_midi_open,
141 	.close		= v_midi_close,
142 	.ioctl		= v_midi_ioctl,
143 	.outputc	= v_midi_out,
144 	.start_read	= v_midi_start_read,
145 	.end_read	= v_midi_end_read,
146 };
147 
148 static struct midi_operations v_midi_operations2 =
149 {
150 	.owner		= THIS_MODULE,
151 	.info		= {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
152 	.converter	= &std_midi_synth,
153 	.in_info	= {0},
154 	.open		= v_midi_open,
155 	.close		= v_midi_close,
156 	.ioctl		= v_midi_ioctl,
157 	.outputc	= v_midi_out,
158 	.start_read	= v_midi_start_read,
159 	.end_read	= v_midi_end_read,
160 };
161 
162 /*
163  *	We kmalloc just one of these - it makes life simpler and the code
164  *	cleaner and the memory handling far more efficient
165  */
166 
167 struct vmidi_memory
168 {
169 	/* Must be first */
170 	struct midi_operations m_ops[2];
171 	struct synth_operations s_ops[2];
172 	struct vmidi_devc v_ops[2];
173 };
174 
attach_v_midi(struct address_info * hw_config)175 static void __init attach_v_midi (struct address_info *hw_config)
176 {
177 	struct vmidi_memory *m;
178 	/* printk("Attaching v_midi device.....\n"); */
179 
180 	midi1 = sound_alloc_mididev();
181 	if (midi1 == -1)
182 	{
183 		printk(KERN_ERR "v_midi: Too many midi devices detected\n");
184 		return;
185 	}
186 
187 	m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
188 	if (m == NULL)
189 	{
190 		printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
191 		sound_unload_mididev(midi1);
192 		return;
193 	}
194 
195 	midi_mem = m;
196 
197 	midi_devs[midi1] = &m->m_ops[0];
198 
199 
200 	midi2 = sound_alloc_mididev();
201 	if (midi2 == -1)
202 	{
203 		printk (KERN_ERR "v_midi: Too many midi devices detected\n");
204 		kfree(m);
205 		sound_unload_mididev(midi1);
206 		return;
207 	}
208 
209 	midi_devs[midi2] = &m->m_ops[1];
210 
211 	/* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
212 
213 	/* for MIDI-1 */
214 	v_devc[0] = &m->v_ops[0];
215 	memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
216 		sizeof (struct midi_operations));
217 
218 	v_devc[0]->my_mididev = midi1;
219 	v_devc[0]->pair_mididev = midi2;
220 	v_devc[0]->opened = v_devc[0]->input_opened = 0;
221 	v_devc[0]->intr_active = 0;
222 	v_devc[0]->midi_input_intr = NULL;
223 	spin_lock_init(&v_devc[0]->lock);
224 
225 	midi_devs[midi1]->devc = v_devc[0];
226 
227 	midi_devs[midi1]->converter = &m->s_ops[0];
228 	std_midi_synth.midi_dev = midi1;
229 	memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
230 		sizeof (struct synth_operations));
231 	midi_devs[midi1]->converter->id = "V_MIDI 1";
232 
233 	/* for MIDI-2 */
234 	v_devc[1] = &m->v_ops[1];
235 
236 	memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
237 		sizeof (struct midi_operations));
238 
239 	v_devc[1]->my_mididev = midi2;
240 	v_devc[1]->pair_mididev = midi1;
241 	v_devc[1]->opened = v_devc[1]->input_opened = 0;
242 	v_devc[1]->intr_active = 0;
243 	v_devc[1]->midi_input_intr = NULL;
244 	spin_lock_init(&v_devc[1]->lock);
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 
probe_v_midi(struct address_info * hw_config)258 static inline int __init probe_v_midi(struct address_info *hw_config)
259 {
260 	return(1);	/* always OK */
261 }
262 
263 
unload_v_midi(struct address_info * hw_config)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 
init_vmidi(void)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 
cleanup_vmidi(void)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 MODULE_LICENSE("GPL");
291