~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/isa/wavefront/wavefront_midi.c

Version: ~ [ linux-5.10-rc6 ] ~ [ linux-5.9.12 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.81 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.161 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.210 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.247 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.247 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp