linux/sound/oss/sb_midi.c
<<
>>
Prefs
   1/*
   2 * sound/oss/sb_midi.c
   3 *
   4 * The low level driver for the Sound Blaster DS chips.
   5 *
   6 *
   7 * Copyright (C) by Hannu Savolainen 1993-1997
   8 *
   9 * OSS/Free 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#include <linux/spinlock.h>
  15
  16#include "sound_config.h"
  17
  18#include "sb.h"
  19#undef SB_TEST_IRQ
  20
  21/*
  22 * The DSP channel can be used either for input or output. Variable
  23 * 'sb_irq_mode' will be set when the program calls read or write first time
  24 * after open. Current version doesn't support mode changes without closing
  25 * and reopening the device. Support for this feature may be implemented in a
  26 * future version of this driver.
  27 */
  28
  29
  30static int sb_midi_open(int dev, int mode,
  31             void            (*input) (int dev, unsigned char data),
  32             void            (*output) (int dev)
  33)
  34{
  35        sb_devc *devc = midi_devs[dev]->devc;
  36        unsigned long flags;
  37
  38        if (devc == NULL)
  39                return -ENXIO;
  40
  41        spin_lock_irqsave(&devc->lock, flags);
  42        if (devc->opened)
  43        {
  44                spin_unlock_irqrestore(&devc->lock, flags);
  45                return -EBUSY;
  46        }
  47        devc->opened = 1;
  48        spin_unlock_irqrestore(&devc->lock, flags);
  49
  50        devc->irq_mode = IMODE_MIDI;
  51        devc->midi_broken = 0;
  52
  53        sb_dsp_reset(devc);
  54
  55        if (!sb_dsp_command(devc, 0x35))        /* Start MIDI UART mode */
  56        {
  57                  devc->opened = 0;
  58                  return -EIO;
  59        }
  60        devc->intr_active = 1;
  61
  62        if (mode & OPEN_READ)
  63        {
  64                devc->input_opened = 1;
  65                devc->midi_input_intr = input;
  66        }
  67        return 0;
  68}
  69
  70static void sb_midi_close(int dev)
  71{
  72        sb_devc *devc = midi_devs[dev]->devc;
  73        unsigned long flags;
  74
  75        if (devc == NULL)
  76                return;
  77
  78        spin_lock_irqsave(&devc->lock, flags);
  79        sb_dsp_reset(devc);
  80        devc->intr_active = 0;
  81        devc->input_opened = 0;
  82        devc->opened = 0;
  83        spin_unlock_irqrestore(&devc->lock, flags);
  84}
  85
  86static int sb_midi_out(int dev, unsigned char midi_byte)
  87{
  88        sb_devc *devc = midi_devs[dev]->devc;
  89
  90        if (devc == NULL)
  91                return 1;
  92
  93        if (devc->midi_broken)
  94                return 1;
  95
  96        if (!sb_dsp_command(devc, midi_byte))
  97        {
  98                devc->midi_broken = 1;
  99                return 1;
 100        }
 101        return 1;
 102}
 103
 104static int sb_midi_start_read(int dev)
 105{
 106        return 0;
 107}
 108
 109static int sb_midi_end_read(int dev)
 110{
 111        sb_devc *devc = midi_devs[dev]->devc;
 112
 113        if (devc == NULL)
 114                return -ENXIO;
 115
 116        sb_dsp_reset(devc);
 117        devc->intr_active = 0;
 118        return 0;
 119}
 120
 121static int sb_midi_ioctl(int dev, unsigned cmd, void __user *arg)
 122{
 123        return -EINVAL;
 124}
 125
 126void sb_midi_interrupt(sb_devc * devc)
 127{
 128        unsigned long   flags;
 129        unsigned char   data;
 130
 131        if (devc == NULL)
 132                return;
 133
 134        spin_lock_irqsave(&devc->lock, flags);
 135
 136        data = inb(DSP_READ);
 137        if (devc->input_opened)
 138                devc->midi_input_intr(devc->my_mididev, data);
 139
 140        spin_unlock_irqrestore(&devc->lock, flags);
 141}
 142
 143#define MIDI_SYNTH_NAME "Sound Blaster Midi"
 144#define MIDI_SYNTH_CAPS 0
 145#include "midi_synth.h"
 146
 147static struct midi_operations sb_midi_operations =
 148{
 149        .owner          = THIS_MODULE,
 150        .info           = {"Sound Blaster", 0, 0, SNDCARD_SB},
 151        .converter      = &std_midi_synth,
 152        .in_info        = {0},
 153        .open           = sb_midi_open,
 154        .close          = sb_midi_close,
 155        .ioctl          = sb_midi_ioctl,
 156        .outputc        = sb_midi_out,
 157        .start_read     = sb_midi_start_read,
 158        .end_read       = sb_midi_end_read,
 159};
 160
 161void sb_dsp_midi_init(sb_devc * devc, struct module *owner)
 162{
 163        int dev;
 164
 165        if (devc->model < 2)    /* No MIDI support for SB 1.x */
 166                return;
 167
 168        dev = sound_alloc_mididev();
 169
 170        if (dev == -1)
 171        {
 172                printk(KERN_ERR "sb_midi: too many MIDI devices detected\n");
 173                return;
 174        }
 175        std_midi_synth.midi_dev = devc->my_mididev = dev;
 176        midi_devs[dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
 177        if (midi_devs[dev] == NULL)
 178        {
 179                printk(KERN_WARNING "Sound Blaster:  failed to allocate MIDI memory.\n");
 180                sound_unload_mididev(dev);
 181                  return;
 182        }
 183        memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations,
 184               sizeof(struct midi_operations));
 185
 186        if (owner)
 187                        midi_devs[dev]->owner = owner;
 188        
 189        midi_devs[dev]->devc = devc;
 190
 191
 192        midi_devs[dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL);
 193        if (midi_devs[dev]->converter == NULL)
 194        {
 195                  printk(KERN_WARNING "Sound Blaster:  failed to allocate MIDI memory.\n");
 196                  kfree(midi_devs[dev]);
 197                  sound_unload_mididev(dev);
 198                  return;
 199        }
 200        memcpy((char *) midi_devs[dev]->converter, (char *) &std_midi_synth,
 201               sizeof(struct synth_operations));
 202
 203        midi_devs[dev]->converter->id = "SBMIDI";
 204        sequencer_init();
 205}
 206