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