Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/isa/wavefront/wavefront_midi.c
10817 views
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
57
static inline int
58
wf_mpu_status (snd_wavefront_midi_t *midi)
59
60
{
61
return inb (midi->mpu_status_port);
62
}
63
64
static inline int
65
input_avail (snd_wavefront_midi_t *midi)
66
67
{
68
return !(wf_mpu_status(midi) & INPUT_AVAIL);
69
}
70
71
static inline int
72
output_ready (snd_wavefront_midi_t *midi)
73
74
{
75
return !(wf_mpu_status(midi) & OUTPUT_READY);
76
}
77
78
static inline int
79
read_data (snd_wavefront_midi_t *midi)
80
81
{
82
return inb (midi->mpu_data_port);
83
}
84
85
static inline void
86
write_data (snd_wavefront_midi_t *midi, unsigned char byte)
87
88
{
89
outb (byte, midi->mpu_data_port);
90
}
91
92
static snd_wavefront_midi_t *
93
get_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
115
static 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
232
static 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
256
static 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
280
static 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
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
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
325
static 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
352
static 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
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
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
405
void
406
snd_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
458
void
459
snd_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
471
void
472
snd_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
484
int __devinit
485
snd_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
564
struct 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
571
struct 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
578
579