File Index
Files and directories
Sign in
FILE

wavefront_midi.c

File preview with syntax highlighting.

linux-6.19.14/sound/isa/wavefront/wavefront_midi.c C
  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 char midi_byte;
117	int max = 256, mask = 1;
118	int timeout;
119
120	/* Its not OK to try to change the status of "virtuality" of
121	   the MIDI interface while we're outputting stuff.  See
122	   snd_wavefront_midi_{enable,disable}_virtual () for the
123	   other half of this.  
124
125	   The first loop attempts to flush any data from the
126	   current output device, and then the second 
127	   emits the switch byte (if necessary), and starts
128	   outputting data for the output device currently in use.
129	*/
130
131	if (midi->substream_output[midi->output_mpu] == NULL) {
132		goto __second;
133	}
134
135	while (max > 0) {
136
137		/* XXX fix me - no hard timing loops allowed! */
138
139		for (timeout = 30000; timeout > 0; timeout--) {
140			if (output_ready (midi))
141				break;
142		}
143	
144		guard(spinlock_irqsave)(&midi->virtual);
145		if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0)
146			goto __second;
147		if (output_ready (midi)) {
148			if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
149				if (!midi->isvirtual ||
150					(midi_byte != WF_INTERNAL_SWITCH &&
151					 midi_byte != WF_EXTERNAL_SWITCH))
152					write_data(midi, midi_byte);
153				max--;
154			} else {
155				if (midi->istimer) {
156					if (--midi->istimer <= 0)
157						timer_delete(&midi->timer);
158				}
159				midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
160				goto __second;
161			}
162		} else {
163			return;
164		}
165	}
166
167      __second:
168
169	if (midi->substream_output[!midi->output_mpu] == NULL) {
170		return;
171	}
172
173	while (max > 0) {
174
175		/* XXX fix me - no hard timing loops allowed! */
176
177		for (timeout = 30000; timeout > 0; timeout--) {
178			if (output_ready (midi))
179				break;
180		}
181	
182		guard(spinlock_irqsave)(&midi->virtual);
183		if (!midi->isvirtual)
184			mask = 0;
185		mpu = midi->output_mpu ^ mask;
186		mask = 0;	/* don't invert the value from now */
187		if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0)
188			return;
189		if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
190			goto __timer;
191		if (output_ready (midi)) {
192			if (mpu != midi->output_mpu) {
193				write_data(midi, mpu == internal_mpu ?
194							WF_INTERNAL_SWITCH :
195							WF_EXTERNAL_SWITCH);
196				midi->output_mpu = mpu;
197			} else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
198				if (!midi->isvirtual ||
199					(midi_byte != WF_INTERNAL_SWITCH &&
200					 midi_byte != WF_EXTERNAL_SWITCH))
201					write_data(midi, midi_byte);
202				max--;
203			} else {
204			      __timer:
205				if (midi->istimer) {
206					if (--midi->istimer <= 0)
207						timer_delete(&midi->timer);
208				}
209				midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
210				return;
211			}
212		} else {
213			return;
214		}
215	}
216}
217
218static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
219{
220	snd_wavefront_midi_t *midi;
221	snd_wavefront_mpu_id mpu;
222
223	if (snd_BUG_ON(!substream || !substream->rmidi))
224		return -ENXIO;
225	if (snd_BUG_ON(!substream->rmidi->private_data))
226		return -ENXIO;
227
228	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
229
230	midi = get_wavefront_midi(substream);
231	if (!midi)
232	        return -EIO;
233
234	guard(spinlock_irqsave)(&midi->open);
235	midi->mode[mpu] |= MPU401_MODE_INPUT;
236	midi->substream_input[mpu] = substream;
237
238	return 0;
239}
240
241static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
242{
243	snd_wavefront_midi_t *midi;
244	snd_wavefront_mpu_id mpu;
245
246	if (snd_BUG_ON(!substream || !substream->rmidi))
247		return -ENXIO;
248	if (snd_BUG_ON(!substream->rmidi->private_data))
249		return -ENXIO;
250
251	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
252
253	midi = get_wavefront_midi(substream);
254	if (!midi)
255	        return -EIO;
256
257	guard(spinlock_irqsave)(&midi->open);
258	midi->mode[mpu] |= MPU401_MODE_OUTPUT;
259	midi->substream_output[mpu] = substream;
260
261	return 0;
262}
263
264static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
265{
266	snd_wavefront_midi_t *midi;
267	snd_wavefront_mpu_id mpu;
268
269	if (snd_BUG_ON(!substream || !substream->rmidi))
270		return -ENXIO;
271	if (snd_BUG_ON(!substream->rmidi->private_data))
272		return -ENXIO;
273
274	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
275
276	midi = get_wavefront_midi(substream);
277	if (!midi)
278	        return -EIO;
279
280	guard(spinlock_irqsave)(&midi->open);
281	midi->substream_input[mpu] = NULL;
282	midi->mode[mpu] &= ~MPU401_MODE_INPUT;
283
284	return 0;
285}
286
287static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
288{
289	snd_wavefront_midi_t *midi;
290	snd_wavefront_mpu_id mpu;
291
292	if (snd_BUG_ON(!substream || !substream->rmidi))
293		return -ENXIO;
294	if (snd_BUG_ON(!substream->rmidi->private_data))
295		return -ENXIO;
296
297	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
298
299	midi = get_wavefront_midi(substream);
300	if (!midi)
301	        return -EIO;
302
303	guard(spinlock_irqsave)(&midi->open);
304	midi->substream_output[mpu] = NULL;
305	midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
306	return 0;
307}
308
309static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
310{
311	snd_wavefront_midi_t *midi;
312	snd_wavefront_mpu_id mpu;
313
314	if (substream == NULL || substream->rmidi == NULL) 
315	        return;
316
317	if (substream->rmidi->private_data == NULL)
318	        return;
319
320	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
321
322	midi = get_wavefront_midi(substream);
323	if (!midi)
324		return;
325
326	guard(spinlock_irqsave)(&midi->virtual);
327	if (up) {
328		midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
329	} else {
330		midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
331	}
332}
333
334static void snd_wavefront_midi_output_timer(struct timer_list *t)
335{
336	snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer);
337	snd_wavefront_card_t *card = midi->timer_card;
338	
339	scoped_guard(spinlock_irqsave, &midi->virtual) {
340		mod_timer(&midi->timer, 1 + jiffies);
341	}
342	snd_wavefront_midi_output_write(card);
343}
344
345static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
346{
347	snd_wavefront_midi_t *midi;
348	snd_wavefront_mpu_id mpu;
349
350	if (substream == NULL || substream->rmidi == NULL) 
351	        return;
352
353	if (substream->rmidi->private_data == NULL)
354	        return;
355
356	mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
357
358	midi = get_wavefront_midi(substream);
359	if (!midi)
360		return;
361
362	scoped_guard(spinlock_irqsave, &midi->virtual) {
363		if (up) {
364			if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
365				if (!midi->istimer) {
366					timer_setup(&midi->timer,
367						    snd_wavefront_midi_output_timer,
368						    0);
369					mod_timer(&midi->timer, 1 + jiffies);
370				}
371				midi->istimer++;
372				midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
373			}
374		} else {
375			midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
376		}
377	}
378
379	if (up)
380		snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
381}
382
383void
384snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
385
386{
387	snd_wavefront_midi_t *midi;
388	static struct snd_rawmidi_substream *substream = NULL;
389	static int mpu = external_mpu; 
390	int max = 128;
391	unsigned char byte;
392
393	midi = &card->wavefront.midi;
394
395	if (!input_avail (midi)) { /* not for us */
396		snd_wavefront_midi_output_write(card);
397		return;
398	}
399
400	scoped_guard(spinlock_irqsave, &midi->virtual) {
401		while (--max) {
402
403			if (input_avail(midi)) {
404				byte = read_data(midi);
405
406				if (midi->isvirtual) {
407					if (byte == WF_EXTERNAL_SWITCH) {
408						substream = midi->substream_input[external_mpu];
409						mpu = external_mpu;
410					} else if (byte == WF_INTERNAL_SWITCH) {
411						substream = midi->substream_output[internal_mpu];
412						mpu = internal_mpu;
413					} /* else just leave it as it is */
414				} else {
415					substream = midi->substream_input[internal_mpu];
416					mpu = internal_mpu;
417				}
418
419				if (substream == NULL) {
420					continue;
421				}
422
423				if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
424					snd_rawmidi_receive(substream, &byte, 1);
425				}
426			} else {
427				break;
428			}
429		}
430	}
431
432	snd_wavefront_midi_output_write(card);
433}
434
435void
436snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
437
438{
439	unsigned long flags;
440
441	spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
442	card->wavefront.midi.isvirtual = 1;
443	card->wavefront.midi.output_mpu = internal_mpu;
444	card->wavefront.midi.input_mpu = internal_mpu;
445	spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
446}
447
448void
449snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
450
451{
452	guard(spinlock_irqsave)(&card->wavefront.midi.virtual);
453	// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
454	// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
455	card->wavefront.midi.isvirtual = 0;
456}
457
458int
459snd_wavefront_midi_start (snd_wavefront_card_t *card)
460
461{
462	int ok, i;
463	unsigned char rbuf[4], wbuf[4];
464	snd_wavefront_t *dev;
465	snd_wavefront_midi_t *midi;
466
467	dev = &card->wavefront;
468	midi = &dev->midi;
469
470	/* The ICS2115 MPU-401 interface doesn't do anything
471	   until its set into UART mode.
472	*/
473
474	/* XXX fix me - no hard timing loops allowed! */
475
476	for (i = 0; i < 30000 && !output_ready (midi); i++);
477
478	if (!output_ready (midi)) {
479		dev_err(card->wavefront.card->dev,
480			"MIDI interface not ready for command\n");
481		return -1;
482	}
483
484	/* Any interrupts received from now on
485	   are owned by the MIDI side of things.
486	*/
487
488	dev->interrupts_are_midi = 1;
489	
490	outb (UART_MODE_ON, midi->mpu_command_port);
491
492	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
493		if (input_avail (midi)) {
494			if (read_data (midi) == MPU_ACK) {
495				ok = 1;
496				break;
497			}
498		}
499	}
500
501	if (!ok) {
502		dev_err(card->wavefront.card->dev,
503			"cannot set UART mode for MIDI interface");
504		dev->interrupts_are_midi = 0;
505		return -1;
506	}
507
508	/* Route external MIDI to WaveFront synth (by default) */
509    
510	if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
511		dev_warn(card->wavefront.card->dev,
512			 "can't enable MIDI-IN-2-synth routing.\n");
513		/* XXX error ? */
514	}
515
516	/* Turn on Virtual MIDI, but first *always* turn it off,
517	   since otherwise consecutive reloads of the driver will
518	   never cause the hardware to generate the initial "internal" or 
519	   "external" source bytes in the MIDI data stream. This
520	   is pretty important, since the internal hardware generally will
521	   be used to generate none or very little MIDI output, and
522	   thus the only source of MIDI data is actually external. Without
523	   the switch bytes, the driver will think it all comes from
524	   the internal interface. Duh.
525	*/
526
527	if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
528		dev_warn(card->wavefront.card->dev,
529			 "virtual MIDI mode not disabled\n");
530		return 0; /* We're OK, but missing the external MIDI dev */
531	}
532
533	snd_wavefront_midi_enable_virtual (card);
534
535	if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
536		dev_warn(card->wavefront.card->dev,
537			 "cannot enable virtual MIDI mode.\n");
538		snd_wavefront_midi_disable_virtual (card);
539	} 
540	return 0;
541}
542
543const struct snd_rawmidi_ops snd_wavefront_midi_output =
544{
545	.open =		snd_wavefront_midi_output_open,
546	.close =	snd_wavefront_midi_output_close,
547	.trigger =	snd_wavefront_midi_output_trigger,
548};
549
550const struct snd_rawmidi_ops snd_wavefront_midi_input =
551{
552	.open =		snd_wavefront_midi_input_open,
553	.close =	snd_wavefront_midi_input_close,
554	.trigger =	snd_wavefront_midi_input_trigger,
555};
556
~/ Read-only file preview.