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/spinlock.h>
  25#include "sound_config.h"
  26
  27#include "v_midi.h"
  28
  29static vmidi_devc *v_devc[2] = { NULL, NULL};
  30static int midi1,midi2;
  31static void *midi_mem = NULL;
  32
  33/*
  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.
  39 */
  40
  41
  42static int v_midi_open (int dev, int mode,
  43              void            (*input) (int dev, unsigned char data),
  44              void            (*output) (int dev)
  45)
  46{
  47        vmidi_devc *devc = midi_devs[dev]->devc;
  48        unsigned long flags;
  49
  50        if (devc == NULL)
  51                return -(ENXIO);
  52
  53        spin_lock_irqsave(&devc->lock,flags);
  54        if (devc->opened)
  55        {
  56                spin_unlock_irqrestore(&devc->lock,flags);
  57                return -(EBUSY);
  58        }
  59        devc->opened = 1;
  60        spin_unlock_irqrestore(&devc->lock,flags);
  61
  62        devc->intr_active = 1;
  63
  64        if (mode & OPEN_READ)
  65        {
  66                devc->input_opened = 1;
  67                devc->midi_input_intr = input;
  68        }
  69
  70        return 0;
  71}
  72
  73static void v_midi_close (int dev)
  74{
  75        vmidi_devc *devc = midi_devs[dev]->devc;
  76        unsigned long flags;
  77
  78        if (devc == NULL)
  79                return;
  80
  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);
  86}
  87
  88static int v_midi_out (int dev, unsigned char midi_byte)
  89{
  90        vmidi_devc *devc = midi_devs[dev]->devc;
  91        vmidi_devc *pdevc;
  92
  93        if (devc == NULL)
  94                return -ENXIO;
  95
  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);
 101        }
 102        return 1;
 103}
 104
 105static inline int v_midi_start_read (int dev)
 106{
 107        return 0;
 108}
 109
 110static int v_midi_end_read (int dev)
 111{
 112        vmidi_devc *devc = midi_devs[dev]->devc;
 113        if (devc == NULL)
 114                return -ENXIO;
 115
 116        devc->intr_active = 0;
 117        return 0;
 118}
 119
 120/* why -EPERM and not -EINVAL?? */
 121
 122static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
 123{
 124        return -EPERM;
 125}
 126
 127
 128#define MIDI_SYNTH_NAME "Loopback MIDI"
 129#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
 130
 131#include "midi_synth.h"
 132
 133static struct midi_operations v_midi_operations =
 134{
 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,
 145};
 146
 147static struct midi_operations v_midi_operations2 =
 148{
 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,
 159};
 160
 161/*
 162 *      We kmalloc just one of these - it makes life simpler and the code
 163 *      cleaner and the memory handling far more efficient
 164 */
 165 
 166struct vmidi_memory
 167{
 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];
 172};
 173
 174static void __init attach_v_midi (struct address_info *hw_config)
 175{
 176        struct vmidi_memory *m;
 177        /* printk("Attaching v_midi device.....\n"); */
 178
 179        midi1 = sound_alloc_mididev();
 180        if (midi1 == -1)
 181        {
 182                printk(KERN_ERR "v_midi: Too many midi devices detected\n");
 183                return;
 184        }
 185        
 186        m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
 187        if (m == NULL)
 188        {
 189                printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
 190                sound_unload_mididev(midi1);
 191                return;
 192        }
 193        
 194        midi_mem = m;
 195        
 196        midi_devs[midi1] = &m->m_ops[0];
 197        
 198
 199        midi2 = sound_alloc_mididev();
 200        if (midi2 == -1)
 201        {
 202                printk (KERN_ERR "v_midi: Too many midi devices detected\n");
 203                kfree(m);
 204                sound_unload_mididev(midi1);
 205                return;
 206        }
 207
 208        midi_devs[midi2] = &m->m_ops[1];
 209
 210        /* printk("VMIDI1: %d   VMIDI2: %d\n",midi1,midi2); */
 211
 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));
 216
 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);
 223
 224        midi_devs[midi1]->devc = v_devc[0];
 225
 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";
 231
 232        /* for MIDI-2 */
 233        v_devc[1] = &m->v_ops[1];
 234
 235        memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
 236                sizeof (struct midi_operations));
 237
 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);
 244
 245        midi_devs[midi2]->devc = v_devc[1];
 246        midi_devs[midi2]->converter = &m->s_ops[1];
 247
 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";
 252
 253        sequencer_init();
 254        /* printk("Attached v_midi device\n"); */
 255}
 256
 257static inline int __init probe_v_midi(struct address_info *hw_config)
 258{
 259        return(1);      /* always OK */
 260}
 261
 262
 263static void __exit unload_v_midi(struct address_info *hw_config)
 264{
 265        sound_unload_mididev(midi1);
 266        sound_unload_mididev(midi2);
 267        kfree(midi_mem);
 268}
 269
 270static struct address_info cfg; /* dummy */
 271
 272static int __init init_vmidi(void)
 273{
 274        printk("MIDI Loopback device driver\n");
 275        if (!probe_v_midi(&cfg))
 276                return -ENODEV;
 277        attach_v_midi(&cfg);
 278
 279        return 0;
 280}
 281
 282static void __exit cleanup_vmidi(void)
 283{
 284        unload_v_midi(&cfg);
 285}
 286
 287module_init(init_vmidi);
 288module_exit(cleanup_vmidi);
 289MODULE_LICENSE("GPL");
 290