omap: Runtime detection of Si features
[linux-ginger.git] / sound / oss / v_midi.c
blob103940fd5b4f46e9e2ae7c8435acf64938679faa
1 /*
2 * sound/oss/v_midi.c
4 * The low level driver for the Sound Blaster DS chips.
7 * Copyright (C) by Hannu Savolainen 1993-1996
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 * ??
14 * Changes
15 * Alan Cox Modularisation, changed memory allocations
16 * Christoph Hellwig Adapted to module_init/module_exit
18 * Status
19 * Untested
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/spinlock.h>
25 #include "sound_config.h"
27 #include "v_midi.h"
29 static vmidi_devc *v_devc[2] = { NULL, NULL};
30 static int midi1,midi2;
31 static void *midi_mem = NULL;
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.
42 static int v_midi_open (int dev, int mode,
43 void (*input) (int dev, unsigned char data),
44 void (*output) (int dev)
47 vmidi_devc *devc = midi_devs[dev]->devc;
48 unsigned long flags;
50 if (devc == NULL)
51 return -(ENXIO);
53 spin_lock_irqsave(&devc->lock,flags);
54 if (devc->opened)
56 spin_unlock_irqrestore(&devc->lock,flags);
57 return -(EBUSY);
59 devc->opened = 1;
60 spin_unlock_irqrestore(&devc->lock,flags);
62 devc->intr_active = 1;
64 if (mode & OPEN_READ)
66 devc->input_opened = 1;
67 devc->midi_input_intr = input;
70 return 0;
73 static void v_midi_close (int dev)
75 vmidi_devc *devc = midi_devs[dev]->devc;
76 unsigned long flags;
78 if (devc == NULL)
79 return;
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);
88 static int v_midi_out (int dev, unsigned char midi_byte)
90 vmidi_devc *devc = midi_devs[dev]->devc;
91 vmidi_devc *pdevc;
93 if (devc == NULL)
94 return -ENXIO;
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);
102 return 1;
105 static inline int v_midi_start_read (int dev)
107 return 0;
110 static int v_midi_end_read (int dev)
112 vmidi_devc *devc = midi_devs[dev]->devc;
113 if (devc == NULL)
114 return -ENXIO;
116 devc->intr_active = 0;
117 return 0;
120 /* why -EPERM and not -EINVAL?? */
122 static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
124 return -EPERM;
128 #define MIDI_SYNTH_NAME "Loopback MIDI"
129 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
131 #include "midi_synth.h"
133 static struct midi_operations v_midi_operations =
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,
147 static struct midi_operations v_midi_operations2 =
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,
162 * We kmalloc just one of these - it makes life simpler and the code
163 * cleaner and the memory handling far more efficient
166 struct vmidi_memory
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];
174 static void __init attach_v_midi (struct address_info *hw_config)
176 struct vmidi_memory *m;
177 /* printk("Attaching v_midi device.....\n"); */
179 midi1 = sound_alloc_mididev();
180 if (midi1 == -1)
182 printk(KERN_ERR "v_midi: Too many midi devices detected\n");
183 return;
186 m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
187 if (m == NULL)
189 printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
190 sound_unload_mididev(midi1);
191 return;
194 midi_mem = m;
196 midi_devs[midi1] = &m->m_ops[0];
199 midi2 = sound_alloc_mididev();
200 if (midi2 == -1)
202 printk (KERN_ERR "v_midi: Too many midi devices detected\n");
203 kfree(m);
204 sound_unload_mididev(midi1);
205 return;
208 midi_devs[midi2] = &m->m_ops[1];
210 /* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */
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));
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);
224 midi_devs[midi1]->devc = v_devc[0];
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";
232 /* for MIDI-2 */
233 v_devc[1] = &m->v_ops[1];
235 memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
236 sizeof (struct midi_operations));
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);
245 midi_devs[midi2]->devc = v_devc[1];
246 midi_devs[midi2]->converter = &m->s_ops[1];
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";
253 sequencer_init();
254 /* printk("Attached v_midi device\n"); */
257 static inline int __init probe_v_midi(struct address_info *hw_config)
259 return(1); /* always OK */
263 static void __exit unload_v_midi(struct address_info *hw_config)
265 sound_unload_mididev(midi1);
266 sound_unload_mididev(midi2);
267 kfree(midi_mem);
270 static struct address_info cfg; /* dummy */
272 static int __init init_vmidi(void)
274 printk("MIDI Loopback device driver\n");
275 if (!probe_v_midi(&cfg))
276 return -ENODEV;
277 attach_v_midi(&cfg);
279 return 0;
282 static void __exit cleanup_vmidi(void)
284 unload_v_midi(&cfg);
287 module_init(init_vmidi);
288 module_exit(cleanup_vmidi);
289 MODULE_LICENSE("GPL");