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