xref: /linux/sound/isa/wavefront/wavefront_midi.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1b8f9f700SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Copyright (C) by Paul Barton-Davis 1998-1999
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds /* The low level driver for the WaveFront ICS2115 MIDI interface(s)
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Note that there is also an MPU-401 emulation (actually, a UART-401
91da177e4SLinus Torvalds  * emulation) on the CS4232 on the Tropez and Tropez Plus. This code
101da177e4SLinus Torvalds  * has nothing to do with that interface at all.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * The interface is essentially just a UART-401, but is has the
131da177e4SLinus Torvalds  * interesting property of supporting what Turtle Beach called
141da177e4SLinus Torvalds  * "Virtual MIDI" mode. In this mode, there are effectively *two*
151da177e4SLinus Torvalds  * MIDI buses accessible via the interface, one that is routed
161da177e4SLinus Torvalds  * solely to/from the external WaveFront synthesizer and the other
171da177e4SLinus Torvalds  * corresponding to the pin/socket connector used to link external
181da177e4SLinus Torvalds  * MIDI devices to the board.
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  * This driver fully supports this mode, allowing two distinct MIDI
211da177e4SLinus Torvalds  * busses to be used completely independently, giving 32 channels of
221da177e4SLinus Torvalds  * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI
231da177e4SLinus Torvalds  * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1,
241da177e4SLinus Torvalds  * where `n' is the card number. Note that the device numbers may be
251da177e4SLinus Torvalds  * something other than 0 and 1 if the CS4232 UART/MPU-401 interface
261da177e4SLinus Torvalds  * is enabled.
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  * Switching between the two is accomplished externally by the driver
291da177e4SLinus Torvalds  * using the two otherwise unused MIDI bytes. See the code for more details.
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c)
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * The main reason to turn off Virtual MIDI mode is when you want to
341da177e4SLinus Torvalds  * tightly couple the WaveFront synth with an external MIDI
351da177e4SLinus Torvalds  * device. You won't be able to distinguish the source of any MIDI
361da177e4SLinus Torvalds  * data except via SysEx ID, but thats probably OK, since for the most
371da177e4SLinus Torvalds  * part, the WaveFront won't be sending any MIDI data at all.
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  * The main reason to turn on Virtual MIDI Mode is to provide two
401da177e4SLinus Torvalds  * completely independent 16-channel MIDI buses, one to the
411da177e4SLinus Torvalds  * WaveFront and one to any external MIDI devices. Given the 32
421da177e4SLinus Torvalds  * voice nature of the WaveFront, its pretty easy to find a use
431da177e4SLinus Torvalds  * for all 16 channels driving just that synth.
441da177e4SLinus Torvalds  *
451da177e4SLinus Torvalds  */
461da177e4SLinus Torvalds 
476cbbfe1cSTakashi Iwai #include <linux/io.h>
481da177e4SLinus Torvalds #include <linux/init.h>
491da177e4SLinus Torvalds #include <linux/time.h>
501da177e4SLinus Torvalds #include <linux/wait.h>
511da177e4SLinus Torvalds #include <sound/core.h>
521da177e4SLinus Torvalds #include <sound/snd_wavefront.h>
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds static inline int
wf_mpu_status(snd_wavefront_midi_t * midi)551da177e4SLinus Torvalds wf_mpu_status (snd_wavefront_midi_t *midi)
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	return inb (midi->mpu_status_port);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds static inline int
input_avail(snd_wavefront_midi_t * midi)621da177e4SLinus Torvalds input_avail (snd_wavefront_midi_t *midi)
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	return !(wf_mpu_status(midi) & INPUT_AVAIL);
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds static inline int
output_ready(snd_wavefront_midi_t * midi)691da177e4SLinus Torvalds output_ready (snd_wavefront_midi_t *midi)
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds 	return !(wf_mpu_status(midi) & OUTPUT_READY);
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds static inline int
read_data(snd_wavefront_midi_t * midi)761da177e4SLinus Torvalds read_data (snd_wavefront_midi_t *midi)
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds 	return inb (midi->mpu_data_port);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds static inline void
write_data(snd_wavefront_midi_t * midi,unsigned char byte)831da177e4SLinus Torvalds write_data (snd_wavefront_midi_t *midi, unsigned char byte)
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	outb (byte, midi->mpu_data_port);
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds static snd_wavefront_midi_t *
get_wavefront_midi(struct snd_rawmidi_substream * substream)90542172f3STakashi Iwai get_wavefront_midi (struct snd_rawmidi_substream *substream)
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds {
93542172f3STakashi Iwai 	struct snd_card *card;
941da177e4SLinus Torvalds 	snd_wavefront_card_t *acard;
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 	if (substream == NULL || substream->rmidi == NULL)
971da177e4SLinus Torvalds 	        return NULL;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	card = substream->rmidi->card;
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 	if (card == NULL)
1021da177e4SLinus Torvalds 	        return NULL;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	if (card->private_data == NULL)
1051da177e4SLinus Torvalds  	        return NULL;
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds 	acard = card->private_data;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	return &acard->wavefront.midi;
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds 
snd_wavefront_midi_output_write(snd_wavefront_card_t * card)1121da177e4SLinus Torvalds static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi = &card->wavefront.midi;
1151da177e4SLinus Torvalds 	snd_wavefront_mpu_id  mpu;
1161da177e4SLinus Torvalds 	unsigned long flags;
1171da177e4SLinus Torvalds 	unsigned char midi_byte;
1181da177e4SLinus Torvalds 	int max = 256, mask = 1;
1191da177e4SLinus Torvalds 	int timeout;
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 	/* Its not OK to try to change the status of "virtuality" of
1221da177e4SLinus Torvalds 	   the MIDI interface while we're outputting stuff.  See
1231da177e4SLinus Torvalds 	   snd_wavefront_midi_{enable,disable}_virtual () for the
1241da177e4SLinus Torvalds 	   other half of this.
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds 	   The first loop attempts to flush any data from the
1271da177e4SLinus Torvalds 	   current output device, and then the second
1281da177e4SLinus Torvalds 	   emits the switch byte (if necessary), and starts
1291da177e4SLinus Torvalds 	   outputting data for the output device currently in use.
1301da177e4SLinus Torvalds 	*/
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	if (midi->substream_output[midi->output_mpu] == NULL) {
1331da177e4SLinus Torvalds 		goto __second;
1341da177e4SLinus Torvalds 	}
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	while (max > 0) {
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 		/* XXX fix me - no hard timing loops allowed! */
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 		for (timeout = 30000; timeout > 0; timeout--) {
1411da177e4SLinus Torvalds 			if (output_ready (midi))
1421da177e4SLinus Torvalds 				break;
1431da177e4SLinus Torvalds 		}
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 		spin_lock_irqsave (&midi->virtual, flags);
1461da177e4SLinus Torvalds 		if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
1471da177e4SLinus Torvalds 			spin_unlock_irqrestore (&midi->virtual, flags);
1481da177e4SLinus Torvalds 			goto __second;
1491da177e4SLinus Torvalds 		}
1501da177e4SLinus Torvalds 		if (output_ready (midi)) {
1511da177e4SLinus Torvalds 			if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
1521da177e4SLinus Torvalds 				if (!midi->isvirtual ||
1531da177e4SLinus Torvalds 					(midi_byte != WF_INTERNAL_SWITCH &&
1541da177e4SLinus Torvalds 					 midi_byte != WF_EXTERNAL_SWITCH))
1551da177e4SLinus Torvalds 					write_data(midi, midi_byte);
1561da177e4SLinus Torvalds 				max--;
1571da177e4SLinus Torvalds 			} else {
1581da177e4SLinus Torvalds 				if (midi->istimer) {
1591da177e4SLinus Torvalds 					if (--midi->istimer <= 0)
1601da177e4SLinus Torvalds 						del_timer(&midi->timer);
1611da177e4SLinus Torvalds 				}
1621da177e4SLinus Torvalds 				midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
1631da177e4SLinus Torvalds 				spin_unlock_irqrestore (&midi->virtual, flags);
1641da177e4SLinus Torvalds 				goto __second;
1651da177e4SLinus Torvalds 			}
1661da177e4SLinus Torvalds 		} else {
1671da177e4SLinus Torvalds 			spin_unlock_irqrestore (&midi->virtual, flags);
1681da177e4SLinus Torvalds 			return;
1691da177e4SLinus Torvalds 		}
1701da177e4SLinus Torvalds 		spin_unlock_irqrestore (&midi->virtual, flags);
1711da177e4SLinus Torvalds 	}
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds       __second:
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	if (midi->substream_output[!midi->output_mpu] == NULL) {
1761da177e4SLinus Torvalds 		return;
1771da177e4SLinus Torvalds 	}
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	while (max > 0) {
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 		/* XXX fix me - no hard timing loops allowed! */
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 		for (timeout = 30000; timeout > 0; timeout--) {
1841da177e4SLinus Torvalds 			if (output_ready (midi))
1851da177e4SLinus Torvalds 				break;
1861da177e4SLinus Torvalds 		}
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 		spin_lock_irqsave (&midi->virtual, flags);
1891da177e4SLinus Torvalds 		if (!midi->isvirtual)
1901da177e4SLinus Torvalds 			mask = 0;
1911da177e4SLinus Torvalds 		mpu = midi->output_mpu ^ mask;
1921da177e4SLinus Torvalds 		mask = 0;	/* don't invert the value from now */
1931da177e4SLinus Torvalds 		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
1941da177e4SLinus Torvalds 			spin_unlock_irqrestore (&midi->virtual, flags);
1951da177e4SLinus Torvalds 			return;
1961da177e4SLinus Torvalds 		}
1971da177e4SLinus Torvalds 		if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
1981da177e4SLinus Torvalds 			goto __timer;
1991da177e4SLinus Torvalds 		if (output_ready (midi)) {
2001da177e4SLinus Torvalds 			if (mpu != midi->output_mpu) {
2011da177e4SLinus Torvalds 				write_data(midi, mpu == internal_mpu ?
2021da177e4SLinus Torvalds 							WF_INTERNAL_SWITCH :
2031da177e4SLinus Torvalds 							WF_EXTERNAL_SWITCH);
2041da177e4SLinus Torvalds 				midi->output_mpu = mpu;
2051da177e4SLinus Torvalds 			} else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
2061da177e4SLinus Torvalds 				if (!midi->isvirtual ||
2071da177e4SLinus Torvalds 					(midi_byte != WF_INTERNAL_SWITCH &&
2081da177e4SLinus Torvalds 					 midi_byte != WF_EXTERNAL_SWITCH))
2091da177e4SLinus Torvalds 					write_data(midi, midi_byte);
2101da177e4SLinus Torvalds 				max--;
2111da177e4SLinus Torvalds 			} else {
2121da177e4SLinus Torvalds 			      __timer:
2131da177e4SLinus Torvalds 				if (midi->istimer) {
2141da177e4SLinus Torvalds 					if (--midi->istimer <= 0)
2151da177e4SLinus Torvalds 						del_timer(&midi->timer);
2161da177e4SLinus Torvalds 				}
2171da177e4SLinus Torvalds 				midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
2181da177e4SLinus Torvalds 				spin_unlock_irqrestore (&midi->virtual, flags);
2191da177e4SLinus Torvalds 				return;
2201da177e4SLinus Torvalds 			}
2211da177e4SLinus Torvalds 		} else {
2221da177e4SLinus Torvalds 			spin_unlock_irqrestore (&midi->virtual, flags);
2231da177e4SLinus Torvalds 			return;
2241da177e4SLinus Torvalds 		}
2251da177e4SLinus Torvalds 		spin_unlock_irqrestore (&midi->virtual, flags);
2261da177e4SLinus Torvalds 	}
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds 
snd_wavefront_midi_input_open(struct snd_rawmidi_substream * substream)229542172f3STakashi Iwai static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
2301da177e4SLinus Torvalds {
2311da177e4SLinus Torvalds 	unsigned long flags;
2321da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
2331da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
2341da177e4SLinus Torvalds 
235622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream || !substream->rmidi))
236622207dcSTakashi Iwai 		return -ENXIO;
237622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream->rmidi->private_data))
238622207dcSTakashi Iwai 		return -ENXIO;
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
2411da177e4SLinus Torvalds 
242520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
243520226e9STakashi Iwai 	if (!midi)
2441da177e4SLinus Torvalds 	        return -EIO;
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->open, flags);
2471da177e4SLinus Torvalds 	midi->mode[mpu] |= MPU401_MODE_INPUT;
2481da177e4SLinus Torvalds 	midi->substream_input[mpu] = substream;
2491da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->open, flags);
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds 	return 0;
2521da177e4SLinus Torvalds }
2531da177e4SLinus Torvalds 
snd_wavefront_midi_output_open(struct snd_rawmidi_substream * substream)254542172f3STakashi Iwai static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
2551da177e4SLinus Torvalds {
2561da177e4SLinus Torvalds 	unsigned long flags;
2571da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
2581da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
2591da177e4SLinus Torvalds 
260622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream || !substream->rmidi))
261622207dcSTakashi Iwai 		return -ENXIO;
262622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream->rmidi->private_data))
263622207dcSTakashi Iwai 		return -ENXIO;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
2661da177e4SLinus Torvalds 
267520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
268520226e9STakashi Iwai 	if (!midi)
2691da177e4SLinus Torvalds 	        return -EIO;
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->open, flags);
2721da177e4SLinus Torvalds 	midi->mode[mpu] |= MPU401_MODE_OUTPUT;
2731da177e4SLinus Torvalds 	midi->substream_output[mpu] = substream;
2741da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->open, flags);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 	return 0;
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
snd_wavefront_midi_input_close(struct snd_rawmidi_substream * substream)279542172f3STakashi Iwai static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
2801da177e4SLinus Torvalds {
2811da177e4SLinus Torvalds 	unsigned long flags;
2821da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
2831da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
2841da177e4SLinus Torvalds 
285622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream || !substream->rmidi))
286622207dcSTakashi Iwai 		return -ENXIO;
287622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream->rmidi->private_data))
288622207dcSTakashi Iwai 		return -ENXIO;
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
2911da177e4SLinus Torvalds 
292520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
293520226e9STakashi Iwai 	if (!midi)
2941da177e4SLinus Torvalds 	        return -EIO;
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->open, flags);
2971da177e4SLinus Torvalds 	midi->mode[mpu] &= ~MPU401_MODE_INPUT;
2981da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->open, flags);
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	return 0;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
snd_wavefront_midi_output_close(struct snd_rawmidi_substream * substream)303542172f3STakashi Iwai static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
3041da177e4SLinus Torvalds {
3051da177e4SLinus Torvalds 	unsigned long flags;
3061da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
3071da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
3081da177e4SLinus Torvalds 
309622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream || !substream->rmidi))
310622207dcSTakashi Iwai 		return -ENXIO;
311622207dcSTakashi Iwai 	if (snd_BUG_ON(!substream->rmidi->private_data))
312622207dcSTakashi Iwai 		return -ENXIO;
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
3151da177e4SLinus Torvalds 
316520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
317520226e9STakashi Iwai 	if (!midi)
3181da177e4SLinus Torvalds 	        return -EIO;
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->open, flags);
3211da177e4SLinus Torvalds 	midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
3221da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->open, flags);
3231da177e4SLinus Torvalds 	return 0;
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)326542172f3STakashi Iwai static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
3271da177e4SLinus Torvalds {
3281da177e4SLinus Torvalds 	unsigned long flags;
3291da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
3301da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	if (substream == NULL || substream->rmidi == NULL)
3331da177e4SLinus Torvalds 	        return;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	if (substream->rmidi->private_data == NULL)
3361da177e4SLinus Torvalds 	        return;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
3391da177e4SLinus Torvalds 
340520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
341520226e9STakashi Iwai 	if (!midi)
3421da177e4SLinus Torvalds 		return;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->virtual, flags);
3451da177e4SLinus Torvalds 	if (up) {
3461da177e4SLinus Torvalds 		midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
3471da177e4SLinus Torvalds 	} else {
3481da177e4SLinus Torvalds 		midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
3491da177e4SLinus Torvalds 	}
3501da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->virtual, flags);
3511da177e4SLinus Torvalds }
3521da177e4SLinus Torvalds 
snd_wavefront_midi_output_timer(struct timer_list * t)35357e69e2fSKees Cook static void snd_wavefront_midi_output_timer(struct timer_list *t)
3541da177e4SLinus Torvalds {
35557e69e2fSKees Cook 	snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
35657e69e2fSKees Cook 	snd_wavefront_card_t *card = midi->timer_card;
3571da177e4SLinus Torvalds 	unsigned long flags;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->virtual, flags);
360b843ce74STakashi Iwai 	mod_timer(&midi->timer, 1 + jiffies);
3611da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->virtual, flags);
3621da177e4SLinus Torvalds 	snd_wavefront_midi_output_write(card);
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds 
snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)365542172f3STakashi Iwai static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
3661da177e4SLinus Torvalds {
3671da177e4SLinus Torvalds 	unsigned long flags;
3681da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
3691da177e4SLinus Torvalds 	snd_wavefront_mpu_id mpu;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	if (substream == NULL || substream->rmidi == NULL)
3721da177e4SLinus Torvalds 	        return;
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	if (substream->rmidi->private_data == NULL)
3751da177e4SLinus Torvalds 	        return;
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
3781da177e4SLinus Torvalds 
379520226e9STakashi Iwai 	midi = get_wavefront_midi(substream);
380520226e9STakashi Iwai 	if (!midi)
3811da177e4SLinus Torvalds 		return;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->virtual, flags);
3841da177e4SLinus Torvalds 	if (up) {
3851da177e4SLinus Torvalds 		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
3861da177e4SLinus Torvalds 			if (!midi->istimer) {
38757e69e2fSKees Cook 				timer_setup(&midi->timer,
388b843ce74STakashi Iwai 					    snd_wavefront_midi_output_timer,
38957e69e2fSKees Cook 					    0);
390b843ce74STakashi Iwai 				mod_timer(&midi->timer, 1 + jiffies);
3911da177e4SLinus Torvalds 			}
3921da177e4SLinus Torvalds 			midi->istimer++;
3931da177e4SLinus Torvalds 			midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
3941da177e4SLinus Torvalds 		}
3951da177e4SLinus Torvalds 	} else {
3961da177e4SLinus Torvalds 		midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->virtual, flags);
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds 	if (up)
4011da177e4SLinus Torvalds 		snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
4021da177e4SLinus Torvalds }
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds void
snd_wavefront_midi_interrupt(snd_wavefront_card_t * card)4051da177e4SLinus Torvalds snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds {
4081da177e4SLinus Torvalds 	unsigned long flags;
4091da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
410542172f3STakashi Iwai 	static struct snd_rawmidi_substream *substream = NULL;
4111da177e4SLinus Torvalds 	static int mpu = external_mpu;
4121da177e4SLinus Torvalds 	int max = 128;
4131da177e4SLinus Torvalds 	unsigned char byte;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	midi = &card->wavefront.midi;
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	if (!input_avail (midi)) { /* not for us */
4181da177e4SLinus Torvalds 		snd_wavefront_midi_output_write(card);
4191da177e4SLinus Torvalds 		return;
4201da177e4SLinus Torvalds 	}
4211da177e4SLinus Torvalds 
4221da177e4SLinus Torvalds 	spin_lock_irqsave (&midi->virtual, flags);
4231da177e4SLinus Torvalds 	while (--max) {
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 		if (input_avail (midi)) {
4261da177e4SLinus Torvalds 			byte = read_data (midi);
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 			if (midi->isvirtual) {
4291da177e4SLinus Torvalds 				if (byte == WF_EXTERNAL_SWITCH) {
4301da177e4SLinus Torvalds 					substream = midi->substream_input[external_mpu];
4311da177e4SLinus Torvalds 					mpu = external_mpu;
4321da177e4SLinus Torvalds 				} else if (byte == WF_INTERNAL_SWITCH) {
4331da177e4SLinus Torvalds 					substream = midi->substream_output[internal_mpu];
4341da177e4SLinus Torvalds 					mpu = internal_mpu;
4351da177e4SLinus Torvalds 				} /* else just leave it as it is */
4361da177e4SLinus Torvalds 			} else {
4371da177e4SLinus Torvalds 				substream = midi->substream_input[internal_mpu];
4381da177e4SLinus Torvalds 				mpu = internal_mpu;
4391da177e4SLinus Torvalds 			}
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds 			if (substream == NULL) {
4421da177e4SLinus Torvalds 				continue;
4431da177e4SLinus Torvalds 			}
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds 			if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
4461da177e4SLinus Torvalds 				snd_rawmidi_receive(substream, &byte, 1);
4471da177e4SLinus Torvalds 			}
4481da177e4SLinus Torvalds 		} else {
4491da177e4SLinus Torvalds 			break;
4501da177e4SLinus Torvalds 		}
4511da177e4SLinus Torvalds 	}
4521da177e4SLinus Torvalds 	spin_unlock_irqrestore (&midi->virtual, flags);
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	snd_wavefront_midi_output_write(card);
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds void
snd_wavefront_midi_enable_virtual(snd_wavefront_card_t * card)4581da177e4SLinus Torvalds snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds {
4611da177e4SLinus Torvalds 	unsigned long flags;
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
4641da177e4SLinus Torvalds 	card->wavefront.midi.isvirtual = 1;
4651da177e4SLinus Torvalds 	card->wavefront.midi.output_mpu = internal_mpu;
4661da177e4SLinus Torvalds 	card->wavefront.midi.input_mpu = internal_mpu;
4671da177e4SLinus Torvalds 	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds 
4701da177e4SLinus Torvalds void
snd_wavefront_midi_disable_virtual(snd_wavefront_card_t * card)4711da177e4SLinus Torvalds snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds {
4741da177e4SLinus Torvalds 	unsigned long flags;
4751da177e4SLinus Torvalds 
4761da177e4SLinus Torvalds 	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
4771da177e4SLinus Torvalds 	// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
4781da177e4SLinus Torvalds 	// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
4791da177e4SLinus Torvalds 	card->wavefront.midi.isvirtual = 0;
4801da177e4SLinus Torvalds 	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds 
4831bff292eSBill Pemberton int
snd_wavefront_midi_start(snd_wavefront_card_t * card)4841da177e4SLinus Torvalds snd_wavefront_midi_start (snd_wavefront_card_t *card)
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds {
4871da177e4SLinus Torvalds 	int ok, i;
4881da177e4SLinus Torvalds 	unsigned char rbuf[4], wbuf[4];
4891da177e4SLinus Torvalds 	snd_wavefront_t *dev;
4901da177e4SLinus Torvalds 	snd_wavefront_midi_t *midi;
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	dev = &card->wavefront;
4931da177e4SLinus Torvalds 	midi = &dev->midi;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	/* The ICS2115 MPU-401 interface doesn't do anything
4961da177e4SLinus Torvalds 	   until its set into UART mode.
4971da177e4SLinus Torvalds 	*/
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	/* XXX fix me - no hard timing loops allowed! */
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 	for (i = 0; i < 30000 && !output_ready (midi); i++);
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	if (!output_ready (midi)) {
504*8b4ac542STakashi Iwai 		dev_err(card->wavefront.card->dev,
505*8b4ac542STakashi Iwai 			"MIDI interface not ready for command\n");
5061da177e4SLinus Torvalds 		return -1;
5071da177e4SLinus Torvalds 	}
5081da177e4SLinus Torvalds 
5091da177e4SLinus Torvalds 	/* Any interrupts received from now on
5101da177e4SLinus Torvalds 	   are owned by the MIDI side of things.
5111da177e4SLinus Torvalds 	*/
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	dev->interrupts_are_midi = 1;
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	outb (UART_MODE_ON, midi->mpu_command_port);
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
5181da177e4SLinus Torvalds 		if (input_avail (midi)) {
5191da177e4SLinus Torvalds 			if (read_data (midi) == MPU_ACK) {
5201da177e4SLinus Torvalds 				ok = 1;
5211da177e4SLinus Torvalds 				break;
5221da177e4SLinus Torvalds 			}
5231da177e4SLinus Torvalds 		}
5241da177e4SLinus Torvalds 	}
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	if (!ok) {
527*8b4ac542STakashi Iwai 		dev_err(card->wavefront.card->dev,
528*8b4ac542STakashi Iwai 			"cannot set UART mode for MIDI interface");
5291da177e4SLinus Torvalds 		dev->interrupts_are_midi = 0;
5301da177e4SLinus Torvalds 		return -1;
5311da177e4SLinus Torvalds 	}
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds 	/* Route external MIDI to WaveFront synth (by default) */
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 	if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
536*8b4ac542STakashi Iwai 		dev_warn(card->wavefront.card->dev,
537*8b4ac542STakashi Iwai 			 "can't enable MIDI-IN-2-synth routing.\n");
5381da177e4SLinus Torvalds 		/* XXX error ? */
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	/* Turn on Virtual MIDI, but first *always* turn it off,
54225985edcSLucas De Marchi 	   since otherwise consecutive reloads of the driver will
5431da177e4SLinus Torvalds 	   never cause the hardware to generate the initial "internal" or
5441da177e4SLinus Torvalds 	   "external" source bytes in the MIDI data stream. This
5451da177e4SLinus Torvalds 	   is pretty important, since the internal hardware generally will
5461da177e4SLinus Torvalds 	   be used to generate none or very little MIDI output, and
5471da177e4SLinus Torvalds 	   thus the only source of MIDI data is actually external. Without
5481da177e4SLinus Torvalds 	   the switch bytes, the driver will think it all comes from
5491da177e4SLinus Torvalds 	   the internal interface. Duh.
5501da177e4SLinus Torvalds 	*/
5511da177e4SLinus Torvalds 
5521da177e4SLinus Torvalds 	if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) {
553*8b4ac542STakashi Iwai 		dev_warn(card->wavefront.card->dev,
554*8b4ac542STakashi Iwai 			 "virtual MIDI mode not disabled\n");
5551da177e4SLinus Torvalds 		return 0; /* We're OK, but missing the external MIDI dev */
5561da177e4SLinus Torvalds 	}
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds 	snd_wavefront_midi_enable_virtual (card);
5591da177e4SLinus Torvalds 
5601da177e4SLinus Torvalds 	if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
561*8b4ac542STakashi Iwai 		dev_warn(card->wavefront.card->dev,
562*8b4ac542STakashi Iwai 			 "cannot enable virtual MIDI mode.\n");
5631da177e4SLinus Torvalds 		snd_wavefront_midi_disable_virtual (card);
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 	return 0;
5661da177e4SLinus Torvalds }
5671da177e4SLinus Torvalds 
5689021b2b8STakashi Iwai const struct snd_rawmidi_ops snd_wavefront_midi_output =
5691da177e4SLinus Torvalds {
5701da177e4SLinus Torvalds 	.open =		snd_wavefront_midi_output_open,
5711da177e4SLinus Torvalds 	.close =	snd_wavefront_midi_output_close,
5721da177e4SLinus Torvalds 	.trigger =	snd_wavefront_midi_output_trigger,
5731da177e4SLinus Torvalds };
5741da177e4SLinus Torvalds 
5759021b2b8STakashi Iwai const struct snd_rawmidi_ops snd_wavefront_midi_input =
5761da177e4SLinus Torvalds {
5771da177e4SLinus Torvalds 	.open =		snd_wavefront_midi_input_open,
5781da177e4SLinus Torvalds 	.close =	snd_wavefront_midi_input_close,
5791da177e4SLinus Torvalds 	.trigger =	snd_wavefront_midi_input_trigger,
5801da177e4SLinus Torvalds };
5811da177e4SLinus Torvalds 
582