Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/wavefront/wavefront_midi.c
26424 views
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
54
static inline int
55
wf_mpu_status (snd_wavefront_midi_t *midi)
56
57
{
58
return inb (midi->mpu_status_port);
59
}
60
61
static inline int
62
input_avail (snd_wavefront_midi_t *midi)
63
64
{
65
return !(wf_mpu_status(midi) & INPUT_AVAIL);
66
}
67
68
static inline int
69
output_ready (snd_wavefront_midi_t *midi)
70
71
{
72
return !(wf_mpu_status(midi) & OUTPUT_READY);
73
}
74
75
static inline int
76
read_data (snd_wavefront_midi_t *midi)
77
78
{
79
return inb (midi->mpu_data_port);
80
}
81
82
static inline void
83
write_data (snd_wavefront_midi_t *midi, unsigned char byte)
84
85
{
86
outb (byte, midi->mpu_data_port);
87
}
88
89
static snd_wavefront_midi_t *
90
get_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
112
static 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
timer_delete(&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
timer_delete(&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
229
static 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
midi = get_wavefront_midi(substream);
243
if (!midi)
244
return -EIO;
245
246
spin_lock_irqsave (&midi->open, flags);
247
midi->mode[mpu] |= MPU401_MODE_INPUT;
248
midi->substream_input[mpu] = substream;
249
spin_unlock_irqrestore (&midi->open, flags);
250
251
return 0;
252
}
253
254
static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream)
255
{
256
unsigned long flags;
257
snd_wavefront_midi_t *midi;
258
snd_wavefront_mpu_id mpu;
259
260
if (snd_BUG_ON(!substream || !substream->rmidi))
261
return -ENXIO;
262
if (snd_BUG_ON(!substream->rmidi->private_data))
263
return -ENXIO;
264
265
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
266
267
midi = get_wavefront_midi(substream);
268
if (!midi)
269
return -EIO;
270
271
spin_lock_irqsave (&midi->open, flags);
272
midi->mode[mpu] |= MPU401_MODE_OUTPUT;
273
midi->substream_output[mpu] = substream;
274
spin_unlock_irqrestore (&midi->open, flags);
275
276
return 0;
277
}
278
279
static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
280
{
281
unsigned long flags;
282
snd_wavefront_midi_t *midi;
283
snd_wavefront_mpu_id mpu;
284
285
if (snd_BUG_ON(!substream || !substream->rmidi))
286
return -ENXIO;
287
if (snd_BUG_ON(!substream->rmidi->private_data))
288
return -ENXIO;
289
290
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
291
292
midi = get_wavefront_midi(substream);
293
if (!midi)
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
303
static 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
midi = get_wavefront_midi(substream);
317
if (!midi)
318
return -EIO;
319
320
spin_lock_irqsave (&midi->open, flags);
321
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
322
spin_unlock_irqrestore (&midi->open, flags);
323
return 0;
324
}
325
326
static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
327
{
328
unsigned long flags;
329
snd_wavefront_midi_t *midi;
330
snd_wavefront_mpu_id mpu;
331
332
if (substream == NULL || substream->rmidi == NULL)
333
return;
334
335
if (substream->rmidi->private_data == NULL)
336
return;
337
338
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
339
340
midi = get_wavefront_midi(substream);
341
if (!midi)
342
return;
343
344
spin_lock_irqsave (&midi->virtual, flags);
345
if (up) {
346
midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
347
} else {
348
midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
349
}
350
spin_unlock_irqrestore (&midi->virtual, flags);
351
}
352
353
static void snd_wavefront_midi_output_timer(struct timer_list *t)
354
{
355
snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer);
356
snd_wavefront_card_t *card = midi->timer_card;
357
unsigned long flags;
358
359
spin_lock_irqsave (&midi->virtual, flags);
360
mod_timer(&midi->timer, 1 + jiffies);
361
spin_unlock_irqrestore (&midi->virtual, flags);
362
snd_wavefront_midi_output_write(card);
363
}
364
365
static 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
midi = get_wavefront_midi(substream);
380
if (!midi)
381
return;
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
timer_setup(&midi->timer,
388
snd_wavefront_midi_output_timer,
389
0);
390
mod_timer(&midi->timer, 1 + jiffies);
391
}
392
midi->istimer++;
393
midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
394
}
395
} else {
396
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
397
}
398
spin_unlock_irqrestore (&midi->virtual, flags);
399
400
if (up)
401
snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
402
}
403
404
void
405
snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
406
407
{
408
unsigned long flags;
409
snd_wavefront_midi_t *midi;
410
static struct snd_rawmidi_substream *substream = NULL;
411
static int mpu = external_mpu;
412
int max = 128;
413
unsigned char byte;
414
415
midi = &card->wavefront.midi;
416
417
if (!input_avail (midi)) { /* not for us */
418
snd_wavefront_midi_output_write(card);
419
return;
420
}
421
422
spin_lock_irqsave (&midi->virtual, flags);
423
while (--max) {
424
425
if (input_avail (midi)) {
426
byte = read_data (midi);
427
428
if (midi->isvirtual) {
429
if (byte == WF_EXTERNAL_SWITCH) {
430
substream = midi->substream_input[external_mpu];
431
mpu = external_mpu;
432
} else if (byte == WF_INTERNAL_SWITCH) {
433
substream = midi->substream_output[internal_mpu];
434
mpu = internal_mpu;
435
} /* else just leave it as it is */
436
} else {
437
substream = midi->substream_input[internal_mpu];
438
mpu = internal_mpu;
439
}
440
441
if (substream == NULL) {
442
continue;
443
}
444
445
if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
446
snd_rawmidi_receive(substream, &byte, 1);
447
}
448
} else {
449
break;
450
}
451
}
452
spin_unlock_irqrestore (&midi->virtual, flags);
453
454
snd_wavefront_midi_output_write(card);
455
}
456
457
void
458
snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
459
460
{
461
unsigned long flags;
462
463
spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
464
card->wavefront.midi.isvirtual = 1;
465
card->wavefront.midi.output_mpu = internal_mpu;
466
card->wavefront.midi.input_mpu = internal_mpu;
467
spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
468
}
469
470
void
471
snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
472
473
{
474
unsigned long flags;
475
476
spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
477
// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
478
// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
479
card->wavefront.midi.isvirtual = 0;
480
spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
481
}
482
483
int
484
snd_wavefront_midi_start (snd_wavefront_card_t *card)
485
486
{
487
int ok, i;
488
unsigned char rbuf[4], wbuf[4];
489
snd_wavefront_t *dev;
490
snd_wavefront_midi_t *midi;
491
492
dev = &card->wavefront;
493
midi = &dev->midi;
494
495
/* The ICS2115 MPU-401 interface doesn't do anything
496
until its set into UART mode.
497
*/
498
499
/* XXX fix me - no hard timing loops allowed! */
500
501
for (i = 0; i < 30000 && !output_ready (midi); i++);
502
503
if (!output_ready (midi)) {
504
dev_err(card->wavefront.card->dev,
505
"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
dev_err(card->wavefront.card->dev,
528
"cannot set UART mode for MIDI interface");
529
dev->interrupts_are_midi = 0;
530
return -1;
531
}
532
533
/* Route external MIDI to WaveFront synth (by default) */
534
535
if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
536
dev_warn(card->wavefront.card->dev,
537
"can't enable MIDI-IN-2-synth routing.\n");
538
/* XXX error ? */
539
}
540
541
/* Turn on Virtual MIDI, but first *always* turn it off,
542
since otherwise consecutive reloads of the driver will
543
never cause the hardware to generate the initial "internal" or
544
"external" source bytes in the MIDI data stream. This
545
is pretty important, since the internal hardware generally will
546
be used to generate none or very little MIDI output, and
547
thus the only source of MIDI data is actually external. Without
548
the switch bytes, the driver will think it all comes from
549
the internal interface. Duh.
550
*/
551
552
if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) {
553
dev_warn(card->wavefront.card->dev,
554
"virtual MIDI mode not disabled\n");
555
return 0; /* We're OK, but missing the external MIDI dev */
556
}
557
558
snd_wavefront_midi_enable_virtual (card);
559
560
if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
561
dev_warn(card->wavefront.card->dev,
562
"cannot enable virtual MIDI mode.\n");
563
snd_wavefront_midi_disable_virtual (card);
564
}
565
return 0;
566
}
567
568
const struct snd_rawmidi_ops snd_wavefront_midi_output =
569
{
570
.open = snd_wavefront_midi_output_open,
571
.close = snd_wavefront_midi_output_close,
572
.trigger = snd_wavefront_midi_output_trigger,
573
};
574
575
const struct snd_rawmidi_ops snd_wavefront_midi_input =
576
{
577
.open = snd_wavefront_midi_input_open,
578
.close = snd_wavefront_midi_input_close,
579
.trigger = snd_wavefront_midi_input_trigger,
580
};
581
582
583