1*b8f9f700SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Copyright (C) by Paul Barton-Davis 1998-1999 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds /* The low level driver for the WaveFront ICS2115 MIDI interface(s) 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Note that there is also an MPU-401 emulation (actually, a UART-401 91da177e4SLinus Torvalds * emulation) on the CS4232 on the Tropez and Tropez Plus. This code 101da177e4SLinus Torvalds * has nothing to do with that interface at all. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * The interface is essentially just a UART-401, but is has the 131da177e4SLinus Torvalds * interesting property of supporting what Turtle Beach called 141da177e4SLinus Torvalds * "Virtual MIDI" mode. In this mode, there are effectively *two* 151da177e4SLinus Torvalds * MIDI buses accessible via the interface, one that is routed 161da177e4SLinus Torvalds * solely to/from the external WaveFront synthesizer and the other 171da177e4SLinus Torvalds * corresponding to the pin/socket connector used to link external 181da177e4SLinus Torvalds * MIDI devices to the board. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * This driver fully supports this mode, allowing two distinct MIDI 211da177e4SLinus Torvalds * busses to be used completely independently, giving 32 channels of 221da177e4SLinus Torvalds * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI 231da177e4SLinus Torvalds * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1, 241da177e4SLinus Torvalds * where `n' is the card number. Note that the device numbers may be 251da177e4SLinus Torvalds * something other than 0 and 1 if the CS4232 UART/MPU-401 interface 261da177e4SLinus Torvalds * is enabled. 271da177e4SLinus Torvalds * 281da177e4SLinus Torvalds * Switching between the two is accomplished externally by the driver 291da177e4SLinus Torvalds * using the two otherwise unused MIDI bytes. See the code for more details. 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c) 321da177e4SLinus Torvalds * 331da177e4SLinus Torvalds * The main reason to turn off Virtual MIDI mode is when you want to 341da177e4SLinus Torvalds * tightly couple the WaveFront synth with an external MIDI 351da177e4SLinus Torvalds * device. You won't be able to distinguish the source of any MIDI 361da177e4SLinus Torvalds * data except via SysEx ID, but thats probably OK, since for the most 371da177e4SLinus Torvalds * part, the WaveFront won't be sending any MIDI data at all. 381da177e4SLinus Torvalds * 391da177e4SLinus Torvalds * The main reason to turn on Virtual MIDI Mode is to provide two 401da177e4SLinus Torvalds * completely independent 16-channel MIDI buses, one to the 411da177e4SLinus Torvalds * WaveFront and one to any external MIDI devices. Given the 32 421da177e4SLinus Torvalds * voice nature of the WaveFront, its pretty easy to find a use 431da177e4SLinus Torvalds * for all 16 channels driving just that synth. 441da177e4SLinus Torvalds * 451da177e4SLinus Torvalds */ 461da177e4SLinus Torvalds 476cbbfe1cSTakashi Iwai #include <linux/io.h> 481da177e4SLinus Torvalds #include <linux/init.h> 491da177e4SLinus Torvalds #include <linux/time.h> 501da177e4SLinus Torvalds #include <linux/wait.h> 511da177e4SLinus Torvalds #include <sound/core.h> 521da177e4SLinus Torvalds #include <sound/snd_wavefront.h> 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds static inline int 551da177e4SLinus Torvalds wf_mpu_status (snd_wavefront_midi_t *midi) 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds { 581da177e4SLinus Torvalds return inb (midi->mpu_status_port); 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static inline int 621da177e4SLinus Torvalds input_avail (snd_wavefront_midi_t *midi) 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds return !(wf_mpu_status(midi) & INPUT_AVAIL); 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds static inline int 691da177e4SLinus Torvalds output_ready (snd_wavefront_midi_t *midi) 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds return !(wf_mpu_status(midi) & OUTPUT_READY); 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds static inline int 761da177e4SLinus Torvalds read_data (snd_wavefront_midi_t *midi) 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds return inb (midi->mpu_data_port); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static inline void 831da177e4SLinus Torvalds write_data (snd_wavefront_midi_t *midi, unsigned char byte) 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds outb (byte, midi->mpu_data_port); 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds static snd_wavefront_midi_t * 90542172f3STakashi Iwai get_wavefront_midi (struct snd_rawmidi_substream *substream) 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds { 93542172f3STakashi Iwai struct snd_card *card; 941da177e4SLinus Torvalds snd_wavefront_card_t *acard; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds if (substream == NULL || substream->rmidi == NULL) 971da177e4SLinus Torvalds return NULL; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds card = substream->rmidi->card; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds if (card == NULL) 1021da177e4SLinus Torvalds return NULL; 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds if (card->private_data == NULL) 1051da177e4SLinus Torvalds return NULL; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds acard = card->private_data; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds return &acard->wavefront.midi; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1121da177e4SLinus Torvalds static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds snd_wavefront_midi_t *midi = &card->wavefront.midi; 1151da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 1161da177e4SLinus Torvalds unsigned long flags; 1171da177e4SLinus Torvalds unsigned char midi_byte; 1181da177e4SLinus Torvalds int max = 256, mask = 1; 1191da177e4SLinus Torvalds int timeout; 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* Its not OK to try to change the status of "virtuality" of 1221da177e4SLinus Torvalds the MIDI interface while we're outputting stuff. See 1231da177e4SLinus Torvalds snd_wavefront_midi_{enable,disable}_virtual () for the 1241da177e4SLinus Torvalds other half of this. 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds The first loop attempts to flush any data from the 1271da177e4SLinus Torvalds current output device, and then the second 1281da177e4SLinus Torvalds emits the switch byte (if necessary), and starts 1291da177e4SLinus Torvalds outputting data for the output device currently in use. 1301da177e4SLinus Torvalds */ 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds if (midi->substream_output[midi->output_mpu] == NULL) { 1331da177e4SLinus Torvalds goto __second; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds while (max > 0) { 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* XXX fix me - no hard timing loops allowed! */ 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds for (timeout = 30000; timeout > 0; timeout--) { 1411da177e4SLinus Torvalds if (output_ready (midi)) 1421da177e4SLinus Torvalds break; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 1461da177e4SLinus Torvalds if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) { 1471da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 1481da177e4SLinus Torvalds goto __second; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds if (output_ready (midi)) { 1511da177e4SLinus Torvalds if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) { 1521da177e4SLinus Torvalds if (!midi->isvirtual || 1531da177e4SLinus Torvalds (midi_byte != WF_INTERNAL_SWITCH && 1541da177e4SLinus Torvalds midi_byte != WF_EXTERNAL_SWITCH)) 1551da177e4SLinus Torvalds write_data(midi, midi_byte); 1561da177e4SLinus Torvalds max--; 1571da177e4SLinus Torvalds } else { 1581da177e4SLinus Torvalds if (midi->istimer) { 1591da177e4SLinus Torvalds if (--midi->istimer <= 0) 1601da177e4SLinus Torvalds del_timer(&midi->timer); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 1631da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 1641da177e4SLinus Torvalds goto __second; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds } else { 1671da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 1681da177e4SLinus Torvalds return; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds __second: 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds if (midi->substream_output[!midi->output_mpu] == NULL) { 1761da177e4SLinus Torvalds return; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds while (max > 0) { 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /* XXX fix me - no hard timing loops allowed! */ 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds for (timeout = 30000; timeout > 0; timeout--) { 1841da177e4SLinus Torvalds if (output_ready (midi)) 1851da177e4SLinus Torvalds break; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 1891da177e4SLinus Torvalds if (!midi->isvirtual) 1901da177e4SLinus Torvalds mask = 0; 1911da177e4SLinus Torvalds mpu = midi->output_mpu ^ mask; 1921da177e4SLinus Torvalds mask = 0; /* don't invert the value from now */ 1931da177e4SLinus Torvalds if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) { 1941da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 1951da177e4SLinus Torvalds return; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds if (snd_rawmidi_transmit_empty(midi->substream_output[mpu])) 1981da177e4SLinus Torvalds goto __timer; 1991da177e4SLinus Torvalds if (output_ready (midi)) { 2001da177e4SLinus Torvalds if (mpu != midi->output_mpu) { 2011da177e4SLinus Torvalds write_data(midi, mpu == internal_mpu ? 2021da177e4SLinus Torvalds WF_INTERNAL_SWITCH : 2031da177e4SLinus Torvalds WF_EXTERNAL_SWITCH); 2041da177e4SLinus Torvalds midi->output_mpu = mpu; 2051da177e4SLinus Torvalds } else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) { 2061da177e4SLinus Torvalds if (!midi->isvirtual || 2071da177e4SLinus Torvalds (midi_byte != WF_INTERNAL_SWITCH && 2081da177e4SLinus Torvalds midi_byte != WF_EXTERNAL_SWITCH)) 2091da177e4SLinus Torvalds write_data(midi, midi_byte); 2101da177e4SLinus Torvalds max--; 2111da177e4SLinus Torvalds } else { 2121da177e4SLinus Torvalds __timer: 2131da177e4SLinus Torvalds if (midi->istimer) { 2141da177e4SLinus Torvalds if (--midi->istimer <= 0) 2151da177e4SLinus Torvalds del_timer(&midi->timer); 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 2181da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 2191da177e4SLinus Torvalds return; 2201da177e4SLinus Torvalds } 2211da177e4SLinus Torvalds } else { 2221da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 2231da177e4SLinus Torvalds return; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 229542172f3STakashi Iwai static int snd_wavefront_midi_input_open(struct snd_rawmidi_substream *substream) 2301da177e4SLinus Torvalds { 2311da177e4SLinus Torvalds unsigned long flags; 2321da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 2331da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 2341da177e4SLinus Torvalds 235622207dcSTakashi Iwai if (snd_BUG_ON(!substream || !substream->rmidi)) 236622207dcSTakashi Iwai return -ENXIO; 237622207dcSTakashi Iwai if (snd_BUG_ON(!substream->rmidi->private_data)) 238622207dcSTakashi Iwai return -ENXIO; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) 2431da177e4SLinus Torvalds return -EIO; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds spin_lock_irqsave (&midi->open, flags); 2461da177e4SLinus Torvalds midi->mode[mpu] |= MPU401_MODE_INPUT; 2471da177e4SLinus Torvalds midi->substream_input[mpu] = substream; 2481da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->open, flags); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds return 0; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 253542172f3STakashi Iwai static int snd_wavefront_midi_output_open(struct snd_rawmidi_substream *substream) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds unsigned long flags; 2561da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 2571da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 2581da177e4SLinus Torvalds 259622207dcSTakashi Iwai if (snd_BUG_ON(!substream || !substream->rmidi)) 260622207dcSTakashi Iwai return -ENXIO; 261622207dcSTakashi Iwai if (snd_BUG_ON(!substream->rmidi->private_data)) 262622207dcSTakashi Iwai return -ENXIO; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) 2671da177e4SLinus Torvalds return -EIO; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds spin_lock_irqsave (&midi->open, flags); 2701da177e4SLinus Torvalds midi->mode[mpu] |= MPU401_MODE_OUTPUT; 2711da177e4SLinus Torvalds midi->substream_output[mpu] = substream; 2721da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->open, flags); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds return 0; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 277542172f3STakashi Iwai static int snd_wavefront_midi_input_close(struct snd_rawmidi_substream *substream) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds unsigned long flags; 2801da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 2811da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 2821da177e4SLinus Torvalds 283622207dcSTakashi Iwai if (snd_BUG_ON(!substream || !substream->rmidi)) 284622207dcSTakashi Iwai return -ENXIO; 285622207dcSTakashi Iwai if (snd_BUG_ON(!substream->rmidi->private_data)) 286622207dcSTakashi Iwai return -ENXIO; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) 2911da177e4SLinus Torvalds return -EIO; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds spin_lock_irqsave (&midi->open, flags); 2941da177e4SLinus Torvalds midi->mode[mpu] &= ~MPU401_MODE_INPUT; 2951da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->open, flags); 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds return 0; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 300542172f3STakashi Iwai static int snd_wavefront_midi_output_close(struct snd_rawmidi_substream *substream) 3011da177e4SLinus Torvalds { 3021da177e4SLinus Torvalds unsigned long flags; 3031da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 3041da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 3051da177e4SLinus Torvalds 306622207dcSTakashi Iwai if (snd_BUG_ON(!substream || !substream->rmidi)) 307622207dcSTakashi Iwai return -ENXIO; 308622207dcSTakashi Iwai if (snd_BUG_ON(!substream->rmidi->private_data)) 309622207dcSTakashi Iwai return -ENXIO; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) 3141da177e4SLinus Torvalds return -EIO; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds spin_lock_irqsave (&midi->open, flags); 3171da177e4SLinus Torvalds midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; 3181da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->open, flags); 3191da177e4SLinus Torvalds return 0; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 322542172f3STakashi Iwai static void snd_wavefront_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds unsigned long flags; 3251da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 3261da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds if (substream == NULL || substream->rmidi == NULL) 3291da177e4SLinus Torvalds return; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds if (substream->rmidi->private_data == NULL) 3321da177e4SLinus Torvalds return; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) { 3371da177e4SLinus Torvalds return; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 3411da177e4SLinus Torvalds if (up) { 3421da177e4SLinus Torvalds midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER; 3431da177e4SLinus Torvalds } else { 3441da177e4SLinus Torvalds midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 34957e69e2fSKees Cook static void snd_wavefront_midi_output_timer(struct timer_list *t) 3501da177e4SLinus Torvalds { 35157e69e2fSKees Cook snd_wavefront_midi_t *midi = from_timer(midi, t, timer); 35257e69e2fSKees Cook snd_wavefront_card_t *card = midi->timer_card; 3531da177e4SLinus Torvalds unsigned long flags; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 356b843ce74STakashi Iwai mod_timer(&midi->timer, 1 + jiffies); 3571da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 3581da177e4SLinus Torvalds snd_wavefront_midi_output_write(card); 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds 361542172f3STakashi Iwai static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 3621da177e4SLinus Torvalds { 3631da177e4SLinus Torvalds unsigned long flags; 3641da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 3651da177e4SLinus Torvalds snd_wavefront_mpu_id mpu; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds if (substream == NULL || substream->rmidi == NULL) 3681da177e4SLinus Torvalds return; 3691da177e4SLinus Torvalds 3701da177e4SLinus Torvalds if (substream->rmidi->private_data == NULL) 3711da177e4SLinus Torvalds return; 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds if ((midi = get_wavefront_midi (substream)) == NULL) { 3761da177e4SLinus Torvalds return; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 3801da177e4SLinus Torvalds if (up) { 3811da177e4SLinus Torvalds if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { 3821da177e4SLinus Torvalds if (!midi->istimer) { 38357e69e2fSKees Cook timer_setup(&midi->timer, 384b843ce74STakashi Iwai snd_wavefront_midi_output_timer, 38557e69e2fSKees Cook 0); 386b843ce74STakashi Iwai mod_timer(&midi->timer, 1 + jiffies); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds midi->istimer++; 3891da177e4SLinus Torvalds midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds } else { 3921da177e4SLinus Torvalds midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds if (up) 3971da177e4SLinus Torvalds snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data); 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds void 4011da177e4SLinus Torvalds snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds unsigned long flags; 4051da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 406542172f3STakashi Iwai static struct snd_rawmidi_substream *substream = NULL; 4071da177e4SLinus Torvalds static int mpu = external_mpu; 4081da177e4SLinus Torvalds int max = 128; 4091da177e4SLinus Torvalds unsigned char byte; 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds midi = &card->wavefront.midi; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds if (!input_avail (midi)) { /* not for us */ 4141da177e4SLinus Torvalds snd_wavefront_midi_output_write(card); 4151da177e4SLinus Torvalds return; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds spin_lock_irqsave (&midi->virtual, flags); 4191da177e4SLinus Torvalds while (--max) { 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (input_avail (midi)) { 4221da177e4SLinus Torvalds byte = read_data (midi); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds if (midi->isvirtual) { 4251da177e4SLinus Torvalds if (byte == WF_EXTERNAL_SWITCH) { 4261da177e4SLinus Torvalds substream = midi->substream_input[external_mpu]; 4271da177e4SLinus Torvalds mpu = external_mpu; 4281da177e4SLinus Torvalds } else if (byte == WF_INTERNAL_SWITCH) { 4291da177e4SLinus Torvalds substream = midi->substream_output[internal_mpu]; 4301da177e4SLinus Torvalds mpu = internal_mpu; 4311da177e4SLinus Torvalds } /* else just leave it as it is */ 4321da177e4SLinus Torvalds } else { 4331da177e4SLinus Torvalds substream = midi->substream_input[internal_mpu]; 4341da177e4SLinus Torvalds mpu = internal_mpu; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds if (substream == NULL) { 4381da177e4SLinus Torvalds continue; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { 4421da177e4SLinus Torvalds snd_rawmidi_receive(substream, &byte, 1); 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds } else { 4451da177e4SLinus Torvalds break; 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds spin_unlock_irqrestore (&midi->virtual, flags); 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds snd_wavefront_midi_output_write(card); 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds void 4541da177e4SLinus Torvalds snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card) 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds { 4571da177e4SLinus Torvalds unsigned long flags; 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds spin_lock_irqsave (&card->wavefront.midi.virtual, flags); 4601da177e4SLinus Torvalds card->wavefront.midi.isvirtual = 1; 4611da177e4SLinus Torvalds card->wavefront.midi.output_mpu = internal_mpu; 4621da177e4SLinus Torvalds card->wavefront.midi.input_mpu = internal_mpu; 4631da177e4SLinus Torvalds spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds void 4671da177e4SLinus Torvalds snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds { 4701da177e4SLinus Torvalds unsigned long flags; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds spin_lock_irqsave (&card->wavefront.midi.virtual, flags); 4731da177e4SLinus Torvalds // snd_wavefront_midi_input_close (card->ics2115_external_rmidi); 4741da177e4SLinus Torvalds // snd_wavefront_midi_output_close (card->ics2115_external_rmidi); 4751da177e4SLinus Torvalds card->wavefront.midi.isvirtual = 0; 4761da177e4SLinus Torvalds spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); 4771da177e4SLinus Torvalds } 4781da177e4SLinus Torvalds 4791bff292eSBill Pemberton int 4801da177e4SLinus Torvalds snd_wavefront_midi_start (snd_wavefront_card_t *card) 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds { 4831da177e4SLinus Torvalds int ok, i; 4841da177e4SLinus Torvalds unsigned char rbuf[4], wbuf[4]; 4851da177e4SLinus Torvalds snd_wavefront_t *dev; 4861da177e4SLinus Torvalds snd_wavefront_midi_t *midi; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds dev = &card->wavefront; 4891da177e4SLinus Torvalds midi = &dev->midi; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds /* The ICS2115 MPU-401 interface doesn't do anything 4921da177e4SLinus Torvalds until its set into UART mode. 4931da177e4SLinus Torvalds */ 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds /* XXX fix me - no hard timing loops allowed! */ 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds for (i = 0; i < 30000 && !output_ready (midi); i++); 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds if (!output_ready (midi)) { 5001da177e4SLinus Torvalds snd_printk ("MIDI interface not ready for command\n"); 5011da177e4SLinus Torvalds return -1; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds /* Any interrupts received from now on 5051da177e4SLinus Torvalds are owned by the MIDI side of things. 5061da177e4SLinus Torvalds */ 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds dev->interrupts_are_midi = 1; 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds outb (UART_MODE_ON, midi->mpu_command_port); 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds for (ok = 0, i = 50000; i > 0 && !ok; i--) { 5131da177e4SLinus Torvalds if (input_avail (midi)) { 5141da177e4SLinus Torvalds if (read_data (midi) == MPU_ACK) { 5151da177e4SLinus Torvalds ok = 1; 5161da177e4SLinus Torvalds break; 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds if (!ok) { 5221da177e4SLinus Torvalds snd_printk ("cannot set UART mode for MIDI interface"); 5231da177e4SLinus Torvalds dev->interrupts_are_midi = 0; 5241da177e4SLinus Torvalds return -1; 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds /* Route external MIDI to WaveFront synth (by default) */ 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) { 5301da177e4SLinus Torvalds snd_printk ("can't enable MIDI-IN-2-synth routing.\n"); 5311da177e4SLinus Torvalds /* XXX error ? */ 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* Turn on Virtual MIDI, but first *always* turn it off, 53525985edcSLucas De Marchi since otherwise consecutive reloads of the driver will 5361da177e4SLinus Torvalds never cause the hardware to generate the initial "internal" or 5371da177e4SLinus Torvalds "external" source bytes in the MIDI data stream. This 5381da177e4SLinus Torvalds is pretty important, since the internal hardware generally will 5391da177e4SLinus Torvalds be used to generate none or very little MIDI output, and 5401da177e4SLinus Torvalds thus the only source of MIDI data is actually external. Without 5411da177e4SLinus Torvalds the switch bytes, the driver will think it all comes from 5421da177e4SLinus Torvalds the internal interface. Duh. 5431da177e4SLinus Torvalds */ 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { 5461da177e4SLinus Torvalds snd_printk ("virtual MIDI mode not disabled\n"); 5471da177e4SLinus Torvalds return 0; /* We're OK, but missing the external MIDI dev */ 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds snd_wavefront_midi_enable_virtual (card); 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) { 5531da177e4SLinus Torvalds snd_printk ("cannot enable virtual MIDI mode.\n"); 5541da177e4SLinus Torvalds snd_wavefront_midi_disable_virtual (card); 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds return 0; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5599021b2b8STakashi Iwai const struct snd_rawmidi_ops snd_wavefront_midi_output = 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds .open = snd_wavefront_midi_output_open, 5621da177e4SLinus Torvalds .close = snd_wavefront_midi_output_close, 5631da177e4SLinus Torvalds .trigger = snd_wavefront_midi_output_trigger, 5641da177e4SLinus Torvalds }; 5651da177e4SLinus Torvalds 5669021b2b8STakashi Iwai const struct snd_rawmidi_ops snd_wavefront_midi_input = 5671da177e4SLinus Torvalds { 5681da177e4SLinus Torvalds .open = snd_wavefront_midi_input_open, 5691da177e4SLinus Torvalds .close = snd_wavefront_midi_input_close, 5701da177e4SLinus Torvalds .trigger = snd_wavefront_midi_input_trigger, 5711da177e4SLinus Torvalds }; 5721da177e4SLinus Torvalds 573