162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) by Paul Barton-Davis 1998-1999 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* The low level driver for the WaveFront ICS2115 MIDI interface(s) 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Note that there is also an MPU-401 emulation (actually, a UART-401 962306a36Sopenharmony_ci * emulation) on the CS4232 on the Tropez and Tropez Plus. This code 1062306a36Sopenharmony_ci * has nothing to do with that interface at all. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The interface is essentially just a UART-401, but is has the 1362306a36Sopenharmony_ci * interesting property of supporting what Turtle Beach called 1462306a36Sopenharmony_ci * "Virtual MIDI" mode. In this mode, there are effectively *two* 1562306a36Sopenharmony_ci * MIDI buses accessible via the interface, one that is routed 1662306a36Sopenharmony_ci * solely to/from the external WaveFront synthesizer and the other 1762306a36Sopenharmony_ci * corresponding to the pin/socket connector used to link external 1862306a36Sopenharmony_ci * MIDI devices to the board. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * This driver fully supports this mode, allowing two distinct MIDI 2162306a36Sopenharmony_ci * busses to be used completely independently, giving 32 channels of 2262306a36Sopenharmony_ci * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI 2362306a36Sopenharmony_ci * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1, 2462306a36Sopenharmony_ci * where `n' is the card number. Note that the device numbers may be 2562306a36Sopenharmony_ci * something other than 0 and 1 if the CS4232 UART/MPU-401 interface 2662306a36Sopenharmony_ci * is enabled. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Switching between the two is accomplished externally by the driver 2962306a36Sopenharmony_ci * using the two otherwise unused MIDI bytes. See the code for more details. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c) 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * The main reason to turn off Virtual MIDI mode is when you want to 3462306a36Sopenharmony_ci * tightly couple the WaveFront synth with an external MIDI 3562306a36Sopenharmony_ci * device. You won't be able to distinguish the source of any MIDI 3662306a36Sopenharmony_ci * data except via SysEx ID, but thats probably OK, since for the most 3762306a36Sopenharmony_ci * part, the WaveFront won't be sending any MIDI data at all. 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * The main reason to turn on Virtual MIDI Mode is to provide two 4062306a36Sopenharmony_ci * completely independent 16-channel MIDI buses, one to the 4162306a36Sopenharmony_ci * WaveFront and one to any external MIDI devices. Given the 32 4262306a36Sopenharmony_ci * voice nature of the WaveFront, its pretty easy to find a use 4362306a36Sopenharmony_ci * for all 16 channels driving just that synth. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <linux/io.h> 4862306a36Sopenharmony_ci#include <linux/init.h> 4962306a36Sopenharmony_ci#include <linux/time.h> 5062306a36Sopenharmony_ci#include <linux/wait.h> 5162306a36Sopenharmony_ci#include <sound/core.h> 5262306a36Sopenharmony_ci#include <sound/snd_wavefront.h> 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline int 5562306a36Sopenharmony_ciwf_mpu_status (snd_wavefront_midi_t *midi) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci return inb (midi->mpu_status_port); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic inline int 6262306a36Sopenharmony_ciinput_avail (snd_wavefront_midi_t *midi) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return !(wf_mpu_status(midi) & INPUT_AVAIL); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic inline int 6962306a36Sopenharmony_cioutput_ready (snd_wavefront_midi_t *midi) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return !(wf_mpu_status(midi) & OUTPUT_READY); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline int 7662306a36Sopenharmony_ciread_data (snd_wavefront_midi_t *midi) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return inb (midi->mpu_data_port); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline void 8362306a36Sopenharmony_ciwrite_data (snd_wavefront_midi_t *midi, unsigned char byte) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci outb (byte, midi->mpu_data_port); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic snd_wavefront_midi_t * 9062306a36Sopenharmony_ciget_wavefront_midi (struct snd_rawmidi_substream *substream) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct snd_card *card; 9462306a36Sopenharmony_ci snd_wavefront_card_t *acard; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (substream == NULL || substream->rmidi == NULL) 9762306a36Sopenharmony_ci return NULL; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci card = substream->rmidi->card; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (card == NULL) 10262306a36Sopenharmony_ci return NULL; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (card->private_data == NULL) 10562306a36Sopenharmony_ci return NULL; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci acard = card->private_data; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return &acard->wavefront.midi; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci snd_wavefront_midi_t *midi = &card->wavefront.midi; 11562306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 11662306a36Sopenharmony_ci unsigned long flags; 11762306a36Sopenharmony_ci unsigned char midi_byte; 11862306a36Sopenharmony_ci int max = 256, mask = 1; 11962306a36Sopenharmony_ci int timeout; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* Its not OK to try to change the status of "virtuality" of 12262306a36Sopenharmony_ci the MIDI interface while we're outputting stuff. See 12362306a36Sopenharmony_ci snd_wavefront_midi_{enable,disable}_virtual () for the 12462306a36Sopenharmony_ci other half of this. 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci The first loop attempts to flush any data from the 12762306a36Sopenharmony_ci current output device, and then the second 12862306a36Sopenharmony_ci emits the switch byte (if necessary), and starts 12962306a36Sopenharmony_ci outputting data for the output device currently in use. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (midi->substream_output[midi->output_mpu] == NULL) { 13362306a36Sopenharmony_ci goto __second; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci while (max > 0) { 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* XXX fix me - no hard timing loops allowed! */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci for (timeout = 30000; timeout > 0; timeout--) { 14162306a36Sopenharmony_ci if (output_ready (midi)) 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 14662306a36Sopenharmony_ci if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) { 14762306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 14862306a36Sopenharmony_ci goto __second; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci if (output_ready (midi)) { 15162306a36Sopenharmony_ci if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) { 15262306a36Sopenharmony_ci if (!midi->isvirtual || 15362306a36Sopenharmony_ci (midi_byte != WF_INTERNAL_SWITCH && 15462306a36Sopenharmony_ci midi_byte != WF_EXTERNAL_SWITCH)) 15562306a36Sopenharmony_ci write_data(midi, midi_byte); 15662306a36Sopenharmony_ci max--; 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci if (midi->istimer) { 15962306a36Sopenharmony_ci if (--midi->istimer <= 0) 16062306a36Sopenharmony_ci del_timer(&midi->timer); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 16362306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 16462306a36Sopenharmony_ci goto __second; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 16862306a36Sopenharmony_ci return; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci __second: 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (midi->substream_output[!midi->output_mpu] == NULL) { 17662306a36Sopenharmony_ci return; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci while (max > 0) { 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* XXX fix me - no hard timing loops allowed! */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci for (timeout = 30000; timeout > 0; timeout--) { 18462306a36Sopenharmony_ci if (output_ready (midi)) 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 18962306a36Sopenharmony_ci if (!midi->isvirtual) 19062306a36Sopenharmony_ci mask = 0; 19162306a36Sopenharmony_ci mpu = midi->output_mpu ^ mask; 19262306a36Sopenharmony_ci mask = 0; /* don't invert the value from now */ 19362306a36Sopenharmony_ci if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) { 19462306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci if (snd_rawmidi_transmit_empty(midi->substream_output[mpu])) 19862306a36Sopenharmony_ci goto __timer; 19962306a36Sopenharmony_ci if (output_ready (midi)) { 20062306a36Sopenharmony_ci if (mpu != midi->output_mpu) { 20162306a36Sopenharmony_ci write_data(midi, mpu == internal_mpu ? 20262306a36Sopenharmony_ci WF_INTERNAL_SWITCH : 20362306a36Sopenharmony_ci WF_EXTERNAL_SWITCH); 20462306a36Sopenharmony_ci midi->output_mpu = mpu; 20562306a36Sopenharmony_ci } else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) { 20662306a36Sopenharmony_ci if (!midi->isvirtual || 20762306a36Sopenharmony_ci (midi_byte != WF_INTERNAL_SWITCH && 20862306a36Sopenharmony_ci midi_byte != WF_EXTERNAL_SWITCH)) 20962306a36Sopenharmony_ci write_data(midi, midi_byte); 21062306a36Sopenharmony_ci max--; 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci __timer: 21362306a36Sopenharmony_ci if (midi->istimer) { 21462306a36Sopenharmony_ci if (--midi->istimer <= 0) 21562306a36Sopenharmony_ci del_timer(&midi->timer); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 21862306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci unsigned long flags; 23262306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 23362306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (snd_BUG_ON(!substream || !substream->rmidi)) 23662306a36Sopenharmony_ci return -ENXIO; 23762306a36Sopenharmony_ci if (snd_BUG_ON(!substream->rmidi->private_data)) 23862306a36Sopenharmony_ci return -ENXIO; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 24362306a36Sopenharmony_ci if (!midi) 24462306a36Sopenharmony_ci return -EIO; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci spin_lock_irqsave (&midi->open, flags); 24762306a36Sopenharmony_ci midi->mode[mpu] |= MPU401_MODE_INPUT; 24862306a36Sopenharmony_ci midi->substream_input[mpu] = substream; 24962306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->open, flags); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci unsigned long flags; 25762306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 25862306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (snd_BUG_ON(!substream || !substream->rmidi)) 26162306a36Sopenharmony_ci return -ENXIO; 26262306a36Sopenharmony_ci if (snd_BUG_ON(!substream->rmidi->private_data)) 26362306a36Sopenharmony_ci return -ENXIO; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 26862306a36Sopenharmony_ci if (!midi) 26962306a36Sopenharmony_ci return -EIO; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci spin_lock_irqsave (&midi->open, flags); 27262306a36Sopenharmony_ci midi->mode[mpu] |= MPU401_MODE_OUTPUT; 27362306a36Sopenharmony_ci midi->substream_output[mpu] = substream; 27462306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->open, flags); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci unsigned long flags; 28262306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 28362306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (snd_BUG_ON(!substream || !substream->rmidi)) 28662306a36Sopenharmony_ci return -ENXIO; 28762306a36Sopenharmony_ci if (snd_BUG_ON(!substream->rmidi->private_data)) 28862306a36Sopenharmony_ci return -ENXIO; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 29362306a36Sopenharmony_ci if (!midi) 29462306a36Sopenharmony_ci return -EIO; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci spin_lock_irqsave (&midi->open, flags); 29762306a36Sopenharmony_ci midi->mode[mpu] &= ~MPU401_MODE_INPUT; 29862306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->open, flags); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci unsigned long flags; 30662306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 30762306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (snd_BUG_ON(!substream || !substream->rmidi)) 31062306a36Sopenharmony_ci return -ENXIO; 31162306a36Sopenharmony_ci if (snd_BUG_ON(!substream->rmidi->private_data)) 31262306a36Sopenharmony_ci return -ENXIO; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 31762306a36Sopenharmony_ci if (!midi) 31862306a36Sopenharmony_ci return -EIO; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci spin_lock_irqsave (&midi->open, flags); 32162306a36Sopenharmony_ci midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; 32262306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->open, flags); 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci unsigned long flags; 32962306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 33062306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (substream == NULL || substream->rmidi == NULL) 33362306a36Sopenharmony_ci return; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (substream->rmidi->private_data == NULL) 33662306a36Sopenharmony_ci return; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 34162306a36Sopenharmony_ci if (!midi) 34262306a36Sopenharmony_ci return; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 34562306a36Sopenharmony_ci if (up) { 34662306a36Sopenharmony_ci midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER; 34762306a36Sopenharmony_ci } else { 34862306a36Sopenharmony_ci midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void snd_wavefront_midi_output_timer(struct timer_list *t) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci snd_wavefront_midi_t *midi = from_timer(midi, t, timer); 35662306a36Sopenharmony_ci snd_wavefront_card_t *card = midi->timer_card; 35762306a36Sopenharmony_ci unsigned long flags; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 36062306a36Sopenharmony_ci mod_timer(&midi->timer, 1 + jiffies); 36162306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 36262306a36Sopenharmony_ci snd_wavefront_midi_output_write(card); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci unsigned long flags; 36862306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 36962306a36Sopenharmony_ci snd_wavefront_mpu_id mpu; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (substream == NULL || substream->rmidi == NULL) 37262306a36Sopenharmony_ci return; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci if (substream->rmidi->private_data == NULL) 37562306a36Sopenharmony_ci return; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci midi = get_wavefront_midi(substream); 38062306a36Sopenharmony_ci if (!midi) 38162306a36Sopenharmony_ci return; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 38462306a36Sopenharmony_ci if (up) { 38562306a36Sopenharmony_ci if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { 38662306a36Sopenharmony_ci if (!midi->istimer) { 38762306a36Sopenharmony_ci timer_setup(&midi->timer, 38862306a36Sopenharmony_ci snd_wavefront_midi_output_timer, 38962306a36Sopenharmony_ci 0); 39062306a36Sopenharmony_ci mod_timer(&midi->timer, 1 + jiffies); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci midi->istimer++; 39362306a36Sopenharmony_ci midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci } else { 39662306a36Sopenharmony_ci midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (up) 40162306a36Sopenharmony_ci snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_civoid 40562306a36Sopenharmony_cisnd_wavefront_midi_interrupt (snd_wavefront_card_t *card) 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci unsigned long flags; 40962306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 41062306a36Sopenharmony_ci static struct snd_rawmidi_substream *substream = NULL; 41162306a36Sopenharmony_ci static int mpu = external_mpu; 41262306a36Sopenharmony_ci int max = 128; 41362306a36Sopenharmony_ci unsigned char byte; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci midi = &card->wavefront.midi; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (!input_avail (midi)) { /* not for us */ 41862306a36Sopenharmony_ci snd_wavefront_midi_output_write(card); 41962306a36Sopenharmony_ci return; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci spin_lock_irqsave (&midi->virtual, flags); 42362306a36Sopenharmony_ci while (--max) { 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (input_avail (midi)) { 42662306a36Sopenharmony_ci byte = read_data (midi); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (midi->isvirtual) { 42962306a36Sopenharmony_ci if (byte == WF_EXTERNAL_SWITCH) { 43062306a36Sopenharmony_ci substream = midi->substream_input[external_mpu]; 43162306a36Sopenharmony_ci mpu = external_mpu; 43262306a36Sopenharmony_ci } else if (byte == WF_INTERNAL_SWITCH) { 43362306a36Sopenharmony_ci substream = midi->substream_output[internal_mpu]; 43462306a36Sopenharmony_ci mpu = internal_mpu; 43562306a36Sopenharmony_ci } /* else just leave it as it is */ 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci substream = midi->substream_input[internal_mpu]; 43862306a36Sopenharmony_ci mpu = internal_mpu; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (substream == NULL) { 44262306a36Sopenharmony_ci continue; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { 44662306a36Sopenharmony_ci snd_rawmidi_receive(substream, &byte, 1); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci } else { 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci spin_unlock_irqrestore (&midi->virtual, flags); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci snd_wavefront_midi_output_write(card); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_civoid 45862306a36Sopenharmony_cisnd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card) 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci unsigned long flags; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci spin_lock_irqsave (&card->wavefront.midi.virtual, flags); 46462306a36Sopenharmony_ci card->wavefront.midi.isvirtual = 1; 46562306a36Sopenharmony_ci card->wavefront.midi.output_mpu = internal_mpu; 46662306a36Sopenharmony_ci card->wavefront.midi.input_mpu = internal_mpu; 46762306a36Sopenharmony_ci spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_civoid 47162306a36Sopenharmony_cisnd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci unsigned long flags; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci spin_lock_irqsave (&card->wavefront.midi.virtual, flags); 47762306a36Sopenharmony_ci // snd_wavefront_midi_input_close (card->ics2115_external_rmidi); 47862306a36Sopenharmony_ci // snd_wavefront_midi_output_close (card->ics2115_external_rmidi); 47962306a36Sopenharmony_ci card->wavefront.midi.isvirtual = 0; 48062306a36Sopenharmony_ci spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ciint 48462306a36Sopenharmony_cisnd_wavefront_midi_start (snd_wavefront_card_t *card) 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int ok, i; 48862306a36Sopenharmony_ci unsigned char rbuf[4], wbuf[4]; 48962306a36Sopenharmony_ci snd_wavefront_t *dev; 49062306a36Sopenharmony_ci snd_wavefront_midi_t *midi; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci dev = &card->wavefront; 49362306a36Sopenharmony_ci midi = &dev->midi; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* The ICS2115 MPU-401 interface doesn't do anything 49662306a36Sopenharmony_ci until its set into UART mode. 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* XXX fix me - no hard timing loops allowed! */ 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci for (i = 0; i < 30000 && !output_ready (midi); i++); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!output_ready (midi)) { 50462306a36Sopenharmony_ci snd_printk ("MIDI interface not ready for command\n"); 50562306a36Sopenharmony_ci return -1; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* Any interrupts received from now on 50962306a36Sopenharmony_ci are owned by the MIDI side of things. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci dev->interrupts_are_midi = 1; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci outb (UART_MODE_ON, midi->mpu_command_port); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (ok = 0, i = 50000; i > 0 && !ok; i--) { 51762306a36Sopenharmony_ci if (input_avail (midi)) { 51862306a36Sopenharmony_ci if (read_data (midi) == MPU_ACK) { 51962306a36Sopenharmony_ci ok = 1; 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!ok) { 52662306a36Sopenharmony_ci snd_printk ("cannot set UART mode for MIDI interface"); 52762306a36Sopenharmony_ci dev->interrupts_are_midi = 0; 52862306a36Sopenharmony_ci return -1; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* Route external MIDI to WaveFront synth (by default) */ 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) { 53462306a36Sopenharmony_ci snd_printk ("can't enable MIDI-IN-2-synth routing.\n"); 53562306a36Sopenharmony_ci /* XXX error ? */ 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Turn on Virtual MIDI, but first *always* turn it off, 53962306a36Sopenharmony_ci since otherwise consecutive reloads of the driver will 54062306a36Sopenharmony_ci never cause the hardware to generate the initial "internal" or 54162306a36Sopenharmony_ci "external" source bytes in the MIDI data stream. This 54262306a36Sopenharmony_ci is pretty important, since the internal hardware generally will 54362306a36Sopenharmony_ci be used to generate none or very little MIDI output, and 54462306a36Sopenharmony_ci thus the only source of MIDI data is actually external. Without 54562306a36Sopenharmony_ci the switch bytes, the driver will think it all comes from 54662306a36Sopenharmony_ci the internal interface. Duh. 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 55062306a36Sopenharmony_ci snd_printk ("virtual MIDI mode not disabled\n"); 55162306a36Sopenharmony_ci return 0; /* We're OK, but missing the external MIDI dev */ 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci snd_wavefront_midi_enable_virtual (card); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) { 55762306a36Sopenharmony_ci snd_printk ("cannot enable virtual MIDI mode.\n"); 55862306a36Sopenharmony_ci snd_wavefront_midi_disable_virtual (card); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ciconst struct snd_rawmidi_ops snd_wavefront_midi_output = 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci .open = snd_wavefront_midi_output_open, 56662306a36Sopenharmony_ci .close = snd_wavefront_midi_output_close, 56762306a36Sopenharmony_ci .trigger = snd_wavefront_midi_output_trigger, 56862306a36Sopenharmony_ci}; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ciconst struct snd_rawmidi_ops snd_wavefront_midi_input = 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci .open = snd_wavefront_midi_input_open, 57362306a36Sopenharmony_ci .close = snd_wavefront_midi_input_close, 57462306a36Sopenharmony_ci .trigger = snd_wavefront_midi_input_trigger, 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_ci 577