Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Mar 24-27, 2025, special US time zones
Register
Loading...
v3.1
 
  1/*
  2 * Copyright (C) by Paul Barton-Davis 1998-1999
  3 *
  4 * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  5 * Version 2 (June 1991). See the "COPYING" file distributed with this
  6 * software for more info.  
  7 */
  8
  9/* The low level driver for the WaveFront ICS2115 MIDI interface(s)
 10 *
 11 * Note that there is also an MPU-401 emulation (actually, a UART-401
 12 * emulation) on the CS4232 on the Tropez and Tropez Plus. This code
 13 * has nothing to do with that interface at all.
 14 *
 15 * The interface is essentially just a UART-401, but is has the
 16 * interesting property of supporting what Turtle Beach called
 17 * "Virtual MIDI" mode. In this mode, there are effectively *two*
 18 * MIDI buses accessible via the interface, one that is routed
 19 * solely to/from the external WaveFront synthesizer and the other
 20 * corresponding to the pin/socket connector used to link external
 21 * MIDI devices to the board.
 22 *
 23 * This driver fully supports this mode, allowing two distinct MIDI
 24 * busses to be used completely independently, giving 32 channels of
 25 * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI
 26 * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1,
 27 * where `n' is the card number. Note that the device numbers may be
 28 * something other than 0 and 1 if the CS4232 UART/MPU-401 interface
 29 * is enabled.
 30 *
 31 * Switching between the two is accomplished externally by the driver
 32 * using the two otherwise unused MIDI bytes. See the code for more details.
 33 *
 34 * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c)
 35 *
 36 * The main reason to turn off Virtual MIDI mode is when you want to
 37 * tightly couple the WaveFront synth with an external MIDI
 38 * device. You won't be able to distinguish the source of any MIDI
 39 * data except via SysEx ID, but thats probably OK, since for the most
 40 * part, the WaveFront won't be sending any MIDI data at all.
 41 *  
 42 * The main reason to turn on Virtual MIDI Mode is to provide two
 43 * completely independent 16-channel MIDI buses, one to the
 44 * WaveFront and one to any external MIDI devices. Given the 32
 45 * voice nature of the WaveFront, its pretty easy to find a use
 46 * for all 16 channels driving just that synth.
 47 *  
 48 */
 49
 50#include <asm/io.h>
 51#include <linux/init.h>
 52#include <linux/time.h>
 53#include <linux/wait.h>
 54#include <sound/core.h>
 55#include <sound/snd_wavefront.h>
 56
 57static inline int 
 58wf_mpu_status (snd_wavefront_midi_t *midi)
 59
 60{
 61	return inb (midi->mpu_status_port);
 62}
 63
 64static inline int 
 65input_avail (snd_wavefront_midi_t *midi)
 66
 67{
 68	return !(wf_mpu_status(midi) & INPUT_AVAIL);
 69}
 70
 71static inline int
 72output_ready (snd_wavefront_midi_t *midi)
 73
 74{
 75	return !(wf_mpu_status(midi) & OUTPUT_READY);
 76}
 77
 78static inline int 
 79read_data (snd_wavefront_midi_t *midi)
 80
 81{
 82	return inb (midi->mpu_data_port);
 83}
 84
 85static inline void 
 86write_data (snd_wavefront_midi_t *midi, unsigned char byte)
 87
 88{
 89	outb (byte, midi->mpu_data_port);
 90}
 91
 92static snd_wavefront_midi_t *
 93get_wavefront_midi (struct snd_rawmidi_substream *substream)
 94
 95{
 96	struct snd_card *card;
 97	snd_wavefront_card_t *acard;
 98
 99	if (substream == NULL || substream->rmidi == NULL) 
100	        return NULL;
101
102	card = substream->rmidi->card;
103
104	if (card == NULL) 
105	        return NULL;
106
107	if (card->private_data == NULL) 
108 	        return NULL;
109
110	acard = card->private_data;
111
112	return &acard->wavefront.midi;
113}
114
115static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
116{
117	snd_wavefront_midi_t *midi = &card->wavefront.midi;
118	snd_wavefront_mpu_id  mpu;
119	unsigned long flags;
120	unsigned char midi_byte;
121	int max = 256, mask = 1;
122	int timeout;
123
124	/* Its not OK to try to change the status of "virtuality" of
125	   the MIDI interface while we're outputting stuff.  See
126	   snd_wavefront_midi_{enable,disable}_virtual () for the
127	   other half of this.  
128
129	   The first loop attempts to flush any data from the
130	   current output device, and then the second 
131	   emits the switch byte (if necessary), and starts
132	   outputting data for the output device currently in use.
133	*/
134
135	if (midi->substream_output[midi->output_mpu] == NULL) {
136		goto __second;
137	}
138
139	while (max > 0) {
140
141		/* XXX fix me - no hard timing loops allowed! */
142
143		for (timeout = 30000; timeout > 0; timeout--) {
144			if (output_ready (midi))
145				break;
146		}
147	
148		spin_lock_irqsave (&midi->virtual, flags);
149		if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
150			spin_unlock_irqrestore (&midi->virtual, flags);
151			goto __second;
152		}
153		if (output_ready (midi)) {
154			if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
155				if (!midi->isvirtual ||
156					(midi_byte != WF_INTERNAL_SWITCH &&
157					 midi_byte != WF_EXTERNAL_SWITCH))
158					write_data(midi, midi_byte);
159				max--;
160			} else {
161				if (midi->istimer) {
162					if (--midi->istimer <= 0)
163						del_timer(&midi->timer);
164				}
165				midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
166				spin_unlock_irqrestore (&midi->virtual, flags);
167				goto __second;
168			}
169		} else {
170			spin_unlock_irqrestore (&midi->virtual, flags);
171			return;
172		}
173		spin_unlock_irqrestore (&midi->virtual, flags);
174	}
175
176      __second:
177
178	if (midi->substream_output[!midi->output_mpu] == NULL) {
179		return;
180	}
181
182	while (max > 0) {
183
184		/* XXX fix me - no hard timing loops allowed! */
185
186		for (timeout = 30000; timeout > 0; timeout--) {
187			if (output_ready (midi))
188				break;
189		}
190	
191		spin_lock_irqsave (&midi->virtual, flags);
192		if (!midi->isvirtual)
193			mask = 0;
194		mpu = midi->output_mpu ^ mask;
195		mask = 0;	/* don't invert the value from now */
196		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
197			spin_unlock_irqrestore (&midi->virtual, flags);
198			return;
199		}
200		if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
201			goto __timer;
202		if (output_ready (midi)) {
203			if (mpu != midi->output_mpu) {
204				write_data(midi, mpu == internal_mpu ?
205							WF_INTERNAL_SWITCH :
206							WF_EXTERNAL_SWITCH);
207				midi->output_mpu = mpu;
208			} else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
209				if (!midi->isvirtual ||
210					(midi_byte != WF_INTERNAL_SWITCH &&
211					 midi_byte != WF_EXTERNAL_SWITCH))
212					write_data(midi, midi_byte);
213				max--;
214			} else {
215			      __timer:
216				if (midi->istimer) {
217					if (--midi->istimer <= 0)
218						del_timer(&midi->timer);
219				}
220				midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
221				spin_unlock_irqrestore (&midi->virtual, flags);
222				return;
223			}
224		} else {
225			spin_unlock_irqrestore (&midi->virtual, flags);
226			return;
227		}
228		spin_unlock_irqrestore (&midi->virtual, flags);
229	}
230}
231
232static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
233{
234	unsigned long flags;
235	snd_wavefront_midi_t *midi;
236	snd_wavefront_mpu_id mpu;
237
238	if (snd_BUG_ON(!substream || !substream->rmidi))
239		return -ENXIO;
240	if (snd_BUG_ON(!substream->rmidi->private_data))
241		return -ENXIO;
242
243	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
244
245	if ((midi = get_wavefront_midi (substream)) == NULL)
246	        return -EIO;
247
248	spin_lock_irqsave (&midi->open, flags);
249	midi->mode[mpu] |= MPU401_MODE_INPUT;
250	midi->substream_input[mpu] = substream;
251	spin_unlock_irqrestore (&midi->open, flags);
252
253	return 0;
254}
255
256static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
257{
258	unsigned long flags;
259	snd_wavefront_midi_t *midi;
260	snd_wavefront_mpu_id mpu;
261
262	if (snd_BUG_ON(!substream || !substream->rmidi))
263		return -ENXIO;
264	if (snd_BUG_ON(!substream->rmidi->private_data))
265		return -ENXIO;
266
267	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
268
269	if ((midi = get_wavefront_midi (substream)) == NULL)
270	        return -EIO;
271
272	spin_lock_irqsave (&midi->open, flags);
273	midi->mode[mpu] |= MPU401_MODE_OUTPUT;
274	midi->substream_output[mpu] = substream;
275	spin_unlock_irqrestore (&midi->open, flags);
276
277	return 0;
278}
279
280static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
281{
282	unsigned long flags;
283	snd_wavefront_midi_t *midi;
284	snd_wavefront_mpu_id mpu;
285
286	if (snd_BUG_ON(!substream || !substream->rmidi))
287		return -ENXIO;
288	if (snd_BUG_ON(!substream->rmidi->private_data))
289		return -ENXIO;
290
291	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
292
293	if ((midi = get_wavefront_midi (substream)) == NULL)
294	        return -EIO;
295
296	spin_lock_irqsave (&midi->open, flags);
297	midi->mode[mpu] &= ~MPU401_MODE_INPUT;
298	spin_unlock_irqrestore (&midi->open, flags);
299
300	return 0;
301}
302
303static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
304{
305	unsigned long flags;
306	snd_wavefront_midi_t *midi;
307	snd_wavefront_mpu_id mpu;
308
309	if (snd_BUG_ON(!substream || !substream->rmidi))
310		return -ENXIO;
311	if (snd_BUG_ON(!substream->rmidi->private_data))
312		return -ENXIO;
313
314	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
315
316	if ((midi = get_wavefront_midi (substream)) == NULL)
317	        return -EIO;
318
319	spin_lock_irqsave (&midi->open, flags);
320	midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
321	spin_unlock_irqrestore (&midi->open, flags);
322	return 0;
323}
324
325static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
326{
327	unsigned long flags;
328	snd_wavefront_midi_t *midi;
329	snd_wavefront_mpu_id mpu;
330
331	if (substream == NULL || substream->rmidi == NULL) 
332	        return;
333
334	if (substream->rmidi->private_data == NULL)
335	        return;
336
337	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
338
339	if ((midi = get_wavefront_midi (substream)) == NULL) {
340		return;
341	}
342
343	spin_lock_irqsave (&midi->virtual, flags);
344	if (up) {
345		midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
346	} else {
347		midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
348	}
349	spin_unlock_irqrestore (&midi->virtual, flags);
350}
351
352static void snd_wavefront_midi_output_timer(unsigned long data)
353{
354	snd_wavefront_card_t *card = (snd_wavefront_card_t *)data;
355	snd_wavefront_midi_t *midi = &card->wavefront.midi;
356	unsigned long flags;
357	
358	spin_lock_irqsave (&midi->virtual, flags);
359	midi->timer.expires = 1 + jiffies;
360	add_timer(&midi->timer);
361	spin_unlock_irqrestore (&midi->virtual, flags);
362	snd_wavefront_midi_output_write(card);
363}
364
365static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
366{
367	unsigned long flags;
368	snd_wavefront_midi_t *midi;
369	snd_wavefront_mpu_id mpu;
370
371	if (substream == NULL || substream->rmidi == NULL) 
372	        return;
373
374	if (substream->rmidi->private_data == NULL)
375	        return;
376
377	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
378
379	if ((midi = get_wavefront_midi (substream)) == NULL) {
380		return;
381	}
382
383	spin_lock_irqsave (&midi->virtual, flags);
384	if (up) {
385		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
386			if (!midi->istimer) {
387				init_timer(&midi->timer);
388				midi->timer.function = snd_wavefront_midi_output_timer;
389				midi->timer.data = (unsigned long) substream->rmidi->card->private_data;
390				midi->timer.expires = 1 + jiffies;
391				add_timer(&midi->timer);
392			}
393			midi->istimer++;
394			midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
395		}
396	} else {
397		midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
398	}
399	spin_unlock_irqrestore (&midi->virtual, flags);
400
401	if (up)
402		snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
403}
404
405void
406snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
407
408{
409	unsigned long flags;
410	snd_wavefront_midi_t *midi;
411	static struct snd_rawmidi_substream *substream = NULL;
412	static int mpu = external_mpu; 
413	int max = 128;
414	unsigned char byte;
415
416	midi = &card->wavefront.midi;
417
418	if (!input_avail (midi)) { /* not for us */
419		snd_wavefront_midi_output_write(card);
420		return;
421	}
422
423	spin_lock_irqsave (&midi->virtual, flags);
424	while (--max) {
425
426		if (input_avail (midi)) {
427			byte = read_data (midi);
428
429			if (midi->isvirtual) {				
430				if (byte == WF_EXTERNAL_SWITCH) {
431					substream = midi->substream_input[external_mpu];
432					mpu = external_mpu;
433				} else if (byte == WF_INTERNAL_SWITCH) { 
434					substream = midi->substream_output[internal_mpu];
435					mpu = internal_mpu;
436				} /* else just leave it as it is */
437			} else {
438				substream = midi->substream_input[internal_mpu];
439				mpu = internal_mpu;
440			}
441
442			if (substream == NULL) {
443				continue;
444			}
445
446			if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
447				snd_rawmidi_receive(substream, &byte, 1);
448			}
449		} else {
450			break;
451		}
452	} 
453	spin_unlock_irqrestore (&midi->virtual, flags);
454
455	snd_wavefront_midi_output_write(card);
456}
457
458void
459snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
460
461{
462	unsigned long flags;
463
464	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
465	card->wavefront.midi.isvirtual = 1;
466	card->wavefront.midi.output_mpu = internal_mpu;
467	card->wavefront.midi.input_mpu = internal_mpu;
468	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
469}
470
471void
472snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
473
474{
475	unsigned long flags;
476
477	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
478	// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
479	// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
480	card->wavefront.midi.isvirtual = 0;
481	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
482}
483
484int __devinit
485snd_wavefront_midi_start (snd_wavefront_card_t *card)
486
487{
488	int ok, i;
489	unsigned char rbuf[4], wbuf[4];
490	snd_wavefront_t *dev;
491	snd_wavefront_midi_t *midi;
492
493	dev = &card->wavefront;
494	midi = &dev->midi;
495
496	/* The ICS2115 MPU-401 interface doesn't do anything
497	   until its set into UART mode.
498	*/
499
500	/* XXX fix me - no hard timing loops allowed! */
501
502	for (i = 0; i < 30000 && !output_ready (midi); i++);
503
504	if (!output_ready (midi)) {
505		snd_printk ("MIDI interface not ready for command\n");
506		return -1;
507	}
508
509	/* Any interrupts received from now on
510	   are owned by the MIDI side of things.
511	*/
512
513	dev->interrupts_are_midi = 1;
514	
515	outb (UART_MODE_ON, midi->mpu_command_port);
516
517	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
518		if (input_avail (midi)) {
519			if (read_data (midi) == MPU_ACK) {
520				ok = 1;
521				break;
522			}
523		}
524	}
525
526	if (!ok) {
527		snd_printk ("cannot set UART mode for MIDI interface");
528		dev->interrupts_are_midi = 0;
529		return -1;
530	}
531
532	/* Route external MIDI to WaveFront synth (by default) */
533    
534	if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
535		snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
536		/* XXX error ? */
537	}
538
539	/* Turn on Virtual MIDI, but first *always* turn it off,
540	   since otherwise consecutive reloads of the driver will
541	   never cause the hardware to generate the initial "internal" or 
542	   "external" source bytes in the MIDI data stream. This
543	   is pretty important, since the internal hardware generally will
544	   be used to generate none or very little MIDI output, and
545	   thus the only source of MIDI data is actually external. Without
546	   the switch bytes, the driver will think it all comes from
547	   the internal interface. Duh.
548	*/
549
550	if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
551		snd_printk ("virtual MIDI mode not disabled\n");
552		return 0; /* We're OK, but missing the external MIDI dev */
553	}
554
555	snd_wavefront_midi_enable_virtual (card);
556
557	if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
558		snd_printk ("cannot enable virtual MIDI mode.\n");
559		snd_wavefront_midi_disable_virtual (card);
560	} 
561	return 0;
562}
563
564struct snd_rawmidi_ops snd_wavefront_midi_output =
565{
566	.open =		snd_wavefront_midi_output_open,
567	.close =	snd_wavefront_midi_output_close,
568	.trigger =	snd_wavefront_midi_output_trigger,
569};
570
571struct snd_rawmidi_ops snd_wavefront_midi_input =
572{
573	.open =		snd_wavefront_midi_input_open,
574	.close =	snd_wavefront_midi_input_close,
575	.trigger =	snd_wavefront_midi_input_trigger,
576};
577
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) by Paul Barton-Davis 1998-1999
 
 
 
 
  4 */
  5
  6/* The low level driver for the WaveFront ICS2115 MIDI interface(s)
  7 *
  8 * Note that there is also an MPU-401 emulation (actually, a UART-401
  9 * emulation) on the CS4232 on the Tropez and Tropez Plus. This code
 10 * has nothing to do with that interface at all.
 11 *
 12 * The interface is essentially just a UART-401, but is has the
 13 * interesting property of supporting what Turtle Beach called
 14 * "Virtual MIDI" mode. In this mode, there are effectively *two*
 15 * MIDI buses accessible via the interface, one that is routed
 16 * solely to/from the external WaveFront synthesizer and the other
 17 * corresponding to the pin/socket connector used to link external
 18 * MIDI devices to the board.
 19 *
 20 * This driver fully supports this mode, allowing two distinct MIDI
 21 * busses to be used completely independently, giving 32 channels of
 22 * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI
 23 * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1,
 24 * where `n' is the card number. Note that the device numbers may be
 25 * something other than 0 and 1 if the CS4232 UART/MPU-401 interface
 26 * is enabled.
 27 *
 28 * Switching between the two is accomplished externally by the driver
 29 * using the two otherwise unused MIDI bytes. See the code for more details.
 30 *
 31 * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c)
 32 *
 33 * The main reason to turn off Virtual MIDI mode is when you want to
 34 * tightly couple the WaveFront synth with an external MIDI
 35 * device. You won't be able to distinguish the source of any MIDI
 36 * data except via SysEx ID, but thats probably OK, since for the most
 37 * part, the WaveFront won't be sending any MIDI data at all.
 38 *  
 39 * The main reason to turn on Virtual MIDI Mode is to provide two
 40 * completely independent 16-channel MIDI buses, one to the
 41 * WaveFront and one to any external MIDI devices. Given the 32
 42 * voice nature of the WaveFront, its pretty easy to find a use
 43 * for all 16 channels driving just that synth.
 44 *  
 45 */
 46
 47#include <linux/io.h>
 48#include <linux/init.h>
 49#include <linux/time.h>
 50#include <linux/wait.h>
 51#include <sound/core.h>
 52#include <sound/snd_wavefront.h>
 53
 54static inline int 
 55wf_mpu_status (snd_wavefront_midi_t *midi)
 56
 57{
 58	return inb (midi->mpu_status_port);
 59}
 60
 61static inline int 
 62input_avail (snd_wavefront_midi_t *midi)
 63
 64{
 65	return !(wf_mpu_status(midi) & INPUT_AVAIL);
 66}
 67
 68static inline int
 69output_ready (snd_wavefront_midi_t *midi)
 70
 71{
 72	return !(wf_mpu_status(midi) & OUTPUT_READY);
 73}
 74
 75static inline int 
 76read_data (snd_wavefront_midi_t *midi)
 77
 78{
 79	return inb (midi->mpu_data_port);
 80}
 81
 82static inline void 
 83write_data (snd_wavefront_midi_t *midi, unsigned char byte)
 84
 85{
 86	outb (byte, midi->mpu_data_port);
 87}
 88
 89static snd_wavefront_midi_t *
 90get_wavefront_midi (struct snd_rawmidi_substream *substream)
 91
 92{
 93	struct snd_card *card;
 94	snd_wavefront_card_t *acard;
 95
 96	if (substream == NULL || substream->rmidi == NULL) 
 97	        return NULL;
 98
 99	card = substream->rmidi->card;
100
101	if (card == NULL) 
102	        return NULL;
103
104	if (card->private_data == NULL) 
105 	        return NULL;
106
107	acard = card->private_data;
108
109	return &acard->wavefront.midi;
110}
111
112static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
113{
114	snd_wavefront_midi_t *midi = &card->wavefront.midi;
115	snd_wavefront_mpu_id  mpu;
116	unsigned long flags;
117	unsigned char midi_byte;
118	int max = 256, mask = 1;
119	int timeout;
120
121	/* Its not OK to try to change the status of "virtuality" of
122	   the MIDI interface while we're outputting stuff.  See
123	   snd_wavefront_midi_{enable,disable}_virtual () for the
124	   other half of this.  
125
126	   The first loop attempts to flush any data from the
127	   current output device, and then the second 
128	   emits the switch byte (if necessary), and starts
129	   outputting data for the output device currently in use.
130	*/
131
132	if (midi->substream_output[midi->output_mpu] == NULL) {
133		goto __second;
134	}
135
136	while (max > 0) {
137
138		/* XXX fix me - no hard timing loops allowed! */
139
140		for (timeout = 30000; timeout > 0; timeout--) {
141			if (output_ready (midi))
142				break;
143		}
144	
145		spin_lock_irqsave (&midi->virtual, flags);
146		if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
147			spin_unlock_irqrestore (&midi->virtual, flags);
148			goto __second;
149		}
150		if (output_ready (midi)) {
151			if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
152				if (!midi->isvirtual ||
153					(midi_byte != WF_INTERNAL_SWITCH &&
154					 midi_byte != WF_EXTERNAL_SWITCH))
155					write_data(midi, midi_byte);
156				max--;
157			} else {
158				if (midi->istimer) {
159					if (--midi->istimer <= 0)
160						del_timer(&midi->timer);
161				}
162				midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
163				spin_unlock_irqrestore (&midi->virtual, flags);
164				goto __second;
165			}
166		} else {
167			spin_unlock_irqrestore (&midi->virtual, flags);
168			return;
169		}
170		spin_unlock_irqrestore (&midi->virtual, flags);
171	}
172
173      __second:
174
175	if (midi->substream_output[!midi->output_mpu] == NULL) {
176		return;
177	}
178
179	while (max > 0) {
180
181		/* XXX fix me - no hard timing loops allowed! */
182
183		for (timeout = 30000; timeout > 0; timeout--) {
184			if (output_ready (midi))
185				break;
186		}
187	
188		spin_lock_irqsave (&midi->virtual, flags);
189		if (!midi->isvirtual)
190			mask = 0;
191		mpu = midi->output_mpu ^ mask;
192		mask = 0;	/* don't invert the value from now */
193		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
194			spin_unlock_irqrestore (&midi->virtual, flags);
195			return;
196		}
197		if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
198			goto __timer;
199		if (output_ready (midi)) {
200			if (mpu != midi->output_mpu) {
201				write_data(midi, mpu == internal_mpu ?
202							WF_INTERNAL_SWITCH :
203							WF_EXTERNAL_SWITCH);
204				midi->output_mpu = mpu;
205			} else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
206				if (!midi->isvirtual ||
207					(midi_byte != WF_INTERNAL_SWITCH &&
208					 midi_byte != WF_EXTERNAL_SWITCH))
209					write_data(midi, midi_byte);
210				max--;
211			} else {
212			      __timer:
213				if (midi->istimer) {
214					if (--midi->istimer <= 0)
215						del_timer(&midi->timer);
216				}
217				midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
218				spin_unlock_irqrestore (&midi->virtual, flags);
219				return;
220			}
221		} else {
222			spin_unlock_irqrestore (&midi->virtual, flags);
223			return;
224		}
225		spin_unlock_irqrestore (&midi->virtual, flags);
226	}
227}
228
229static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
230{
231	unsigned long flags;
232	snd_wavefront_midi_t *midi;
233	snd_wavefront_mpu_id mpu;
234
235	if (snd_BUG_ON(!substream || !substream->rmidi))
236		return -ENXIO;
237	if (snd_BUG_ON(!substream->rmidi->private_data))
238		return -ENXIO;
239
240	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
241
242	if ((midi = get_wavefront_midi (substream)) == NULL)
243	        return -EIO;
244
245	spin_lock_irqsave (&midi->open, flags);
246	midi->mode[mpu] |= MPU401_MODE_INPUT;
247	midi->substream_input[mpu] = substream;
248	spin_unlock_irqrestore (&midi->open, flags);
249
250	return 0;
251}
252
253static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
254{
255	unsigned long flags;
256	snd_wavefront_midi_t *midi;
257	snd_wavefront_mpu_id mpu;
258
259	if (snd_BUG_ON(!substream || !substream->rmidi))
260		return -ENXIO;
261	if (snd_BUG_ON(!substream->rmidi->private_data))
262		return -ENXIO;
263
264	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
265
266	if ((midi = get_wavefront_midi (substream)) == NULL)
267	        return -EIO;
268
269	spin_lock_irqsave (&midi->open, flags);
270	midi->mode[mpu] |= MPU401_MODE_OUTPUT;
271	midi->substream_output[mpu] = substream;
272	spin_unlock_irqrestore (&midi->open, flags);
273
274	return 0;
275}
276
277static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
278{
279	unsigned long flags;
280	snd_wavefront_midi_t *midi;
281	snd_wavefront_mpu_id mpu;
282
283	if (snd_BUG_ON(!substream || !substream->rmidi))
284		return -ENXIO;
285	if (snd_BUG_ON(!substream->rmidi->private_data))
286		return -ENXIO;
287
288	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
289
290	if ((midi = get_wavefront_midi (substream)) == NULL)
291	        return -EIO;
292
293	spin_lock_irqsave (&midi->open, flags);
294	midi->mode[mpu] &= ~MPU401_MODE_INPUT;
295	spin_unlock_irqrestore (&midi->open, flags);
296
297	return 0;
298}
299
300static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
301{
302	unsigned long flags;
303	snd_wavefront_midi_t *midi;
304	snd_wavefront_mpu_id mpu;
305
306	if (snd_BUG_ON(!substream || !substream->rmidi))
307		return -ENXIO;
308	if (snd_BUG_ON(!substream->rmidi->private_data))
309		return -ENXIO;
310
311	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
312
313	if ((midi = get_wavefront_midi (substream)) == NULL)
314	        return -EIO;
315
316	spin_lock_irqsave (&midi->open, flags);
317	midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
318	spin_unlock_irqrestore (&midi->open, flags);
319	return 0;
320}
321
322static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
323{
324	unsigned long flags;
325	snd_wavefront_midi_t *midi;
326	snd_wavefront_mpu_id mpu;
327
328	if (substream == NULL || substream->rmidi == NULL) 
329	        return;
330
331	if (substream->rmidi->private_data == NULL)
332	        return;
333
334	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
335
336	if ((midi = get_wavefront_midi (substream)) == NULL) {
337		return;
338	}
339
340	spin_lock_irqsave (&midi->virtual, flags);
341	if (up) {
342		midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
343	} else {
344		midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
345	}
346	spin_unlock_irqrestore (&midi->virtual, flags);
347}
348
349static void snd_wavefront_midi_output_timer(struct timer_list *t)
350{
351	snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
352	snd_wavefront_card_t *card = midi->timer_card;
353	unsigned long flags;
354	
355	spin_lock_irqsave (&midi->virtual, flags);
356	mod_timer(&midi->timer, 1 + jiffies);
 
357	spin_unlock_irqrestore (&midi->virtual, flags);
358	snd_wavefront_midi_output_write(card);
359}
360
361static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
362{
363	unsigned long flags;
364	snd_wavefront_midi_t *midi;
365	snd_wavefront_mpu_id mpu;
366
367	if (substream == NULL || substream->rmidi == NULL) 
368	        return;
369
370	if (substream->rmidi->private_data == NULL)
371	        return;
372
373	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
374
375	if ((midi = get_wavefront_midi (substream)) == NULL) {
376		return;
377	}
378
379	spin_lock_irqsave (&midi->virtual, flags);
380	if (up) {
381		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
382			if (!midi->istimer) {
383				timer_setup(&midi->timer,
384					    snd_wavefront_midi_output_timer,
385					    0);
386				mod_timer(&midi->timer, 1 + jiffies);
 
387			}
388			midi->istimer++;
389			midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
390		}
391	} else {
392		midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
393	}
394	spin_unlock_irqrestore (&midi->virtual, flags);
395
396	if (up)
397		snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
398}
399
400void
401snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
402
403{
404	unsigned long flags;
405	snd_wavefront_midi_t *midi;
406	static struct snd_rawmidi_substream *substream = NULL;
407	static int mpu = external_mpu; 
408	int max = 128;
409	unsigned char byte;
410
411	midi = &card->wavefront.midi;
412
413	if (!input_avail (midi)) { /* not for us */
414		snd_wavefront_midi_output_write(card);
415		return;
416	}
417
418	spin_lock_irqsave (&midi->virtual, flags);
419	while (--max) {
420
421		if (input_avail (midi)) {
422			byte = read_data (midi);
423
424			if (midi->isvirtual) {				
425				if (byte == WF_EXTERNAL_SWITCH) {
426					substream = midi->substream_input[external_mpu];
427					mpu = external_mpu;
428				} else if (byte == WF_INTERNAL_SWITCH) { 
429					substream = midi->substream_output[internal_mpu];
430					mpu = internal_mpu;
431				} /* else just leave it as it is */
432			} else {
433				substream = midi->substream_input[internal_mpu];
434				mpu = internal_mpu;
435			}
436
437			if (substream == NULL) {
438				continue;
439			}
440
441			if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
442				snd_rawmidi_receive(substream, &byte, 1);
443			}
444		} else {
445			break;
446		}
447	} 
448	spin_unlock_irqrestore (&midi->virtual, flags);
449
450	snd_wavefront_midi_output_write(card);
451}
452
453void
454snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
455
456{
457	unsigned long flags;
458
459	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
460	card->wavefront.midi.isvirtual = 1;
461	card->wavefront.midi.output_mpu = internal_mpu;
462	card->wavefront.midi.input_mpu = internal_mpu;
463	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
464}
465
466void
467snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
468
469{
470	unsigned long flags;
471
472	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
473	// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
474	// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
475	card->wavefront.midi.isvirtual = 0;
476	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
477}
478
479int
480snd_wavefront_midi_start (snd_wavefront_card_t *card)
481
482{
483	int ok, i;
484	unsigned char rbuf[4], wbuf[4];
485	snd_wavefront_t *dev;
486	snd_wavefront_midi_t *midi;
487
488	dev = &card->wavefront;
489	midi = &dev->midi;
490
491	/* The ICS2115 MPU-401 interface doesn't do anything
492	   until its set into UART mode.
493	*/
494
495	/* XXX fix me - no hard timing loops allowed! */
496
497	for (i = 0; i < 30000 && !output_ready (midi); i++);
498
499	if (!output_ready (midi)) {
500		snd_printk ("MIDI interface not ready for command\n");
501		return -1;
502	}
503
504	/* Any interrupts received from now on
505	   are owned by the MIDI side of things.
506	*/
507
508	dev->interrupts_are_midi = 1;
509	
510	outb (UART_MODE_ON, midi->mpu_command_port);
511
512	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
513		if (input_avail (midi)) {
514			if (read_data (midi) == MPU_ACK) {
515				ok = 1;
516				break;
517			}
518		}
519	}
520
521	if (!ok) {
522		snd_printk ("cannot set UART mode for MIDI interface");
523		dev->interrupts_are_midi = 0;
524		return -1;
525	}
526
527	/* Route external MIDI to WaveFront synth (by default) */
528    
529	if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
530		snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
531		/* XXX error ? */
532	}
533
534	/* Turn on Virtual MIDI, but first *always* turn it off,
535	   since otherwise consecutive reloads of the driver will
536	   never cause the hardware to generate the initial "internal" or 
537	   "external" source bytes in the MIDI data stream. This
538	   is pretty important, since the internal hardware generally will
539	   be used to generate none or very little MIDI output, and
540	   thus the only source of MIDI data is actually external. Without
541	   the switch bytes, the driver will think it all comes from
542	   the internal interface. Duh.
543	*/
544
545	if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
546		snd_printk ("virtual MIDI mode not disabled\n");
547		return 0; /* We're OK, but missing the external MIDI dev */
548	}
549
550	snd_wavefront_midi_enable_virtual (card);
551
552	if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
553		snd_printk ("cannot enable virtual MIDI mode.\n");
554		snd_wavefront_midi_disable_virtual (card);
555	} 
556	return 0;
557}
558
559const struct snd_rawmidi_ops snd_wavefront_midi_output =
560{
561	.open =		snd_wavefront_midi_output_open,
562	.close =	snd_wavefront_midi_output_close,
563	.trigger =	snd_wavefront_midi_output_trigger,
564};
565
566const struct snd_rawmidi_ops snd_wavefront_midi_input =
567{
568	.open =		snd_wavefront_midi_input_open,
569	.close =	snd_wavefront_midi_input_close,
570	.trigger =	snd_wavefront_midi_input_trigger,
571};
572