Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  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
 30static vmidi_devc *v_devc[2] = { NULL, NULL};
 31static int midi1,midi2;
 32static 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
 43static 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
 74static 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
 89static 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
106static inline int v_midi_start_read (int dev)
107{
108	return 0;
109}
110
111static 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
123static 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
134static 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
148static 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 
167struct 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
175static 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
258static inline int __init probe_v_midi(struct address_info *hw_config)
259{
260	return(1);	/* always OK */
261}
262
263
264static 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
271static struct address_info cfg; /* dummy */
272
273static 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
283static void __exit cleanup_vmidi(void)
284{
285	unload_v_midi(&cfg);
286}
287
288module_init(init_vmidi);
289module_exit(cleanup_vmidi);
290MODULE_LICENSE("GPL");