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 <asm/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        midi->timer.expires = 1 + jiffies;
 360        add_timer(&midi->timer);
 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        if ((midi = get_wavefront_midi (substream)) == NULL) {
 380                return;
 381        }
 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                                init_timer(&midi->timer);
 388                                midi->timer.function = snd_wavefront_midi_output_timer;
 389                                midi->timer.data = (unsigned long) substream->rmidi->card->private_data;
 390                                midi->timer.expires = 1 + jiffies;
 391                                add_timer(&midi->timer);
 392                        }
 393                        midi->istimer++;
 394                        midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
 395                }
 396        } else {
 397                midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
 398        }
 399        spin_unlock_irqrestore (&midi->virtual, flags);
 400
 401        if (up)
 402                snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
 403}
 404
 405void
 406snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
 407
 408{
 409        unsigned long flags;
 410        snd_wavefront_midi_t *midi;
 411        static struct snd_rawmidi_substream *substream = NULL;
 412        static int mpu = external_mpu; 
 413        int max = 128;
 414        unsigned char byte;
 415
 416        midi = &card->wavefront.midi;
 417
 418        if (!input_avail (midi)) { /* not for us */
 419                snd_wavefront_midi_output_write(card);
 420                return;
 421        }
 422
 423        spin_lock_irqsave (&midi->virtual, flags);
 424        while (--max) {
 425
 426                if (input_avail (midi)) {
 427                        byte = read_data (midi);
 428
 429                        if (midi->isvirtual) {                          
 430                                if (byte == WF_EXTERNAL_SWITCH) {
 431                                        substream = midi->substream_input[external_mpu];
 432                                        mpu = external_mpu;
 433                                } else if (byte == WF_INTERNAL_SWITCH) { 
 434                                        substream = midi->substream_output[internal_mpu];
 435                                        mpu = internal_mpu;
 436                                } /* else just leave it as it is */
 437                        } else {
 438                                substream = midi->substream_input[internal_mpu];
 439                                mpu = internal_mpu;
 440                        }
 441
 442                        if (substream == NULL) {
 443                                continue;
 444                        }
 445
 446                        if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
 447                                snd_rawmidi_receive(substream, &byte, 1);
 448                        }
 449                } else {
 450                        break;
 451                }
 452        } 
 453        spin_unlock_irqrestore (&midi->virtual, flags);
 454
 455        snd_wavefront_midi_output_write(card);
 456}
 457
 458void
 459snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
 460
 461{
 462        unsigned long flags;
 463
 464        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 465        card->wavefront.midi.isvirtual = 1;
 466        card->wavefront.midi.output_mpu = internal_mpu;
 467        card->wavefront.midi.input_mpu = internal_mpu;
 468        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 469}
 470
 471void
 472snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
 473
 474{
 475        unsigned long flags;
 476
 477        spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
 478        // snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
 479        // snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
 480        card->wavefront.midi.isvirtual = 0;
 481        spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
 482}
 483
 484int __devinit
 485snd_wavefront_midi_start (snd_wavefront_card_t *card)
 486
 487{
 488        int ok, i;
 489        unsigned char rbuf[4], wbuf[4];
 490        snd_wavefront_t *dev;
 491        snd_wavefront_midi_t *midi;
 492
 493        dev = &card->wavefront;
 494        midi = &dev->midi;
 495
 496        /* The ICS2115 MPU-401 interface doesn't do anything
 497           until its set into UART mode.
 498        */
 499
 500        /* XXX fix me - no hard timing loops allowed! */
 501
 502        for (i = 0; i < 30000 && !output_ready (midi); i++);
 503
 504        if (!output_ready (midi)) {
 505                snd_printk ("MIDI interface not ready for command\n");
 506                return -1;
 507        }
 508
 509        /* Any interrupts received from now on
 510           are owned by the MIDI side of things.
 511        */
 512
 513        dev->interrupts_are_midi = 1;
 514        
 515        outb (UART_MODE_ON, midi->mpu_command_port);
 516
 517        for (ok = 0, i = 50000; i > 0 && !ok; i--) {
 518                if (input_avail (midi)) {
 519                        if (read_data (midi) == MPU_ACK) {
 520                                ok = 1;
 521                                break;
 522                        }
 523                }
 524        }
 525
 526        if (!ok) {
 527                snd_printk ("cannot set UART mode for MIDI interface");
 528                dev->interrupts_are_midi = 0;
 529                return -1;
 530        }
 531
 532        /* Route external MIDI to WaveFront synth (by default) */
 533    
 534        if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
 535                snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
 536                /* XXX error ? */
 537        }
 538
 539        /* Turn on Virtual MIDI, but first *always* turn it off,
 540           since otherwise consectutive reloads of the driver will
 541           never cause the hardware to generate the initial "internal" or 
 542           "external" source bytes in the MIDI data stream. This
 543           is pretty important, since the internal hardware generally will
 544           be used to generate none or very little MIDI output, and
 545           thus the only source of MIDI data is actually external. Without
 546           the switch bytes, the driver will think it all comes from
 547           the internal interface. Duh.
 548        */
 549
 550        if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
 551                snd_printk ("virtual MIDI mode not disabled\n");
 552                return 0; /* We're OK, but missing the external MIDI dev */
 553        }
 554
 555        snd_wavefront_midi_enable_virtual (card);
 556
 557        if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
 558                snd_printk ("cannot enable virtual MIDI mode.\n");
 559                snd_wavefront_midi_disable_virtual (card);
 560        } 
 561        return 0;
 562}
 563
 564struct snd_rawmidi_ops snd_wavefront_midi_output =
 565{
 566        .open =         snd_wavefront_midi_output_open,
 567        .close =        snd_wavefront_midi_output_close,
 568        .trigger =      snd_wavefront_midi_output_trigger,
 569};
 570
 571struct snd_rawmidi_ops snd_wavefront_midi_input =
 572{
 573        .open =         snd_wavefront_midi_input_open,
 574        .close =        snd_wavefront_midi_input_close,
 575        .trigger =      snd_wavefront_midi_input_trigger,
 576};
 577
 578