root/sound/isa/wavefront/wavefront_midi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wf_mpu_status
  2. input_avail
  3. output_ready
  4. read_data
  5. write_data
  6. get_wavefront_midi
  7. snd_wavefront_midi_output_write
  8. snd_wavefront_midi_input_open
  9. snd_wavefront_midi_output_open
  10. snd_wavefront_midi_input_close
  11. snd_wavefront_midi_output_close
  12. snd_wavefront_midi_input_trigger
  13. snd_wavefront_midi_output_timer
  14. snd_wavefront_midi_output_trigger
  15. snd_wavefront_midi_interrupt
  16. snd_wavefront_midi_enable_virtual
  17. snd_wavefront_midi_disable_virtual
  18. snd_wavefront_midi_start

   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 
  54 static inline int 
  55 wf_mpu_status (snd_wavefront_midi_t *midi)
  56 
  57 {
  58         return inb (midi->mpu_status_port);
  59 }
  60 
  61 static inline int 
  62 input_avail (snd_wavefront_midi_t *midi)
  63 
  64 {
  65         return !(wf_mpu_status(midi) & INPUT_AVAIL);
  66 }
  67 
  68 static inline int
  69 output_ready (snd_wavefront_midi_t *midi)
  70 
  71 {
  72         return !(wf_mpu_status(midi) & OUTPUT_READY);
  73 }
  74 
  75 static inline int 
  76 read_data (snd_wavefront_midi_t *midi)
  77 
  78 {
  79         return inb (midi->mpu_data_port);
  80 }
  81 
  82 static inline void 
  83 write_data (snd_wavefront_midi_t *midi, unsigned char byte)
  84 
  85 {
  86         outb (byte, midi->mpu_data_port);
  87 }
  88 
  89 static snd_wavefront_midi_t *
  90 get_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 
 112 static 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 
 229 static 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 
 253 static 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 
 277 static 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 
 300 static 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 
 322 static 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 
 349 static 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 
 361 static 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 
 400 void
 401 snd_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 
 453 void
 454 snd_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 
 466 void
 467 snd_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 
 479 int
 480 snd_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 
 559 const 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 
 566 const 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 

/* [<][>][^][v][top][bottom][index][help] */