1d056fa04SAlexander Leidinger /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 4d056fa04SAlexander Leidinger * Copyright (c) 1999 Seigo Tanimura 5498a9afeSJoel Dahl * Copyright (c) 2003 Mathew Kanner 6d056fa04SAlexander Leidinger * Copyright (c) 2003-2006 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> 7d056fa04SAlexander Leidinger * All rights reserved 8d056fa04SAlexander Leidinger * 9d056fa04SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 10d056fa04SAlexander Leidinger * modification, are permitted provided that the following conditions 11d056fa04SAlexander Leidinger * are met: 12d056fa04SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 13d056fa04SAlexander Leidinger * notice, this list of conditions and the following disclaimer. 14d056fa04SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 15d056fa04SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 16d056fa04SAlexander Leidinger * documentation and/or other materials provided with the distribution. 17d056fa04SAlexander Leidinger * 18d056fa04SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19d056fa04SAlexander Leidinger * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20d056fa04SAlexander Leidinger * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21d056fa04SAlexander Leidinger * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22d056fa04SAlexander Leidinger * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23d056fa04SAlexander Leidinger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24d056fa04SAlexander Leidinger * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25d056fa04SAlexander Leidinger * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26d056fa04SAlexander Leidinger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27d056fa04SAlexander Leidinger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28d056fa04SAlexander Leidinger * SUCH DAMAGE. 29d056fa04SAlexander Leidinger */ 30d056fa04SAlexander Leidinger 31d056fa04SAlexander Leidinger #include <sys/param.h> 32d056fa04SAlexander Leidinger #include <sys/types.h> 33d056fa04SAlexander Leidinger #include <sys/bus.h> 34d056fa04SAlexander Leidinger #include <machine/bus.h> 35d056fa04SAlexander Leidinger #include <sys/rman.h> 36d056fa04SAlexander Leidinger #include <sys/systm.h> 37d056fa04SAlexander Leidinger #include <sys/sbuf.h> 38d056fa04SAlexander Leidinger #include <sys/queue.h> 39d056fa04SAlexander Leidinger #include <sys/lock.h> 40d056fa04SAlexander Leidinger #include <sys/mutex.h> 41d056fa04SAlexander Leidinger 4290da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS 4390da2b28SAriff Abdullah #include "opt_snd.h" 4490da2b28SAriff Abdullah #endif 4590da2b28SAriff Abdullah 46d056fa04SAlexander Leidinger #include <dev/sound/pcm/sound.h> 47d056fa04SAlexander Leidinger 48d056fa04SAlexander Leidinger #include <dev/sound/midi/midi.h> 49d056fa04SAlexander Leidinger #include <dev/sound/midi/mpu401.h> 50d056fa04SAlexander Leidinger #include "mpufoi_if.h" 51d056fa04SAlexander Leidinger 5270e0bbedSPedro F. Giffuni #include <dev/sound/pci/emuxkireg.h> 53d056fa04SAlexander Leidinger #include <dev/sound/pci/emu10kx.h> 54d056fa04SAlexander Leidinger 55d056fa04SAlexander Leidinger struct emu_midi_softc { 56d056fa04SAlexander Leidinger struct mtx mtx; 57d056fa04SAlexander Leidinger device_t dev; 58d056fa04SAlexander Leidinger struct mpu401 *mpu; 59d056fa04SAlexander Leidinger mpu401_intr_t *mpu_intr; 60d056fa04SAlexander Leidinger struct emu_sc_info *card; 61d056fa04SAlexander Leidinger int port; /* I/O port or I/O ptr reg */ 62d056fa04SAlexander Leidinger int is_emu10k1; 63d056fa04SAlexander Leidinger int fflags; /* File flags */ 64d056fa04SAlexander Leidinger int ihandle; /* interrupt manager handle */ 65d056fa04SAlexander Leidinger }; 66d056fa04SAlexander Leidinger 67d056fa04SAlexander Leidinger static uint32_t emu_midi_card_intr(void *p, uint32_t arg); 68d056fa04SAlexander Leidinger 69d056fa04SAlexander Leidinger static unsigned char 7090da2b28SAriff Abdullah emu_mread(struct mpu401 *arg __unused, void *cookie, int reg) 71d056fa04SAlexander Leidinger { 7290da2b28SAriff Abdullah struct emu_midi_softc *sc = cookie; 73d056fa04SAlexander Leidinger unsigned int d; 74d056fa04SAlexander Leidinger 75d056fa04SAlexander Leidinger d = 0; 76d056fa04SAlexander Leidinger if (sc->is_emu10k1) 77d056fa04SAlexander Leidinger d = emu_rd(sc->card, 0x18 + reg, 1); 78d056fa04SAlexander Leidinger else 79d056fa04SAlexander Leidinger d = emu_rdptr(sc->card, 0, sc->port + reg); 80d056fa04SAlexander Leidinger 81d056fa04SAlexander Leidinger return (d); 82d056fa04SAlexander Leidinger } 83d056fa04SAlexander Leidinger 84d056fa04SAlexander Leidinger static void 8590da2b28SAriff Abdullah emu_mwrite(struct mpu401 *arg __unused, void *cookie, int reg, unsigned char b) 86d056fa04SAlexander Leidinger { 8790da2b28SAriff Abdullah struct emu_midi_softc *sc = cookie; 88d056fa04SAlexander Leidinger 89d056fa04SAlexander Leidinger if (sc->is_emu10k1) 90d056fa04SAlexander Leidinger emu_wr(sc->card, 0x18 + reg, b, 1); 91d056fa04SAlexander Leidinger else 92d056fa04SAlexander Leidinger emu_wrptr(sc->card, 0, sc->port + reg, b); 93d056fa04SAlexander Leidinger } 94d056fa04SAlexander Leidinger 95d056fa04SAlexander Leidinger static int 9690da2b28SAriff Abdullah emu_muninit(struct mpu401 *arg __unused, void *cookie) 97d056fa04SAlexander Leidinger { 9890da2b28SAriff Abdullah struct emu_midi_softc *sc = cookie; 99d056fa04SAlexander Leidinger 100d056fa04SAlexander Leidinger mtx_lock(&sc->mtx); 101d056fa04SAlexander Leidinger sc->mpu_intr = NULL; 102d056fa04SAlexander Leidinger mtx_unlock(&sc->mtx); 103d056fa04SAlexander Leidinger 104d056fa04SAlexander Leidinger return (0); 105d056fa04SAlexander Leidinger } 106d056fa04SAlexander Leidinger 107d056fa04SAlexander Leidinger static kobj_method_t emu_mpu_methods[] = { 108d056fa04SAlexander Leidinger KOBJMETHOD(mpufoi_read, emu_mread), 109d056fa04SAlexander Leidinger KOBJMETHOD(mpufoi_write, emu_mwrite), 110d056fa04SAlexander Leidinger KOBJMETHOD(mpufoi_uninit, emu_muninit), 11190da2b28SAriff Abdullah KOBJMETHOD_END 112d056fa04SAlexander Leidinger }; 11375d7240eSAlexander Leidinger static DEFINE_CLASS(emu_mpu, emu_mpu_methods, 0); 114d056fa04SAlexander Leidinger 115d056fa04SAlexander Leidinger static uint32_t 116d056fa04SAlexander Leidinger emu_midi_card_intr(void *p, uint32_t intr_status) 117d056fa04SAlexander Leidinger { 118d056fa04SAlexander Leidinger struct emu_midi_softc *sc = (struct emu_midi_softc *)p; 119d056fa04SAlexander Leidinger if (sc->mpu_intr) 120d056fa04SAlexander Leidinger (sc->mpu_intr) (sc->mpu); 121d056fa04SAlexander Leidinger if (sc->mpu_intr == NULL) { 122d056fa04SAlexander Leidinger /* We should read MIDI event to unlock card after 123d056fa04SAlexander Leidinger * interrupt. XXX - check, why this happens. */ 124b28624fdSAriff Abdullah if (bootverbose) 125d056fa04SAlexander Leidinger device_printf(sc->dev, "midi interrupt %08x without interrupt handler, force mread!\n", intr_status); 126d056fa04SAlexander Leidinger (void)emu_mread((void *)(NULL), sc, 0); 127d056fa04SAlexander Leidinger } 128d056fa04SAlexander Leidinger return (intr_status); /* Acknowledge everything */ 129d056fa04SAlexander Leidinger } 130d056fa04SAlexander Leidinger 131d056fa04SAlexander Leidinger static void 132d056fa04SAlexander Leidinger emu_midi_intr(void *p) 133d056fa04SAlexander Leidinger { 134d056fa04SAlexander Leidinger (void)emu_midi_card_intr(p, 0); 135d056fa04SAlexander Leidinger } 136d056fa04SAlexander Leidinger 137d056fa04SAlexander Leidinger static int 138d056fa04SAlexander Leidinger emu_midi_probe(device_t dev) 139d056fa04SAlexander Leidinger { 140d056fa04SAlexander Leidinger struct emu_midi_softc *scp; 1417387abd3SWarner Losh uintptr_t func, is_emu10k1; 142d056fa04SAlexander Leidinger 1437387abd3SWarner Losh BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 144d056fa04SAlexander Leidinger if (func != SCF_MIDI) 145d056fa04SAlexander Leidinger return (ENXIO); 146d056fa04SAlexander Leidinger 147d056fa04SAlexander Leidinger scp = device_get_softc(dev); 148d056fa04SAlexander Leidinger bzero(scp, sizeof(*scp)); 1497387abd3SWarner Losh BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ISEMU10K1, &is_emu10k1); 150ca23ff19SAlexander Leidinger scp->is_emu10k1 = is_emu10k1 ? 1 : 0; 151d056fa04SAlexander Leidinger 152d056fa04SAlexander Leidinger device_set_desc(dev, "EMU10Kx MIDI Interface"); 153d056fa04SAlexander Leidinger return (0); 154d056fa04SAlexander Leidinger } 155d056fa04SAlexander Leidinger 156d056fa04SAlexander Leidinger static int 157d056fa04SAlexander Leidinger emu_midi_attach(device_t dev) 158d056fa04SAlexander Leidinger { 159d056fa04SAlexander Leidinger struct emu_midi_softc * scp; 160d056fa04SAlexander Leidinger struct sndcard_func *func; 161d056fa04SAlexander Leidinger struct emu_midiinfo *midiinfo; 162d056fa04SAlexander Leidinger uint32_t inte_val, ipr_val; 163d056fa04SAlexander Leidinger 164d056fa04SAlexander Leidinger scp = device_get_softc(dev); 165d056fa04SAlexander Leidinger func = device_get_ivars(dev); 166d056fa04SAlexander Leidinger 167d056fa04SAlexander Leidinger scp->dev = dev; 168d056fa04SAlexander Leidinger midiinfo = (struct emu_midiinfo *)func->varinfo; 169d056fa04SAlexander Leidinger scp->port = midiinfo->port; 170d056fa04SAlexander Leidinger scp->card = midiinfo->card; 171d056fa04SAlexander Leidinger 172b28624fdSAriff Abdullah mtx_init(&scp->mtx, device_get_nameunit(dev), "midi softc", MTX_DEF); 173d056fa04SAlexander Leidinger 174d056fa04SAlexander Leidinger if (scp->is_emu10k1) { 175d056fa04SAlexander Leidinger /* SB Live! - only one MIDI device here */ 176d056fa04SAlexander Leidinger inte_val = 0; 17770e0bbedSPedro F. Giffuni /* inte_val |= EMU_INTE_MIDITXENABLE;*/ 17870e0bbedSPedro F. Giffuni inte_val |= EMU_INTE_MIDIRXENABLE; 17970e0bbedSPedro F. Giffuni ipr_val = EMU_IPR_MIDITRANSBUFE; 18070e0bbedSPedro F. Giffuni ipr_val |= EMU_IPR_MIDIRECVBUFE; 181d056fa04SAlexander Leidinger } else { 18270e0bbedSPedro F. Giffuni if (scp->port == EMU_A_MUDATA1) { 183d056fa04SAlexander Leidinger /* EXTERNAL MIDI (AudigyDrive) */ 184d056fa04SAlexander Leidinger inte_val = 0; 18570e0bbedSPedro F. Giffuni /* inte_val |= A_EMU_INTE_MIDITXENABLE1;*/ 18670e0bbedSPedro F. Giffuni inte_val |= EMU_INTE_MIDIRXENABLE; 18770e0bbedSPedro F. Giffuni ipr_val = EMU_IPR_MIDITRANSBUFE; 18870e0bbedSPedro F. Giffuni ipr_val |= EMU_IPR_MIDIRECVBUFE; 189d056fa04SAlexander Leidinger } else { 190d056fa04SAlexander Leidinger /* MIDI hw config port 2 */ 191d056fa04SAlexander Leidinger inte_val = 0; 19270e0bbedSPedro F. Giffuni /* inte_val |= A_EMU_INTE_MIDITXENABLE2;*/ 19370e0bbedSPedro F. Giffuni inte_val |= EMU_INTE_A_MIDIRXENABLE2; 19470e0bbedSPedro F. Giffuni ipr_val = EMU_IPR_A_MIDITRANSBUFE2; 19570e0bbedSPedro F. Giffuni ipr_val |= EMU_IPR_A_MIDIRECBUFE2; 196d056fa04SAlexander Leidinger } 197d056fa04SAlexander Leidinger } 198d056fa04SAlexander Leidinger 199d056fa04SAlexander Leidinger scp->ihandle = emu_intr_register(scp->card, inte_val, ipr_val, &emu_midi_card_intr, scp); 200d056fa04SAlexander Leidinger /* Init the interface. */ 201d056fa04SAlexander Leidinger scp->mpu = mpu401_init(&emu_mpu_class, scp, emu_midi_intr, &scp->mpu_intr); 202d056fa04SAlexander Leidinger if (scp->mpu == NULL) { 203d056fa04SAlexander Leidinger emu_intr_unregister(scp->card, scp->ihandle); 204d056fa04SAlexander Leidinger mtx_destroy(&scp->mtx); 205d056fa04SAlexander Leidinger return (ENOMEM); 206d056fa04SAlexander Leidinger } 207d056fa04SAlexander Leidinger /* 208d056fa04SAlexander Leidinger * XXX I don't know how to check for Live!Drive / AudigyDrive 209d056fa04SAlexander Leidinger * presence. Let's hope that IR enabling code will not harm if 210d056fa04SAlexander Leidinger * it is not present. 211d056fa04SAlexander Leidinger */ 212d056fa04SAlexander Leidinger if (scp->is_emu10k1) 213d056fa04SAlexander Leidinger emu_enable_ir(scp->card); 214d056fa04SAlexander Leidinger else { 21570e0bbedSPedro F. Giffuni if (scp->port == EMU_A_MUDATA1) 216d056fa04SAlexander Leidinger emu_enable_ir(scp->card); 217d056fa04SAlexander Leidinger } 218d056fa04SAlexander Leidinger 219d056fa04SAlexander Leidinger return (0); 220d056fa04SAlexander Leidinger } 221d056fa04SAlexander Leidinger 222d056fa04SAlexander Leidinger static int 223d056fa04SAlexander Leidinger emu_midi_detach(device_t dev) 224d056fa04SAlexander Leidinger { 225d056fa04SAlexander Leidinger struct emu_midi_softc *scp; 226d056fa04SAlexander Leidinger 227d056fa04SAlexander Leidinger scp = device_get_softc(dev); 228d056fa04SAlexander Leidinger mpu401_uninit(scp->mpu); 229d056fa04SAlexander Leidinger emu_intr_unregister(scp->card, scp->ihandle); 230d056fa04SAlexander Leidinger mtx_destroy(&scp->mtx); 231d056fa04SAlexander Leidinger return (0); 232d056fa04SAlexander Leidinger } 233d056fa04SAlexander Leidinger 234d056fa04SAlexander Leidinger static device_method_t emu_midi_methods[] = { 235d056fa04SAlexander Leidinger DEVMETHOD(device_probe, emu_midi_probe), 236d056fa04SAlexander Leidinger DEVMETHOD(device_attach, emu_midi_attach), 237d056fa04SAlexander Leidinger DEVMETHOD(device_detach, emu_midi_detach), 238d056fa04SAlexander Leidinger 23961bfd867SSofian Brabez DEVMETHOD_END 240d056fa04SAlexander Leidinger }; 241d056fa04SAlexander Leidinger 242d056fa04SAlexander Leidinger static driver_t emu_midi_driver = { 243d056fa04SAlexander Leidinger "midi", 244d056fa04SAlexander Leidinger emu_midi_methods, 245d056fa04SAlexander Leidinger sizeof(struct emu_midi_softc), 246d056fa04SAlexander Leidinger }; 2473390adfeSJohn Baldwin DRIVER_MODULE(snd_emu10kx_midi, emu10kx, emu_midi_driver, 0, 0); 248d056fa04SAlexander Leidinger MODULE_DEPEND(snd_emu10kx_midi, snd_emu10kx, SND_EMU10KX_MINVER, SND_EMU10KX_PREFVER, SND_EMU10KX_MAXVER); 249d056fa04SAlexander Leidinger MODULE_DEPEND(snd_emu10kx_midi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 250d056fa04SAlexander Leidinger MODULE_VERSION(snd_emu10kx_midi, SND_EMU10KX_PREFVER); 251