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