]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/isa/wavefront/wavefront_midi.c
ALSA: Kill snd_assert() in sound/isa/*
[linux-2.6-omap-h63xx.git] / sound / isa / wavefront / wavefront_midi.c
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 consectutive 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