]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - sound/oss/v_midi.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6.git] / sound / oss / v_midi.c
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
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
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
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
106 static inline int v_midi_start_read (int dev)
107 {
108         return 0;
109 }
110
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
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
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
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 MODULE_LICENSE("GPL");