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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) by Paul Barton-Davis 1998-1999
  4  */
  5 
  6 /* The low level driver for the WaveFront ICS2115 MIDI interface(s)
  7  *
  8  * Note that there is also an MPU-401 emulation (actually, a UART-401
  9  * emulation) on the CS4232 on the Tropez and Tropez Plus. This code
 10  * has nothing to do with that interface at all.
 11  *
 12  * The interface is essentially just a UART-401, but is has the
 13  * interesting property of supporting what Turtle Beach called
 14  * "Virtual MIDI" mode. In this mode, there are effectively *two*
 15  * MIDI buses accessible via the interface, one that is routed
 16  * solely to/from the external WaveFront synthesizer and the other
 17  * corresponding to the pin/socket connector used to link external
 18  * MIDI devices to the board.
 19  *
 20  * This driver fully supports this mode, allowing two distinct MIDI
 21  * busses to be used completely independently, giving 32 channels of
 22  * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI
 23  * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1,
 24  * where `n' is the card number. Note that the device numbers may be
 25  * something other than 0 and 1 if the CS4232 UART/MPU-401 interface
 26  * is enabled.
 27  *
 28  * Switching between the two is accomplished externally by the driver
 29  * using the two otherwise unused MIDI bytes. See the code for more details.
 30  *
 31  * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c)
 32  *
 33  * The main reason to turn off Virtual MIDI mode is when you want to
 34  * tightly couple the WaveFront synth with an external MIDI
 35  * device. You won't be able to distinguish the source of any MIDI
 36  * data except via SysEx ID, but thats probably OK, since for the most
 37  * part, the WaveFront won't be sending any MIDI data at all.
 38  *  
 39  * The main reason to turn on Virtual MIDI Mode is to provide two
 40  * completely independent 16-channel MIDI buses, one to the
 41  * WaveFront and one to any external MIDI devices. Given the 32
 42  * voice nature of the WaveFront, its pretty easy to find a use
 43  * for all 16 channels driving just that synth.
 44  *  
 45  */
 46 
 47 #include <linux/io.h>
 48 #include <linux/init.h>
 49 #include <linux/time.h>
 50 #include <linux/wait.h>
 51 #include <sound/core.h>
 52 #include <sound/snd_wavefront.h>
 53 
 54 static inline int 
 55 wf_mpu_status (snd_wavefront_midi_t *midi)
 56 
 57 {
 58         return inb (midi->mpu_status_port);
 59 }
 60 
 61 static inline int 
 62 input_avail (snd_wavefront_midi_t *midi)
 63 
 64 {
 65         return !(wf_mpu_status(midi) & INPUT_AVAIL);
 66 }
 67 
 68 static inline int
 69 output_ready (snd_wavefront_midi_t *midi)
 70 
 71 {
 72         return !(wf_mpu_status(midi) & OUTPUT_READY);
 73 }
 74 
 75 static inline int 
 76 read_data (snd_wavefront_midi_t *midi)
 77 
 78 {
 79         return inb (midi->mpu_data_port);
 80 }
 81 
 82 static inline void 
 83 write_data (snd_wavefront_midi_t *midi, unsigned char byte)
 84 
 85 {
 86         outb (byte, midi->mpu_data_port);
 87 }
 88 
 89 static snd_wavefront_midi_t *
 90 get_wavefront_midi (struct snd_rawmidi_substream *substream)
 91 
 92 {
 93         struct snd_card *card;
 94         snd_wavefront_card_t *acard;
 95 
 96         if (substream == NULL || substream->rmidi == NULL) 
 97                 return NULL;
 98 
 99         card = substream->rmidi->card;
100 
101         if (card == NULL) 
102                 return NULL;
103 
104         if (card->private_data == NULL) 
105                 return NULL;
106 
107         acard = card->private_data;
108 
109         return &acard->wavefront.midi;
110 }
111 
112 static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card)
113 {
114         snd_wavefront_midi_t *midi = &card->wavefront.midi;
115         snd_wavefront_mpu_id  mpu;
116         unsigned long flags;
117         unsigned char midi_byte;
118         int max = 256, mask = 1;
119         int timeout;
120 
121         /* Its not OK to try to change the status of "virtuality" of
122            the MIDI interface while we're outputting stuff.  See
123            snd_wavefront_midi_{enable,disable}_virtual () for the
124            other half of this.  
125 
126            The first loop attempts to flush any data from the
127            current output device, and then the second 
128            emits the switch byte (if necessary), and starts
129            outputting data for the output device currently in use.
130         */
131 
132         if (midi->substream_output[midi->output_mpu] == NULL) {
133                 goto __second;
134         }
135 
136         while (max > 0) {
137 
138                 /* XXX fix me - no hard timing loops allowed! */
139 
140                 for (timeout = 30000; timeout > 0; timeout--) {
141                         if (output_ready (midi))
142                                 break;
143                 }
144         
145                 spin_lock_irqsave (&midi->virtual, flags);
146                 if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) {
147                         spin_unlock_irqrestore (&midi->virtual, flags);
148                         goto __second;
149                 }
150                 if (output_ready (midi)) {
151                         if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) {
152                                 if (!midi->isvirtual ||
153                                         (midi_byte != WF_INTERNAL_SWITCH &&
154                                          midi_byte != WF_EXTERNAL_SWITCH))
155                                         write_data(midi, midi_byte);
156                                 max--;
157                         } else {
158                                 if (midi->istimer) {
159                                         if (--midi->istimer <= 0)
160                                                 del_timer(&midi->timer);
161                                 }
162                                 midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
163                                 spin_unlock_irqrestore (&midi->virtual, flags);
164                                 goto __second;
165                         }
166                 } else {
167                         spin_unlock_irqrestore (&midi->virtual, flags);
168                         return;
169                 }
170                 spin_unlock_irqrestore (&midi->virtual, flags);
171         }
172 
173       __second:
174 
175         if (midi->substream_output[!midi->output_mpu] == NULL) {
176                 return;
177         }
178 
179         while (max > 0) {
180 
181                 /* XXX fix me - no hard timing loops allowed! */
182 
183                 for (timeout = 30000; timeout > 0; timeout--) {
184                         if (output_ready (midi))
185                                 break;
186                 }
187         
188                 spin_lock_irqsave (&midi->virtual, flags);
189                 if (!midi->isvirtual)
190                         mask = 0;
191                 mpu = midi->output_mpu ^ mask;
192                 mask = 0;       /* don't invert the value from now */
193                 if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) {
194                         spin_unlock_irqrestore (&midi->virtual, flags);
195                         return;
196                 }
197                 if (snd_rawmidi_transmit_empty(midi->substream_output[mpu]))
198                         goto __timer;
199                 if (output_ready (midi)) {
200                         if (mpu != midi->output_mpu) {
201                                 write_data(midi, mpu == internal_mpu ?
202                                                         WF_INTERNAL_SWITCH :
203                                                         WF_EXTERNAL_SWITCH);
204                                 midi->output_mpu = mpu;
205                         } else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) {
206                                 if (!midi->isvirtual ||
207                                         (midi_byte != WF_INTERNAL_SWITCH &&
208                                          midi_byte != WF_EXTERNAL_SWITCH))
209                                         write_data(midi, midi_byte);
210                                 max--;
211                         } else {
212                               __timer:
213                                 if (midi->istimer) {
214                                         if (--midi->istimer <= 0)
215                                                 del_timer(&midi->timer);
216                                 }
217                                 midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
218                                 spin_unlock_irqrestore (&midi->virtual, flags);
219                                 return;
220                         }
221                 } else {
222                         spin_unlock_irqrestore (&midi->virtual, flags);
223                         return;
224                 }
225                 spin_unlock_irqrestore (&midi->virtual, flags);
226         }
227 }
228 
229 static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream)
230 {
231         unsigned long flags;
232         snd_wavefront_midi_t *midi;
233         snd_wavefront_mpu_id mpu;
234 
235         if (snd_BUG_ON(!substream || !substream->rmidi))
236                 return -ENXIO;
237         if (snd_BUG_ON(!substream->rmidi->private_data))
238                 return -ENXIO;
239 
240         mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
241 
242         midi = get_wavefront_midi(substream);
243         if (!midi)
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         if (snd_BUG_ON(!substream || !substream->rmidi))
261                 return -ENXIO;
262         if (snd_BUG_ON(!substream->rmidi->private_data))
263                 return -ENXIO;
264 
265         mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
266 
267         midi = get_wavefront_midi(substream);
268         if (!midi)
269                 return -EIO;
270 
271         spin_lock_irqsave (&midi->open, flags);
272         midi->mode[mpu] |= MPU401_MODE_OUTPUT;
273         midi->substream_output[mpu] = substream;
274         spin_unlock_irqrestore (&midi->open, flags);
275 
276         return 0;
277 }
278 
279 static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream)
280 {
281         unsigned long flags;
282         snd_wavefront_midi_t *midi;
283         snd_wavefront_mpu_id mpu;
284 
285         if (snd_BUG_ON(!substream || !substream->rmidi))
286                 return -ENXIO;
287         if (snd_BUG_ON(!substream->rmidi->private_data))
288                 return -ENXIO;
289 
290         mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
291 
292         midi = get_wavefront_midi(substream);
293         if (!midi)
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         midi = get_wavefront_midi(substream);
317         if (!midi)
318                 return -EIO;
319 
320         spin_lock_irqsave (&midi->open, flags);
321         midi->mode[mpu] &= ~MPU401_MODE_OUTPUT;
322         spin_unlock_irqrestore (&midi->open, flags);
323         return 0;
324 }
325 
326 static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
327 {
328         unsigned long flags;
329         snd_wavefront_midi_t *midi;
330         snd_wavefront_mpu_id mpu;
331 
332         if (substream == NULL || substream->rmidi == NULL) 
333                 return;
334 
335         if (substream->rmidi->private_data == NULL)
336                 return;
337 
338         mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data);
339 
340         midi = get_wavefront_midi(substream);
341         if (!midi)
342                 return;
343 
344         spin_lock_irqsave (&midi->virtual, flags);
345         if (up) {
346                 midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER;
347         } else {
348                 midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER;
349         }
350         spin_unlock_irqrestore (&midi->virtual, flags);
351 }
352 
353 static void snd_wavefront_midi_output_timer(struct timer_list *t)
354 {
355         snd_wavefront_midi_t *midi = from_timer(midi, t, timer);
356         snd_wavefront_card_t *card = midi->timer_card;
357         unsigned long flags;
358         
359         spin_lock_irqsave (&midi->virtual, flags);
360         mod_timer(&midi->timer, 1 + jiffies);
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         midi = get_wavefront_midi(substream);
380         if (!midi)
381                 return;
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                                 timer_setup(&midi->timer,
388                                             snd_wavefront_midi_output_timer,
389                                             0);
390                                 mod_timer(&midi->timer, 1 + jiffies);
391                         }
392                         midi->istimer++;
393                         midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
394                 }
395         } else {
396                 midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER;
397         }
398         spin_unlock_irqrestore (&midi->virtual, flags);
399 
400         if (up)
401                 snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data);
402 }
403 
404 void
405 snd_wavefront_midi_interrupt (snd_wavefront_card_t *card)
406 
407 {
408         unsigned long flags;
409         snd_wavefront_midi_t *midi;
410         static struct snd_rawmidi_substream *substream = NULL;
411         static int mpu = external_mpu; 
412         int max = 128;
413         unsigned char byte;
414 
415         midi = &card->wavefront.midi;
416 
417         if (!input_avail (midi)) { /* not for us */
418                 snd_wavefront_midi_output_write(card);
419                 return;
420         }
421 
422         spin_lock_irqsave (&midi->virtual, flags);
423         while (--max) {
424 
425                 if (input_avail (midi)) {
426                         byte = read_data (midi);
427 
428                         if (midi->isvirtual) {                          
429                                 if (byte == WF_EXTERNAL_SWITCH) {
430                                         substream = midi->substream_input[external_mpu];
431                                         mpu = external_mpu;
432                                 } else if (byte == WF_INTERNAL_SWITCH) { 
433                                         substream = midi->substream_output[internal_mpu];
434                                         mpu = internal_mpu;
435                                 } /* else just leave it as it is */
436                         } else {
437                                 substream = midi->substream_input[internal_mpu];
438                                 mpu = internal_mpu;
439                         }
440 
441                         if (substream == NULL) {
442                                 continue;
443                         }
444 
445                         if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) {
446                                 snd_rawmidi_receive(substream, &byte, 1);
447                         }
448                 } else {
449                         break;
450                 }
451         } 
452         spin_unlock_irqrestore (&midi->virtual, flags);
453 
454         snd_wavefront_midi_output_write(card);
455 }
456 
457 void
458 snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card)
459 
460 {
461         unsigned long flags;
462 
463         spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
464         card->wavefront.midi.isvirtual = 1;
465         card->wavefront.midi.output_mpu = internal_mpu;
466         card->wavefront.midi.input_mpu = internal_mpu;
467         spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
468 }
469 
470 void
471 snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card)
472 
473 {
474         unsigned long flags;
475 
476         spin_lock_irqsave (&card->wavefront.midi.virtual, flags);
477         // snd_wavefront_midi_input_close (card->ics2115_external_rmidi);
478         // snd_wavefront_midi_output_close (card->ics2115_external_rmidi);
479         card->wavefront.midi.isvirtual = 0;
480         spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags);
481 }
482 
483 int
484 snd_wavefront_midi_start (snd_wavefront_card_t *card)
485 
486 {
487         int ok, i;
488         unsigned char rbuf[4], wbuf[4];
489         snd_wavefront_t *dev;
490         snd_wavefront_midi_t *midi;
491 
492         dev = &card->wavefront;
493         midi = &dev->midi;
494 
495         /* The ICS2115 MPU-401 interface doesn't do anything
496            until its set into UART mode.
497         */
498 
499         /* XXX fix me - no hard timing loops allowed! */
500 
501         for (i = 0; i < 30000 && !output_ready (midi); i++);
502 
503         if (!output_ready (midi)) {
504                 snd_printk ("MIDI interface not ready for command\n");
505                 return -1;
506         }
507 
508         /* Any interrupts received from now on
509            are owned by the MIDI side of things.
510         */
511 
512         dev->interrupts_are_midi = 1;
513         
514         outb (UART_MODE_ON, midi->mpu_command_port);
515 
516         for (ok = 0, i = 50000; i > 0 && !ok; i--) {
517                 if (input_avail (midi)) {
518                         if (read_data (midi) == MPU_ACK) {
519                                 ok = 1;
520                                 break;
521                         }
522                 }
523         }
524 
525         if (!ok) {
526                 snd_printk ("cannot set UART mode for MIDI interface");
527                 dev->interrupts_are_midi = 0;
528                 return -1;
529         }
530 
531         /* Route external MIDI to WaveFront synth (by default) */
532     
533         if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) {
534                 snd_printk ("can't enable MIDI-IN-2-synth routing.\n");
535                 /* XXX error ? */
536         }
537 
538         /* Turn on Virtual MIDI, but first *always* turn it off,
539            since otherwise consecutive reloads of the driver will
540            never cause the hardware to generate the initial "internal" or 
541            "external" source bytes in the MIDI data stream. This
542            is pretty important, since the internal hardware generally will
543            be used to generate none or very little MIDI output, and
544            thus the only source of MIDI data is actually external. Without
545            the switch bytes, the driver will think it all comes from
546            the internal interface. Duh.
547         */
548 
549         if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 
550                 snd_printk ("virtual MIDI mode not disabled\n");
551                 return 0; /* We're OK, but missing the external MIDI dev */
552         }
553 
554         snd_wavefront_midi_enable_virtual (card);
555 
556         if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) {
557                 snd_printk ("cannot enable virtual MIDI mode.\n");
558                 snd_wavefront_midi_disable_virtual (card);
559         } 
560         return 0;
561 }
562 
563 const struct snd_rawmidi_ops snd_wavefront_midi_output =
564 {
565         .open =         snd_wavefront_midi_output_open,
566         .close =        snd_wavefront_midi_output_close,
567         .trigger =      snd_wavefront_midi_output_trigger,
568 };
569 
570 const struct snd_rawmidi_ops snd_wavefront_midi_input =
571 {
572         .open =         snd_wavefront_midi_input_open,
573         .close =        snd_wavefront_midi_input_close,
574         .trigger =      snd_wavefront_midi_input_trigger,
575 };
576 
577 

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php