Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/wavefront/wavefront_midi.c
29266 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 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
218
static 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
241
static 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
264
static 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->mode[mpu] &= ~MPU401_MODE_INPUT;
282
283
return 0;
284
}
285
286
static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream)
287
{
288
snd_wavefront_midi_t *midi;
289
snd_wavefront_mpu_id mpu;
290
291
if (snd_BUG_ON(!substream || !substream->rmidi))
292
return -ENXIO;
293
if (snd_BUG_ON(!substream->rmidi->private_data))
294
return -ENXIO;
295
296
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
297
298
midi = get_wavefront_midi(substream);
299
if (!midi)
300
return -EIO;
301
302
guard(spinlock_irqsave)(&midi->open);
303
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
304
return 0;
305
}
306
307
static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
308
{
309
snd_wavefront_midi_t *midi;
310
snd_wavefront_mpu_id mpu;
311
312
if (substream == NULL || substream->rmidi == NULL)
313
return;
314
315
if (substream->rmidi->private_data == NULL)
316
return;
317
318
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
319
320
midi = get_wavefront_midi(substream);
321
if (!midi)
322
return;
323
324
guard(spinlock_irqsave)(&midi->virtual);
325
if (up) {
326
midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
327
} else {
328
midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
329
}
330
}
331
332
static void snd_wavefront_midi_output_timer(struct timer_list *t)
333
{
334
snd_wavefront_midi_t *midi = timer_container_of(midi, t, timer);
335
snd_wavefront_card_t *card = midi->timer_card;
336
337
scoped_guard(spinlock_irqsave, &midi->virtual) {
338
mod_timer(&midi->timer, 1 + jiffies);
339
}
340
snd_wavefront_midi_output_write(card);
341
}
342
343
static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
344
{
345
snd_wavefront_midi_t *midi;
346
snd_wavefront_mpu_id mpu;
347
348
if (substream == NULL || substream->rmidi == NULL)
349
return;
350
351
if (substream->rmidi->private_data == NULL)
352
return;
353
354
mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
355
356
midi = get_wavefront_midi(substream);
357
if (!midi)
358
return;
359
360
scoped_guard(spinlock_irqsave, &midi->virtual) {
361
if (up) {
362
if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
363
if (!midi->istimer) {
364
timer_setup(&midi->timer,
365
snd_wavefront_midi_output_timer,
366
0);
367
mod_timer(&midi->timer, 1 + jiffies);
368
}
369
midi->istimer++;
370
midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
371
}
372
} else {
373
midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
374
}
375
}
376
377
if (up)
378
snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
379
}
380
381
void
382
snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
383
384
{
385
snd_wavefront_midi_t *midi;
386
static struct snd_rawmidi_substream *substream = NULL;
387
static int mpu = external_mpu;
388
int max = 128;
389
unsigned char byte;
390
391
midi = &card->wavefront.midi;
392
393
if (!input_avail (midi)) { /* not for us */
394
snd_wavefront_midi_output_write(card);
395
return;
396
}
397
398
scoped_guard(spinlock_irqsave, &midi->virtual) {
399
while (--max) {
400
401
if (input_avail(midi)) {
402
byte = read_data(midi);
403
404
if (midi->isvirtual) {
405
if (byte == WF_EXTERNAL_SWITCH) {
406
substream = midi->substream_input[external_mpu];
407
mpu = external_mpu;
408
} else if (byte == WF_INTERNAL_SWITCH) {
409
substream = midi->substream_output[internal_mpu];
410
mpu = internal_mpu;
411
} /* else just leave it as it is */
412
} else {
413
substream = midi->substream_input[internal_mpu];
414
mpu = internal_mpu;
415
}
416
417
if (substream == NULL) {
418
continue;
419
}
420
421
if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
422
snd_rawmidi_receive(substream, &byte, 1);
423
}
424
} else {
425
break;
426
}
427
}
428
}
429
430
snd_wavefront_midi_output_write(card);
431
}
432
433
void
434
snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
435
436
{
437
unsigned long flags;
438
439
spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
440
card->wavefront.midi.isvirtual = 1;
441
card->wavefront.midi.output_mpu = internal_mpu;
442
card->wavefront.midi.input_mpu = internal_mpu;
443
spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
444
}
445
446
void
447
snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
448
449
{
450
guard(spinlock_irqsave)(&card->wavefront.midi.virtual);
451
// snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
452
// snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
453
card->wavefront.midi.isvirtual = 0;
454
}
455
456
int
457
snd_wavefront_midi_start (snd_wavefront_card_t *card)
458
459
{
460
int ok, i;
461
unsigned char rbuf[4], wbuf[4];
462
snd_wavefront_t *dev;
463
snd_wavefront_midi_t *midi;
464
465
dev = &card->wavefront;
466
midi = &dev->midi;
467
468
/* The ICS2115 MPU-401 interface doesn't do anything
469
until its set into UART mode.
470
*/
471
472
/* XXX fix me - no hard timing loops allowed! */
473
474
for (i = 0; i < 30000 && !output_ready (midi); i++);
475
476
if (!output_ready (midi)) {
477
dev_err(card->wavefront.card->dev,
478
"MIDI interface not ready for command\n");
479
return -1;
480
}
481
482
/* Any interrupts received from now on
483
are owned by the MIDI side of things.
484
*/
485
486
dev->interrupts_are_midi = 1;
487
488
outb (UART_MODE_ON, midi->mpu_command_port);
489
490
for (ok = 0, i = 50000; i > 0 && !ok; i--) {
491
if (input_avail (midi)) {
492
if (read_data (midi) == MPU_ACK) {
493
ok = 1;
494
break;
495
}
496
}
497
}
498
499
if (!ok) {
500
dev_err(card->wavefront.card->dev,
501
"cannot set UART mode for MIDI interface");
502
dev->interrupts_are_midi = 0;
503
return -1;
504
}
505
506
/* Route external MIDI to WaveFront synth (by default) */
507
508
if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
509
dev_warn(card->wavefront.card->dev,
510
"can't enable MIDI-IN-2-synth routing.\n");
511
/* XXX error ? */
512
}
513
514
/* Turn on Virtual MIDI, but first *always* turn it off,
515
since otherwise consecutive reloads of the driver will
516
never cause the hardware to generate the initial "internal" or
517
"external" source bytes in the MIDI data stream. This
518
is pretty important, since the internal hardware generally will
519
be used to generate none or very little MIDI output, and
520
thus the only source of MIDI data is actually external. Without
521
the switch bytes, the driver will think it all comes from
522
the internal interface. Duh.
523
*/
524
525
if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) {
526
dev_warn(card->wavefront.card->dev,
527
"virtual MIDI mode not disabled\n");
528
return 0; /* We're OK, but missing the external MIDI dev */
529
}
530
531
snd_wavefront_midi_enable_virtual (card);
532
533
if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
534
dev_warn(card->wavefront.card->dev,
535
"cannot enable virtual MIDI mode.\n");
536
snd_wavefront_midi_disable_virtual (card);
537
}
538
return 0;
539
}
540
541
const struct snd_rawmidi_ops snd_wavefront_midi_output =
542
{
543
.open = snd_wavefront_midi_output_open,
544
.close = snd_wavefront_midi_output_close,
545
.trigger = snd_wavefront_midi_output_trigger,
546
};
547
548
const struct snd_rawmidi_ops snd_wavefront_midi_input =
549
{
550
.open = snd_wavefront_midi_input_open,
551
.close = snd_wavefront_midi_input_close,
552
.trigger = snd_wavefront_midi_input_trigger,
553
};
554
555
556