123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /*
- * sound/oss/v_midi.c
- *
- * The low level driver for the Sound Blaster DS chips.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1996
- *
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- * ??
- *
- * Changes
- * Alan Cox Modularisation, changed memory allocations
- * Christoph Hellwig Adapted to module_init/module_exit
- *
- * Status
- * Untested
- */
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/spinlock.h>
- #include "sound_config.h"
- #include "v_midi.h"
- static vmidi_devc *v_devc[2] = { NULL, NULL};
- static int midi1,midi2;
- static void *midi_mem = NULL;
- /*
- * The DSP channel can be used either for input or output. Variable
- * 'sb_irq_mode' will be set when the program calls read or write first time
- * after open. Current version doesn't support mode changes without closing
- * and reopening the device. Support for this feature may be implemented in a
- * future version of this driver.
- */
- static int v_midi_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
- )
- {
- vmidi_devc *devc = midi_devs[dev]->devc;
- unsigned long flags;
- if (devc == NULL)
- return -ENXIO;
- spin_lock_irqsave(&devc->lock,flags);
- if (devc->opened)
- {
- spin_unlock_irqrestore(&devc->lock,flags);
- return -EBUSY;
- }
- devc->opened = 1;
- spin_unlock_irqrestore(&devc->lock,flags);
- devc->intr_active = 1;
- if (mode & OPEN_READ)
- {
- devc->input_opened = 1;
- devc->midi_input_intr = input;
- }
- return 0;
- }
- static void v_midi_close (int dev)
- {
- vmidi_devc *devc = midi_devs[dev]->devc;
- unsigned long flags;
- if (devc == NULL)
- return;
- spin_lock_irqsave(&devc->lock,flags);
- devc->intr_active = 0;
- devc->input_opened = 0;
- devc->opened = 0;
- spin_unlock_irqrestore(&devc->lock,flags);
- }
- static int v_midi_out (int dev, unsigned char midi_byte)
- {
- vmidi_devc *devc = midi_devs[dev]->devc;
- vmidi_devc *pdevc;
- if (devc == NULL)
- return -ENXIO;
- pdevc = midi_devs[devc->pair_mididev]->devc;
- if (pdevc->input_opened > 0){
- if (MIDIbuf_avail(pdevc->my_mididev) > 500)
- return 0;
- pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
- }
- return 1;
- }
- static inline int v_midi_start_read (int dev)
- {
- return 0;
- }
- static int v_midi_end_read (int dev)
- {
- vmidi_devc *devc = midi_devs[dev]->devc;
- if (devc == NULL)
- return -ENXIO;
- devc->intr_active = 0;
- return 0;
- }
- /* why -EPERM and not -EINVAL?? */
- static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
- {
- return -EPERM;
- }
- #define MIDI_SYNTH_NAME "Loopback MIDI"
- #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
- #include "midi_synth.h"
- static struct midi_operations v_midi_operations =
- {
- .owner = THIS_MODULE,
- .info = {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
- .converter = &std_midi_synth,
- .in_info = {0},
- .open = v_midi_open,
- .close = v_midi_close,
- .ioctl = v_midi_ioctl,
- .outputc = v_midi_out,
- .start_read = v_midi_start_read,
- .end_read = v_midi_end_read,
- };
- static struct midi_operations v_midi_operations2 =
- {
- .owner = THIS_MODULE,
- .info = {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
- .converter = &std_midi_synth,
- .in_info = {0},
- .open = v_midi_open,
- .close = v_midi_close,
- .ioctl = v_midi_ioctl,
- .outputc = v_midi_out,
- .start_read = v_midi_start_read,
- .end_read = v_midi_end_read,
- };
- /*
- * We kmalloc just one of these - it makes life simpler and the code
- * cleaner and the memory handling far more efficient
- */
-
- struct vmidi_memory
- {
- /* Must be first */
- struct midi_operations m_ops[2];
- struct synth_operations s_ops[2];
- struct vmidi_devc v_ops[2];
- };
- static void __init attach_v_midi (struct address_info *hw_config)
- {
- struct vmidi_memory *m;
- /* printk("Attaching v_midi device.....\n"); */
- midi1 = sound_alloc_mididev();
- if (midi1 == -1)
- {
- printk(KERN_ERR "v_midi: Too many midi devices detected\n");
- return;
- }
-
- m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
- if (m == NULL)
- {
- printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
- sound_unload_mididev(midi1);
- return;
- }
-
- midi_mem = m;
-
- midi_devs[midi1] = &m->m_ops[0];
-
- midi2 = sound_alloc_mididev();
- if (midi2 == -1)
- {
- printk (KERN_ERR "v_midi: Too many midi devices detected\n");
- kfree(m);
- sound_unload_mididev(midi1);
- return;
- }
- midi_devs[midi2] = &m->m_ops[1];
- /* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */
- /* for MIDI-1 */
- v_devc[0] = &m->v_ops[0];
- memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
- sizeof (struct midi_operations));
- v_devc[0]->my_mididev = midi1;
- v_devc[0]->pair_mididev = midi2;
- v_devc[0]->opened = v_devc[0]->input_opened = 0;
- v_devc[0]->intr_active = 0;
- v_devc[0]->midi_input_intr = NULL;
- spin_lock_init(&v_devc[0]->lock);
- midi_devs[midi1]->devc = v_devc[0];
- midi_devs[midi1]->converter = &m->s_ops[0];
- std_midi_synth.midi_dev = midi1;
- memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
- sizeof (struct synth_operations));
- midi_devs[midi1]->converter->id = "V_MIDI 1";
- /* for MIDI-2 */
- v_devc[1] = &m->v_ops[1];
- memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
- sizeof (struct midi_operations));
- v_devc[1]->my_mididev = midi2;
- v_devc[1]->pair_mididev = midi1;
- v_devc[1]->opened = v_devc[1]->input_opened = 0;
- v_devc[1]->intr_active = 0;
- v_devc[1]->midi_input_intr = NULL;
- spin_lock_init(&v_devc[1]->lock);
- midi_devs[midi2]->devc = v_devc[1];
- midi_devs[midi2]->converter = &m->s_ops[1];
- std_midi_synth.midi_dev = midi2;
- memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
- sizeof (struct synth_operations));
- midi_devs[midi2]->converter->id = "V_MIDI 2";
- sequencer_init();
- /* printk("Attached v_midi device\n"); */
- }
- static inline int __init probe_v_midi(struct address_info *hw_config)
- {
- return(1); /* always OK */
- }
- static void __exit unload_v_midi(struct address_info *hw_config)
- {
- sound_unload_mididev(midi1);
- sound_unload_mididev(midi2);
- kfree(midi_mem);
- }
- static struct address_info cfg; /* dummy */
- static int __init init_vmidi(void)
- {
- printk("MIDI Loopback device driver\n");
- if (!probe_v_midi(&cfg))
- return -ENODEV;
- attach_v_midi(&cfg);
- return 0;
- }
- static void __exit cleanup_vmidi(void)
- {
- unload_v_midi(&cfg);
- }
- module_init(init_vmidi);
- module_exit(cleanup_vmidi);
- MODULE_LICENSE("GPL");
|