• 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/spinlock.h>
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 
v_midi_open(int dev,int mode,void (* input)(int dev,unsigned char data),void (* output)(int dev))42 static int v_midi_open (int dev, int mode,
43 	      void            (*input) (int dev, unsigned char data),
44 	      void            (*output) (int dev)
45 )
46 {
47 	vmidi_devc *devc = midi_devs[dev]->devc;
48 	unsigned long flags;
49 
50 	if (devc == NULL)
51 		return -(ENXIO);
52 
53 	spin_lock_irqsave(&devc->lock,flags);
54 	if (devc->opened)
55 	{
56 		spin_unlock_irqrestore(&devc->lock,flags);
57 		return -(EBUSY);
58 	}
59 	devc->opened = 1;
60 	spin_unlock_irqrestore(&devc->lock,flags);
61 
62 	devc->intr_active = 1;
63 
64 	if (mode & OPEN_READ)
65 	{
66 		devc->input_opened = 1;
67 		devc->midi_input_intr = input;
68 	}
69 
70 	return 0;
71 }
72 
v_midi_close(int dev)73 static void v_midi_close (int dev)
74 {
75 	vmidi_devc *devc = midi_devs[dev]->devc;
76 	unsigned long flags;
77 
78 	if (devc == NULL)
79 		return;
80 
81 	spin_lock_irqsave(&devc->lock,flags);
82 	devc->intr_active = 0;
83 	devc->input_opened = 0;
84 	devc->opened = 0;
85 	spin_unlock_irqrestore(&devc->lock,flags);
86 }
87 
v_midi_out(int dev,unsigned char midi_byte)88 static int v_midi_out (int dev, unsigned char midi_byte)
89 {
90 	vmidi_devc *devc = midi_devs[dev]->devc;
91 	vmidi_devc *pdevc;
92 
93 	if (devc == NULL)
94 		return -ENXIO;
95 
96 	pdevc = midi_devs[devc->pair_mididev]->devc;
97 	if (pdevc->input_opened > 0){
98 		if (MIDIbuf_avail(pdevc->my_mididev) > 500)
99 			return 0;
100 		pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
101 	}
102 	return 1;
103 }
104 
v_midi_start_read(int dev)105 static inline int v_midi_start_read (int dev)
106 {
107 	return 0;
108 }
109 
v_midi_end_read(int dev)110 static int v_midi_end_read (int dev)
111 {
112 	vmidi_devc *devc = midi_devs[dev]->devc;
113 	if (devc == NULL)
114 		return -ENXIO;
115 
116 	devc->intr_active = 0;
117 	return 0;
118 }
119 
120 /* why -EPERM and not -EINVAL?? */
121 
v_midi_ioctl(int dev,unsigned cmd,void __user * arg)122 static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
123 {
124 	return -EPERM;
125 }
126 
127 
128 #define MIDI_SYNTH_NAME	"Loopback MIDI"
129 #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
130 
131 #include "midi_synth.h"
132 
133 static struct midi_operations v_midi_operations =
134 {
135 	.owner		= THIS_MODULE,
136 	.info		= {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
137 	.converter	= &std_midi_synth,
138 	.in_info	= {0},
139 	.open		= v_midi_open,
140 	.close		= v_midi_close,
141 	.ioctl		= v_midi_ioctl,
142 	.outputc	= v_midi_out,
143 	.start_read	= v_midi_start_read,
144 	.end_read	= v_midi_end_read,
145 };
146 
147 static struct midi_operations v_midi_operations2 =
148 {
149 	.owner		= THIS_MODULE,
150 	.info		= {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
151 	.converter	= &std_midi_synth,
152 	.in_info	= {0},
153 	.open		= v_midi_open,
154 	.close		= v_midi_close,
155 	.ioctl		= v_midi_ioctl,
156 	.outputc	= v_midi_out,
157 	.start_read	= v_midi_start_read,
158 	.end_read	= v_midi_end_read,
159 };
160 
161 /*
162  *	We kmalloc just one of these - it makes life simpler and the code
163  *	cleaner and the memory handling far more efficient
164  */
165 
166 struct vmidi_memory
167 {
168 	/* Must be first */
169 	struct midi_operations m_ops[2];
170 	struct synth_operations s_ops[2];
171 	struct vmidi_devc v_ops[2];
172 };
173 
attach_v_midi(struct address_info * hw_config)174 static void __init attach_v_midi (struct address_info *hw_config)
175 {
176 	struct vmidi_memory *m;
177 	/* printk("Attaching v_midi device.....\n"); */
178 
179 	midi1 = sound_alloc_mididev();
180 	if (midi1 == -1)
181 	{
182 		printk(KERN_ERR "v_midi: Too many midi devices detected\n");
183 		return;
184 	}
185 
186 	m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
187 	if (m == NULL)
188 	{
189 		printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
190 		sound_unload_mididev(midi1);
191 		return;
192 	}
193 
194 	midi_mem = m;
195 
196 	midi_devs[midi1] = &m->m_ops[0];
197 
198 
199 	midi2 = sound_alloc_mididev();
200 	if (midi2 == -1)
201 	{
202 		printk (KERN_ERR "v_midi: Too many midi devices detected\n");
203 		kfree(m);
204 		sound_unload_mididev(midi1);
205 		return;
206 	}
207 
208 	midi_devs[midi2] = &m->m_ops[1];
209 
210 	/* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
211 
212 	/* for MIDI-1 */
213 	v_devc[0] = &m->v_ops[0];
214 	memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
215 		sizeof (struct midi_operations));
216 
217 	v_devc[0]->my_mididev = midi1;
218 	v_devc[0]->pair_mididev = midi2;
219 	v_devc[0]->opened = v_devc[0]->input_opened = 0;
220 	v_devc[0]->intr_active = 0;
221 	v_devc[0]->midi_input_intr = NULL;
222 	spin_lock_init(&v_devc[0]->lock);
223 
224 	midi_devs[midi1]->devc = v_devc[0];
225 
226 	midi_devs[midi1]->converter = &m->s_ops[0];
227 	std_midi_synth.midi_dev = midi1;
228 	memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
229 		sizeof (struct synth_operations));
230 	midi_devs[midi1]->converter->id = "V_MIDI 1";
231 
232 	/* for MIDI-2 */
233 	v_devc[1] = &m->v_ops[1];
234 
235 	memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
236 		sizeof (struct midi_operations));
237 
238 	v_devc[1]->my_mididev = midi2;
239 	v_devc[1]->pair_mididev = midi1;
240 	v_devc[1]->opened = v_devc[1]->input_opened = 0;
241 	v_devc[1]->intr_active = 0;
242 	v_devc[1]->midi_input_intr = NULL;
243 	spin_lock_init(&v_devc[1]->lock);
244 
245 	midi_devs[midi2]->devc = v_devc[1];
246 	midi_devs[midi2]->converter = &m->s_ops[1];
247 
248 	std_midi_synth.midi_dev = midi2;
249 	memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
250 		sizeof (struct synth_operations));
251 	midi_devs[midi2]->converter->id = "V_MIDI 2";
252 
253 	sequencer_init();
254 	/* printk("Attached v_midi device\n"); */
255 }
256 
probe_v_midi(struct address_info * hw_config)257 static inline int __init probe_v_midi(struct address_info *hw_config)
258 {
259 	return(1);	/* always OK */
260 }
261 
262 
unload_v_midi(struct address_info * hw_config)263 static void __exit unload_v_midi(struct address_info *hw_config)
264 {
265 	sound_unload_mididev(midi1);
266 	sound_unload_mididev(midi2);
267 	kfree(midi_mem);
268 }
269 
270 static struct address_info cfg; /* dummy */
271 
init_vmidi(void)272 static int __init init_vmidi(void)
273 {
274 	printk("MIDI Loopback device driver\n");
275 	if (!probe_v_midi(&cfg))
276 		return -ENODEV;
277 	attach_v_midi(&cfg);
278 
279 	return 0;
280 }
281 
cleanup_vmidi(void)282 static void __exit cleanup_vmidi(void)
283 {
284 	unload_v_midi(&cfg);
285 }
286 
287 module_init(init_vmidi);
288 module_exit(cleanup_vmidi);
289 MODULE_LICENSE("GPL");
290