linux/sound/isa/wavefront/wavefront_midi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) by Paul Barton-Davis 1998-1999
   4 */
   5
   6/* The low level driver for the WaveFront ICS2115 MIDI interface(s)
   7 *
   8 * Note that there is also an MPU-401 emulation (actually, a UART-401
   9 * emulation) on the CS4232 on the Tropez and Tropez Plus. This code
  10 * has nothing to do with that interface at all.
  11 *
  12 * The interface is essentially just a UART-401, but is has the
  13 * interesting property of supporting what Turtle Beach called
  14 * "Virtual MIDI" mode. In this mode, there are effectively *two*
  15 * MIDI buses accessible via the interface, one that is routed
  16 * solely to/from the external WaveFront synthesizer and the other
  17 * corresponding to the pin/socket connector used to link external
  18 * MIDI devices to the board.
  19 *
  20 * This driver fully supports this mode, allowing two distinct MIDI
  21 * busses to be used completely independently, giving 32 channels of
  22 * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI
  23 * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1,
  24 * where `n' is the card number. Note that the device numbers may be
  25 * something other than 0 and 1 if the CS4232 UART/MPU-401 interface
  26 * is enabled.
  27 *
  28 * Switching between the two is accomplished externally by the driver
  29 * using the two otherwise unused MIDI bytes. See the code for more details.
  30 *
  31 * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c)
  32 *
  33 * The main reason to turn off Virtual MIDI mode is when you want to
  34 * tightly couple the WaveFront synth with an external MIDI
  35 * device. You won't be able to distinguish the source of any MIDI
  36 * data except via SysEx ID, but thats probably OK, since for the most
  37 * part, the WaveFront won't be sending any MIDI data at all.
  38 *  
  39 * The main reason to turn on Virtual MIDI Mode is to provide two
  40 * completely independent 16-channel MIDI buses, one to the
  41 * WaveFront and one to any external MIDI devices. Given the 32
  42 * voice nature of the WaveFront, its pretty easy to find a use
  43 * for all 16 channels driving just that synth.
  44 *  
  45 */
  46
  47#include <linux/io.h>
  48#include <linux/init.h>
  49#include <linux/time.h>
  50#include <linux/wait.h>
  51#include <sound/core.h>
  52#include <sound/snd_wavefront.h>
  53
  54static inline int 
  55wf_mpu_status (snd_wavefront_midi_t *midi)
  56
  57{
  58        return inb (midi->mpu_status_port);
  59}
  60
  61static inline int 
  62input_avail (snd_wavefront_midi_t *midi)
  63
  64{
  65        return !(wf_mpu_status(midi) & INPUT_AVAIL);
  66}
  67
  68static inline int
  69output_ready (snd_wavefront_midi_t *midi)
  70
  71{
  72        return !(wf_mpu_status(midi) & OUTPUT_READY);
  73}
  74
  75static inline int 
  76read_data (snd_wavefront_midi_t *midi)
  77
  78{
  79        return inb (midi->mpu_data_port);
  80}
  81
  82static inline void 
  83write_data (snd_wavefront_midi_t *midi, unsigned char byte)
  84
  85{
  86        outb (byte, midi->mpu_data_port);
  87}
  88
  89static snd_wavefront_midi_t *
  90get_wavefront_midi (struct snd_rawmidi_substream *substream)
  91
  92{
  93        struct snd_card *card;
  94        snd_wavefront_card_t *acard;
  95
  96        if (substream == NULL || substream->rmidi == NULL) 
  97                return NULL;
  98
  99        card = substream->rmidi->card;
 100
 101        if (card == NULL) 
 102                return NULL;
 103
 104        if (card->private_data == NULL) 
 105                return NULL;
 106
 107        acard = card->private_data;
 108
 109        return &acard->wavefront.midi;
 110}
 111
 112static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
 113{
 114        snd_wavefront_midi_t *midi = &card->wavefront.midi;
 115        snd_wavefront_mpu_id  mpu;
 116        unsigned long flags;
 117        unsigned char midi_byte;
 118        int max = 256, mask = 1;
 119        int timeout;
 120
 121        /* Its not OK to try to change the status of "virtuality" of
 122           the MIDI interface while we're outputting stuff.  See
 123           snd_wavefront_midi_{enable,disable}_virtual () for the
 124           other half of this.  
 125
 126           The first loop attempts to flush any data from the
 127           current output device, and then the second 
 128           emits the switch byte (if necessary), and starts
 129           outputting data for the output device currently in use.
 130        */
 131
 132        if (midi->substream_output[midi->output_mpu] == NULL) {
 133                goto __second;
 134        }
 135
 136        while (max > 0) {
 137
 138                /* XXX fix me - no hard timing loops allowed! */
 139
 140                for (timeout = 30000; timeout > 0; timeout--) {
 141                        if (output_ready (midi))
 142                                break;
 143                }
 144        
 145                spin_lock_irqsave (&midi->virtual, flags);
 146                if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
 147                        spin_unlock_irqrestore (&midi->virtual, flags);
 148                        goto __second;
 149                }
 150                if (output_ready (midi)) {
 151                        if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
 152                                if (!midi->isvirtual ||
 153                                        (midi_byte != WF_INTERNAL_SWITCH &&
 154                                         midi_byte != WF_EXTERNAL_SWITCH))
 155                                        write_data(midi, midi_byte);
 156                                max--;
 157                        } else {
 158                                if (midi->istimer) {
 159                                        if (--midi->istimer <= 0)
 160                                                del_timer(&midi->timer);
 161                                }
 162                                midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
 163                                spin_unlock_irqrestore (&midi->virtual, flags);
 164                                goto __second;
 165                        }
 166                } else {
 167                        spin_unlock_irqrestore (&midi->virtual, flags);
 168                        return;
 169                }
 170                spin_unlock_irqrestore (&midi->virtual, flags);
 171        }
 172
 173      __second:
 174
 175        if (midi->substream_output[!midi->output_mpu] == NULL) {
 176                return;
 177        }
 178
 179        while (max > 0) {
 180
 181                /* XXX fix me - no hard timing loops allowed! */
 182
 183                for (timeout = 30000; timeout > 0; timeout--) {
 184                        if (output_ready (midi))
 185                                break;
 186                }
 187        
 188                spin_lock_irqsave (&midi->virtual, flags);
 189                if (!midi->isvirtual)
 190                        mask = 0;
 191                mpu = midi->output_mpu ^ mask;
 192                mask = 0;       /* don't invert the value from now */
 193                if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
 194                        spin_unlock_irqrestore (&midi->virtual, flags);
 195                        return;
 196                }
 197                if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
 198                        goto __timer;
 199                if (output_ready (midi)) {
 200                        if (mpu != midi->output_mpu) {
 201                                write_data(midi, mpu == internal_mpu ?
 202                                                        WF_INTERNAL_SWITCH :
 203                                                        WF_EXTERNAL_SWITCH);
 204                                midi->output_mpu = mpu;
 205                        } else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
 206                                if (!midi->isvirtual ||
 207                                        (midi_byte != WF_INTERNAL_SWITCH &&
 208                                         midi_byte != WF_EXTERNAL_SWITCH))
 209                                        write_data(midi, midi_byte);
 210                                max--;
 211                        } else {
 212                              __timer:
 213                                if (midi->istimer) {
 214                                        if (--midi->istimer <= 0)
 215                                                del_timer(&midi->timer);
 216                                }
 217                                midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
 218                                spin_unlock_irqrestore (&midi->virtual, flags);
 219                                return;
 220                        }
 221                } else {
 222                        spin_unlock_irqrestore (&midi->virtual, flags);
 223                        return;
 224                }
 225                spin_unlock_irqrestore (&midi->virtual, flags);
 226        }
 227}
 228
 229static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
 230{
 231        unsigned long flags;
 232        snd_wavefront_midi_t *midi;
 233        snd_wavefront_mpu_id mpu;
 234
 235        if (snd_BUG_ON(!substream || !substream->rmidi))
 236                return -ENXIO;
 237        if (snd_BUG_ON(!substream->rmidi->private_data))
 238                return -ENXIO;
 239
 240        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 241
 242        if ((midi = get_wavefront_midi (substream)) == NULL)
 243                return -EIO;
 244
 245        spin_lock_irqsave (&midi->open, flags);
 246        midi->mode[mpu] |= MPU401_MODE_INPUT;
 247        midi->substream_input[mpu] = substream;
 248        spin_unlock_irqrestore (&midi->open, flags);
 249
 250        return 0;
 251}
 252
 253static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
 254{
 255        unsigned long flags;
 256        snd_wavefront_midi_t *midi;
 257        snd_wavefront_mpu_id mpu;
 258
 259        if (snd_BUG_ON(!substream || !substream->rmidi))
 260                return -ENXIO;
 261        if (snd_BUG_ON(!substream->rmidi->private_data))
 262                return -ENXIO;
 263
 264        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 265
 266        if ((midi = get_wavefront_midi (substream)) == NULL)
 267                return -EIO;
 268
 269        spin_lock_irqsave (&midi->open, flags);
 270        midi->mode[mpu] |= MPU401_MODE_OUTPUT;
 271        midi->substream_output[mpu] = substream;
 272        spin_unlock_irqrestore (&midi->open, flags);
 273
 274        return 0;
 275}
 276
 277static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
 278{
 279        unsigned long flags;
 280        snd_wavefront_midi_t *midi;
 281        snd_wavefront_mpu_id mpu;
 282
 283        if (snd_BUG_ON(!substream || !substream->rmidi))
 284                return -ENXIO;
 285        if (snd_BUG_ON(!substream->rmidi->private_data))
 286                return -ENXIO;
 287
 288        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 289
 290        if ((midi = get_wavefront_midi (substream)) == NULL)
 291                return -EIO;
 292
 293        spin_lock_irqsave (&midi->open, flags);
 294        midi->mode[mpu] &= ~MPU401_MODE_INPUT;
 295        spin_unlock_irqrestore (&midi->open, flags);
 296
 297        return 0;
 298}
 299
 300static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
 301{
 302        unsigned long flags;
 303        snd_wavefront_midi_t *midi;
 304        snd_wavefront_mpu_id mpu;
 305
 306        if (snd_BUG_ON(!substream || !substream->rmidi))
 307                return -ENXIO;
 308        if (snd_BUG_ON(!substream->rmidi->private_data))
 309                return -ENXIO;
 310
 311        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 312
 313        if ((midi = get_wavefront_midi (substream)) == NULL)
 314                return -EIO;
 315
 316        spin_lock_irqsave (&midi->open, flags);
 317        midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
 318        spin_unlock_irqrestore (&midi->open, flags);
 319        return 0;
 320}
 321
 322static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 323{
 324        unsigned long flags;
 325        snd_wavefront_midi_t *midi;
 326        snd_wavefront_mpu_id mpu;
 327
 328        if (substream == NULL || substream->rmidi == NULL) 
 329                return;
 330
 331        if (substream->rmidi->private_data == NULL)
 332                return;
 333
 334        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 335
 336        if ((midi = get_wavefront_midi (substream)) == NULL) {
 337                return;
 338        }
 339
 340        spin_lock_irqsave (&midi->virtual, flags);
 341        if (up) {
 342                midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
 343        } else {
 344                midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
 345        }
 346        spin_unlock_irqrestore (&midi->virtual, flags);
 347}
 348
 349static void snd_wavefront_midi_output_timer(struct timer_list *t)
 350{
 351        snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
 352        snd_wavefront_card_t *card = midi->timer_card;
 353        unsigned long flags;
 354        
 355        spin_lock_irqsave (&midi->virtual, flags);
 356        mod_timer(&midi->timer, 1 + jiffies);
 357        spin_unlock_irqrestore (&midi->virtual, flags);
 358        snd_wavefront_midi_output_write(card);
 359}
 360
 361static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 362{
 363        unsigned long flags;
 364        snd_wavefront_midi_t *midi;
 365        snd_wavefront_mpu_id mpu;
 366
 367        if (substream == NULL || substream->rmidi == NULL) 
 368                return;
 369
 370        if (substream->rmidi->private_data == NULL)
 371                return;
 372
 373        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 374
 375        if ((midi = get_wavefront_midi (substream)) == NULL) {
 376                return;
 377        }
 378
 379        spin_lock_irqsave (&midi->virtual, flags);
 380        if (up) {
 381                if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
 382                        if (!midi->istimer) {
 383                                timer_setup(&midi->timer,
 384                                            snd_wavefront_midi_output_timer,
 385                                            0);
 386                                mod_timer(&midi->timer, 1 + jiffies);
 387                        }
 388                        midi->istimer++;
 389                        midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
 390                }
 391        } else {
 392                midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
 393        }
 394        spin_unlock_irqrestore (&midi->virtual, flags);
 395
 396        if (up)
 397                snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
 398}
 399
 400void
 401snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
 402
 403{
 404        unsigned long flags;
 405        snd_wavefront_midi_t *midi;
 406        static struct snd_rawmidi_substream *substream = NULL;
 407        static int mpu = external_mpu; 
 408        int max = 128;
 409        unsigned char byte;
 410
 411        midi = &card->wavefront.midi;
 412
 413        if (!input_avail (midi)) { /* not for us */
 414                snd_wavefront_midi_output_write(card);
 415                return;
 416        }
 417
 418        spin_lock_irqsave (&midi->virtual, flags);
 419        while (--max) {
 420
 421                if (input_avail (midi)) {
 422                        byte = read_data (midi);
 423
 424                        if (midi->isvirtual) {                          
 425                                if (byte == WF_EXTERNAL_SWITCH) {
 426                                        substream = midi->substream_input[external_mpu];
 427                                        mpu = external_mpu;
 428                                } else if (byte == WF_INTERNAL_SWITCH) { 
 429                                        substream = midi->substream_output[internal_mpu];
 430                                        mpu = internal_mpu;
 431                                } /* else just leave it as it is */
 432                        } else {
 433                                substream = midi->substream_input[internal_mpu];
 434                                mpu = internal_mpu;
 435                        }
 436
 437                        if (substream == NULL) {
 438                                continue;
 439                        }
 440
 441                        if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
 442                                snd_rawmidi_receive(substream, &byte, 1);
 443                        }
 444                } else {
 445                        break;
 446                }
 447        } 
 448        spin_unlock_irqrestore (&midi->virtual, flags);
 449
 450        snd_wavefront_midi_output_write(card);
 451}
 452
 453void
 454snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
 455
 456{
 457        unsigned long flags;
 458
 459        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 460        card->wavefront.midi.isvirtual = 1;
 461        card->wavefront.midi.output_mpu = internal_mpu;
 462        card->wavefront.midi.input_mpu = internal_mpu;
 463        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 464}
 465
 466void
 467snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
 468
 469{
 470        unsigned long flags;
 471
 472        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 473        // snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
 474        // snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
 475        card->wavefront.midi.isvirtual = 0;
 476        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 477}
 478
 479int
 480snd_wavefront_midi_start (snd_wavefront_card_t *card)
 481
 482{
 483        int ok, i;
 484        unsigned char rbuf[4], wbuf[4];
 485        snd_wavefront_t *dev;
 486        snd_wavefront_midi_t *midi;
 487
 488        dev = &card->wavefront;
 489        midi = &dev->midi;
 490
 491        /* The ICS2115 MPU-401 interface doesn't do anything
 492           until its set into UART mode.
 493        */
 494
 495        /* XXX fix me - no hard timing loops allowed! */
 496
 497        for (i = 0; i < 30000 && !output_ready (midi); i++);
 498
 499        if (!output_ready (midi)) {
 500                snd_printk ("MIDI interface not ready for command\n");
 501                return -1;
 502        }
 503
 504        /* Any interrupts received from now on
 505           are owned by the MIDI side of things.
 506        */
 507
 508        dev->interrupts_are_midi = 1;
 509        
 510        outb (UART_MODE_ON, midi->mpu_command_port);
 511
 512        for (ok = 0, i = 50000; i > 0 && !ok; i--) {
 513                if (input_avail (midi)) {
 514                        if (read_data (midi) == MPU_ACK) {
 515                                ok = 1;
 516                                break;
 517                        }
 518                }
 519        }
 520
 521        if (!ok) {
 522                snd_printk ("cannot set UART mode for MIDI interface");
 523                dev->interrupts_are_midi = 0;
 524                return -1;
 525        }
 526
 527        /* Route external MIDI to WaveFront synth (by default) */
 528    
 529        if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
 530                snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
 531                /* XXX error ? */
 532        }
 533
 534        /* Turn on Virtual MIDI, but first *always* turn it off,
 535           since otherwise consecutive reloads of the driver will
 536           never cause the hardware to generate the initial "internal" or 
 537           "external" source bytes in the MIDI data stream. This
 538           is pretty important, since the internal hardware generally will
 539           be used to generate none or very little MIDI output, and
 540           thus the only source of MIDI data is actually external. Without
 541           the switch bytes, the driver will think it all comes from
 542           the internal interface. Duh.
 543        */
 544
 545        if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
 546                snd_printk ("virtual MIDI mode not disabled\n");
 547                return 0; /* We're OK, but missing the external MIDI dev */
 548        }
 549
 550        snd_wavefront_midi_enable_virtual (card);
 551
 552        if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
 553                snd_printk ("cannot enable virtual MIDI mode.\n");
 554                snd_wavefront_midi_disable_virtual (card);
 555        } 
 556        return 0;
 557}
 558
 559const struct snd_rawmidi_ops snd_wavefront_midi_output =
 560{
 561        .open =         snd_wavefront_midi_output_open,
 562        .close =        snd_wavefront_midi_output_close,
 563        .trigger =      snd_wavefront_midi_output_trigger,
 564};
 565
 566const struct snd_rawmidi_ops snd_wavefront_midi_input =
 567{
 568        .open =         snd_wavefront_midi_input_open,
 569        .close =        snd_wavefront_midi_input_close,
 570        .trigger =      snd_wavefront_midi_input_trigger,
 571};
 572
 573