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