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