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