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