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        midi = get_wavefront_midi(substream);
 243        if (!midi)
 244                return -EIO;
 245
 246        spin_lock_irqsave (&midi->open, flags);
 247        midi->mode[mpu] |= MPU401_MODE_INPUT;
 248        midi->substream_input[mpu] = substream;
 249        spin_unlock_irqrestore (&midi->open, flags);
 250
 251        return 0;
 252}
 253
 254static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
 255{
 256        unsigned long flags;
 257        snd_wavefront_midi_t *midi;
 258        snd_wavefront_mpu_id mpu;
 259
 260        if (snd_BUG_ON(!substream || !substream->rmidi))
 261                return -ENXIO;
 262        if (snd_BUG_ON(!substream->rmidi->private_data))
 263                return -ENXIO;
 264
 265        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 266
 267        midi = get_wavefront_midi(substream);
 268        if (!midi)
 269                return -EIO;
 270
 271        spin_lock_irqsave (&midi->open, flags);
 272        midi->mode[mpu] |= MPU401_MODE_OUTPUT;
 273        midi->substream_output[mpu] = substream;
 274        spin_unlock_irqrestore (&midi->open, flags);
 275
 276        return 0;
 277}
 278
 279static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
 280{
 281        unsigned long flags;
 282        snd_wavefront_midi_t *midi;
 283        snd_wavefront_mpu_id mpu;
 284
 285        if (snd_BUG_ON(!substream || !substream->rmidi))
 286                return -ENXIO;
 287        if (snd_BUG_ON(!substream->rmidi->private_data))
 288                return -ENXIO;
 289
 290        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 291
 292        midi = get_wavefront_midi(substream);
 293        if (!midi)
 294                return -EIO;
 295
 296        spin_lock_irqsave (&midi->open, flags);
 297        midi->mode[mpu] &= ~MPU401_MODE_INPUT;
 298        spin_unlock_irqrestore (&midi->open, flags);
 299
 300        return 0;
 301}
 302
 303static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
 304{
 305        unsigned long flags;
 306        snd_wavefront_midi_t *midi;
 307        snd_wavefront_mpu_id mpu;
 308
 309        if (snd_BUG_ON(!substream || !substream->rmidi))
 310                return -ENXIO;
 311        if (snd_BUG_ON(!substream->rmidi->private_data))
 312                return -ENXIO;
 313
 314        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 315
 316        midi = get_wavefront_midi(substream);
 317        if (!midi)
 318                return -EIO;
 319
 320        spin_lock_irqsave (&midi->open, flags);
 321        midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
 322        spin_unlock_irqrestore (&midi->open, flags);
 323        return 0;
 324}
 325
 326static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
 327{
 328        unsigned long flags;
 329        snd_wavefront_midi_t *midi;
 330        snd_wavefront_mpu_id mpu;
 331
 332        if (substream == NULL || substream->rmidi == NULL) 
 333                return;
 334
 335        if (substream->rmidi->private_data == NULL)
 336                return;
 337
 338        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 339
 340        midi = get_wavefront_midi(substream);
 341        if (!midi)
 342                return;
 343
 344        spin_lock_irqsave (&midi->virtual, flags);
 345        if (up) {
 346                midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
 347        } else {
 348                midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
 349        }
 350        spin_unlock_irqrestore (&midi->virtual, flags);
 351}
 352
 353static void snd_wavefront_midi_output_timer(struct timer_list *t)
 354{
 355        snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
 356        snd_wavefront_card_t *card = midi->timer_card;
 357        unsigned long flags;
 358        
 359        spin_lock_irqsave (&midi->virtual, flags);
 360        mod_timer(&midi->timer, 1 + jiffies);
 361        spin_unlock_irqrestore (&midi->virtual, flags);
 362        snd_wavefront_midi_output_write(card);
 363}
 364
 365static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
 366{
 367        unsigned long flags;
 368        snd_wavefront_midi_t *midi;
 369        snd_wavefront_mpu_id mpu;
 370
 371        if (substream == NULL || substream->rmidi == NULL) 
 372                return;
 373
 374        if (substream->rmidi->private_data == NULL)
 375                return;
 376
 377        mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
 378
 379        midi = get_wavefront_midi(substream);
 380        if (!midi)
 381                return;
 382
 383        spin_lock_irqsave (&midi->virtual, flags);
 384        if (up) {
 385                if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
 386                        if (!midi->istimer) {
 387                                timer_setup(&midi->timer,
 388                                            snd_wavefront_midi_output_timer,
 389                                            0);
 390                                mod_timer(&midi->timer, 1 + jiffies);
 391                        }
 392                        midi->istimer++;
 393                        midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
 394                }
 395        } else {
 396                midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
 397        }
 398        spin_unlock_irqrestore (&midi->virtual, flags);
 399
 400        if (up)
 401                snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
 402}
 403
 404void
 405snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
 406
 407{
 408        unsigned long flags;
 409        snd_wavefront_midi_t *midi;
 410        static struct snd_rawmidi_substream *substream = NULL;
 411        static int mpu = external_mpu; 
 412        int max = 128;
 413        unsigned char byte;
 414
 415        midi = &card->wavefront.midi;
 416
 417        if (!input_avail (midi)) { /* not for us */
 418                snd_wavefront_midi_output_write(card);
 419                return;
 420        }
 421
 422        spin_lock_irqsave (&midi->virtual, flags);
 423        while (--max) {
 424
 425                if (input_avail (midi)) {
 426                        byte = read_data (midi);
 427
 428                        if (midi->isvirtual) {                          
 429                                if (byte == WF_EXTERNAL_SWITCH) {
 430                                        substream = midi->substream_input[external_mpu];
 431                                        mpu = external_mpu;
 432                                } else if (byte == WF_INTERNAL_SWITCH) { 
 433                                        substream = midi->substream_output[internal_mpu];
 434                                        mpu = internal_mpu;
 435                                } /* else just leave it as it is */
 436                        } else {
 437                                substream = midi->substream_input[internal_mpu];
 438                                mpu = internal_mpu;
 439                        }
 440
 441                        if (substream == NULL) {
 442                                continue;
 443                        }
 444
 445                        if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
 446                                snd_rawmidi_receive(substream, &byte, 1);
 447                        }
 448                } else {
 449                        break;
 450                }
 451        } 
 452        spin_unlock_irqrestore (&midi->virtual, flags);
 453
 454        snd_wavefront_midi_output_write(card);
 455}
 456
 457void
 458snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
 459
 460{
 461        unsigned long flags;
 462
 463        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 464        card->wavefront.midi.isvirtual = 1;
 465        card->wavefront.midi.output_mpu = internal_mpu;
 466        card->wavefront.midi.input_mpu = internal_mpu;
 467        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 468}
 469
 470void
 471snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
 472
 473{
 474        unsigned long flags;
 475
 476        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 477        // snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
 478        // snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
 479        card->wavefront.midi.isvirtual = 0;
 480        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 481}
 482
 483int
 484snd_wavefront_midi_start (snd_wavefront_card_t *card)
 485
 486{
 487        int ok, i;
 488        unsigned char rbuf[4], wbuf[4];
 489        snd_wavefront_t *dev;
 490        snd_wavefront_midi_t *midi;
 491
 492        dev = &card->wavefront;
 493        midi = &dev->midi;
 494
 495        /* The ICS2115 MPU-401 interface doesn't do anything
 496           until its set into UART mode.
 497        */
 498
 499        /* XXX fix me - no hard timing loops allowed! */
 500
 501        for (i = 0; i < 30000 && !output_ready (midi); i++);
 502
 503        if (!output_ready (midi)) {
 504                snd_printk ("MIDI interface not ready for command\n");
 505                return -1;
 506        }
 507
 508        /* Any interrupts received from now on
 509           are owned by the MIDI side of things.
 510        */
 511
 512        dev->interrupts_are_midi = 1;
 513        
 514        outb (UART_MODE_ON, midi->mpu_command_port);
 515
 516        for (ok = 0, i = 50000; i > 0 && !ok; i--) {
 517                if (input_avail (midi)) {
 518                        if (read_data (midi) == MPU_ACK) {
 519                                ok = 1;
 520                                break;
 521                        }
 522                }
 523        }
 524
 525        if (!ok) {
 526                snd_printk ("cannot set UART mode for MIDI interface");
 527                dev->interrupts_are_midi = 0;
 528                return -1;
 529        }
 530
 531        /* Route external MIDI to WaveFront synth (by default) */
 532    
 533        if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
 534                snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
 535                /* XXX error ? */
 536        }
 537
 538        /* Turn on Virtual MIDI, but first *always* turn it off,
 539           since otherwise consecutive reloads of the driver will
 540           never cause the hardware to generate the initial "internal" or 
 541           "external" source bytes in the MIDI data stream. This
 542           is pretty important, since the internal hardware generally will
 543           be used to generate none or very little MIDI output, and
 544           thus the only source of MIDI data is actually external. Without
 545           the switch bytes, the driver will think it all comes from
 546           the internal interface. Duh.
 547        */
 548
 549        if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
 550                snd_printk ("virtual MIDI mode not disabled\n");
 551                return 0; /* We're OK, but missing the external MIDI dev */
 552        }
 553
 554        snd_wavefront_midi_enable_virtual (card);
 555
 556        if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
 557                snd_printk ("cannot enable virtual MIDI mode.\n");
 558                snd_wavefront_midi_disable_virtual (card);
 559        } 
 560        return 0;
 561}
 562
 563const struct snd_rawmidi_ops snd_wavefront_midi_output =
 564{
 565        .open =         snd_wavefront_midi_output_open,
 566        .close =        snd_wavefront_midi_output_close,
 567        .trigger =      snd_wavefront_midi_output_trigger,
 568};
 569
 570const struct snd_rawmidi_ops snd_wavefront_midi_input =
 571{
 572        .open =         snd_wavefront_midi_input_open,
 573        .close =        snd_wavefront_midi_input_close,
 574        .trigger =      snd_wavefront_midi_input_trigger,
 575};
 576
 577