linux/sound/oss/v_midi.c
<<
>>
Prefs
   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");
 291