emu10kx-midi.c revision 246128
1160383Snetchild/*- 2160383Snetchild * Copyright (c) 1999 Seigo Tanimura 3192460Sjoel * Copyright (c) 2003 Mathew Kanner 4160383Snetchild * Copyright (c) 2003-2006 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru> 5160383Snetchild * All rights reserved 6160383Snetchild * 7160383Snetchild * Redistribution and use in source and binary forms, with or without 8160383Snetchild * modification, are permitted provided that the following conditions 9160383Snetchild * are met: 10160383Snetchild * 1. Redistributions of source code must retain the above copyright 11160383Snetchild * notice, this list of conditions and the following disclaimer. 12160383Snetchild * 2. Redistributions in binary form must reproduce the above copyright 13160383Snetchild * notice, this list of conditions and the following disclaimer in the 14160383Snetchild * documentation and/or other materials provided with the distribution. 15160383Snetchild * 16160383Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17160383Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18160383Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19160383Snetchild * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20160383Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21160383Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22160383Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23160383Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24160383Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25160383Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26160383Snetchild * SUCH DAMAGE. 27160383Snetchild * 28160383Snetchild * $FreeBSD: head/sys/dev/sound/pci/emu10kx-midi.c 246128 2013-01-30 18:01:20Z sbz $ 29160383Snetchild */ 30160383Snetchild 31160383Snetchild#include <sys/param.h> 32160383Snetchild#include <sys/types.h> 33160383Snetchild#include <sys/bus.h> 34160383Snetchild#include <machine/bus.h> 35160383Snetchild#include <sys/rman.h> 36160383Snetchild#include <sys/systm.h> 37160383Snetchild#include <sys/sbuf.h> 38160383Snetchild#include <sys/queue.h> 39160383Snetchild#include <sys/lock.h> 40160383Snetchild#include <sys/mutex.h> 41160383Snetchild 42193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 43193640Sariff#include "opt_snd.h" 44193640Sariff#endif 45193640Sariff 46160383Snetchild#include <dev/sound/chip.h> 47160383Snetchild#include <dev/sound/pcm/sound.h> 48160383Snetchild 49160383Snetchild#include <dev/sound/midi/midi.h> 50160383Snetchild#include <dev/sound/midi/mpu401.h> 51160383Snetchild#include "mpufoi_if.h" 52160383Snetchild 53229981Spfg#include <dev/sound/pci/emuxkireg.h> 54160383Snetchild#include <dev/sound/pci/emu10kx.h> 55160383Snetchild 56160383Snetchildstruct emu_midi_softc { 57160383Snetchild struct mtx mtx; 58160383Snetchild device_t dev; 59160383Snetchild struct mpu401 *mpu; 60160383Snetchild mpu401_intr_t *mpu_intr; 61160383Snetchild struct emu_sc_info *card; 62160383Snetchild int port; /* I/O port or I/O ptr reg */ 63160383Snetchild int is_emu10k1; 64160383Snetchild int fflags; /* File flags */ 65160383Snetchild int ihandle; /* interrupt manager handle */ 66160383Snetchild}; 67160383Snetchild 68160383Snetchildstatic uint32_t emu_midi_card_intr(void *p, uint32_t arg); 69160383Snetchildstatic devclass_t emu_midi_devclass; 70160383Snetchild 71160383Snetchildstatic unsigned char 72193640Sariffemu_mread(struct mpu401 *arg __unused, void *cookie, int reg) 73160383Snetchild{ 74193640Sariff struct emu_midi_softc *sc = cookie; 75160383Snetchild unsigned int d; 76160383Snetchild 77160383Snetchild d = 0; 78160383Snetchild if (sc->is_emu10k1) 79160383Snetchild d = emu_rd(sc->card, 0x18 + reg, 1); 80160383Snetchild else 81160383Snetchild d = emu_rdptr(sc->card, 0, sc->port + reg); 82160383Snetchild 83160383Snetchild return (d); 84160383Snetchild} 85160383Snetchild 86160383Snetchildstatic void 87193640Sariffemu_mwrite(struct mpu401 *arg __unused, void *cookie, int reg, unsigned char b) 88160383Snetchild{ 89193640Sariff struct emu_midi_softc *sc = cookie; 90160383Snetchild 91160383Snetchild if (sc->is_emu10k1) 92160383Snetchild emu_wr(sc->card, 0x18 + reg, b, 1); 93160383Snetchild else 94160383Snetchild emu_wrptr(sc->card, 0, sc->port + reg, b); 95160383Snetchild} 96160383Snetchild 97160383Snetchildstatic int 98193640Sariffemu_muninit(struct mpu401 *arg __unused, void *cookie) 99160383Snetchild{ 100193640Sariff struct emu_midi_softc *sc = cookie; 101160383Snetchild 102160383Snetchild mtx_lock(&sc->mtx); 103160383Snetchild sc->mpu_intr = NULL; 104160383Snetchild mtx_unlock(&sc->mtx); 105160383Snetchild 106160383Snetchild return (0); 107160383Snetchild} 108160383Snetchild 109160383Snetchildstatic kobj_method_t emu_mpu_methods[] = { 110160383Snetchild KOBJMETHOD(mpufoi_read, emu_mread), 111160383Snetchild KOBJMETHOD(mpufoi_write, emu_mwrite), 112160383Snetchild KOBJMETHOD(mpufoi_uninit, emu_muninit), 113193640Sariff KOBJMETHOD_END 114160383Snetchild}; 115160384Snetchildstatic DEFINE_CLASS(emu_mpu, emu_mpu_methods, 0); 116160383Snetchild 117160383Snetchildstatic uint32_t 118160383Snetchildemu_midi_card_intr(void *p, uint32_t intr_status) 119160383Snetchild{ 120160383Snetchild struct emu_midi_softc *sc = (struct emu_midi_softc *)p; 121160383Snetchild if (sc->mpu_intr) 122160383Snetchild (sc->mpu_intr) (sc->mpu); 123160383Snetchild if (sc->mpu_intr == NULL) { 124160383Snetchild /* We should read MIDI event to unlock card after 125160383Snetchild * interrupt. XXX - check, why this happens. */ 126172150Sariff if (bootverbose) 127172150Sariff device_printf(sc->dev, "midi interrupt %08x without interrupt handler, force mread!\n", intr_status); 128160383Snetchild (void)emu_mread((void *)(NULL), sc, 0); 129160383Snetchild } 130160383Snetchild return (intr_status); /* Acknowledge everything */ 131160383Snetchild} 132160383Snetchild 133160383Snetchildstatic void 134160383Snetchildemu_midi_intr(void *p) 135160383Snetchild{ 136160383Snetchild (void)emu_midi_card_intr(p, 0); 137160383Snetchild} 138160383Snetchild 139160383Snetchildstatic int 140160383Snetchildemu_midi_probe(device_t dev) 141160383Snetchild{ 142160383Snetchild struct emu_midi_softc *scp; 143160409Snetchild uintptr_t func, r, is_emu10k1; 144160383Snetchild 145160383Snetchild r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 146160383Snetchild if (func != SCF_MIDI) 147160383Snetchild return (ENXIO); 148160383Snetchild 149160383Snetchild scp = device_get_softc(dev); 150160383Snetchild bzero(scp, sizeof(*scp)); 151160409Snetchild r = BUS_READ_IVAR(device_get_parent(dev), dev, EMU_VAR_ISEMU10K1, &is_emu10k1); 152160409Snetchild scp->is_emu10k1 = is_emu10k1 ? 1 : 0; 153160383Snetchild 154160383Snetchild device_set_desc(dev, "EMU10Kx MIDI Interface"); 155160383Snetchild return (0); 156160383Snetchild} 157160383Snetchild 158160383Snetchildstatic int 159160383Snetchildemu_midi_attach(device_t dev) 160160383Snetchild{ 161160383Snetchild struct emu_midi_softc * scp; 162160383Snetchild struct sndcard_func *func; 163160383Snetchild struct emu_midiinfo *midiinfo; 164160383Snetchild uint32_t inte_val, ipr_val; 165160383Snetchild 166160383Snetchild scp = device_get_softc(dev); 167160383Snetchild func = device_get_ivars(dev); 168160383Snetchild 169160383Snetchild scp->dev = dev; 170160383Snetchild midiinfo = (struct emu_midiinfo *)func->varinfo; 171160383Snetchild scp->port = midiinfo->port; 172160383Snetchild scp->card = midiinfo->card; 173160383Snetchild 174172150Sariff mtx_init(&scp->mtx, device_get_nameunit(dev), "midi softc", MTX_DEF); 175160383Snetchild 176160383Snetchild if (scp->is_emu10k1) { 177160383Snetchild /* SB Live! - only one MIDI device here */ 178160383Snetchild inte_val = 0; 179229981Spfg /* inte_val |= EMU_INTE_MIDITXENABLE;*/ 180229981Spfg inte_val |= EMU_INTE_MIDIRXENABLE; 181229981Spfg ipr_val = EMU_IPR_MIDITRANSBUFE; 182229981Spfg ipr_val |= EMU_IPR_MIDIRECVBUFE; 183160383Snetchild } else { 184229981Spfg if (scp->port == EMU_A_MUDATA1) { 185160383Snetchild /* EXTERNAL MIDI (AudigyDrive) */ 186160383Snetchild inte_val = 0; 187229981Spfg /* inte_val |= A_EMU_INTE_MIDITXENABLE1;*/ 188229981Spfg inte_val |= EMU_INTE_MIDIRXENABLE; 189229981Spfg ipr_val = EMU_IPR_MIDITRANSBUFE; 190229981Spfg ipr_val |= EMU_IPR_MIDIRECVBUFE; 191160383Snetchild } else { 192160383Snetchild /* MIDI hw config port 2 */ 193160383Snetchild inte_val = 0; 194229981Spfg /* inte_val |= A_EMU_INTE_MIDITXENABLE2;*/ 195229981Spfg inte_val |= EMU_INTE_A_MIDIRXENABLE2; 196229981Spfg ipr_val = EMU_IPR_A_MIDITRANSBUFE2; 197229981Spfg ipr_val |= EMU_IPR_A_MIDIRECBUFE2; 198160383Snetchild } 199160383Snetchild } 200160383Snetchild 201160383Snetchild scp->ihandle = emu_intr_register(scp->card, inte_val, ipr_val, &emu_midi_card_intr, scp); 202160383Snetchild /* Init the interface. */ 203160383Snetchild scp->mpu = mpu401_init(&emu_mpu_class, scp, emu_midi_intr, &scp->mpu_intr); 204160383Snetchild if (scp->mpu == NULL) { 205160383Snetchild emu_intr_unregister(scp->card, scp->ihandle); 206160383Snetchild mtx_destroy(&scp->mtx); 207160383Snetchild return (ENOMEM); 208160383Snetchild } 209160383Snetchild /* 210160383Snetchild * XXX I don't know how to check for Live!Drive / AudigyDrive 211160383Snetchild * presence. Let's hope that IR enabling code will not harm if 212160383Snetchild * it is not present. 213160383Snetchild */ 214160383Snetchild if (scp->is_emu10k1) 215160383Snetchild emu_enable_ir(scp->card); 216160383Snetchild else { 217229981Spfg if (scp->port == EMU_A_MUDATA1) 218160383Snetchild emu_enable_ir(scp->card); 219160383Snetchild } 220160383Snetchild 221160383Snetchild return (0); 222160383Snetchild} 223160383Snetchild 224160383Snetchild 225160383Snetchildstatic int 226160383Snetchildemu_midi_detach(device_t dev) 227160383Snetchild{ 228160383Snetchild struct emu_midi_softc *scp; 229160383Snetchild 230160383Snetchild scp = device_get_softc(dev); 231160383Snetchild mpu401_uninit(scp->mpu); 232160383Snetchild emu_intr_unregister(scp->card, scp->ihandle); 233160383Snetchild mtx_destroy(&scp->mtx); 234160383Snetchild return (0); 235160383Snetchild} 236160383Snetchild 237160383Snetchildstatic device_method_t emu_midi_methods[] = { 238160383Snetchild DEVMETHOD(device_probe, emu_midi_probe), 239160383Snetchild DEVMETHOD(device_attach, emu_midi_attach), 240160383Snetchild DEVMETHOD(device_detach, emu_midi_detach), 241160383Snetchild 242246128Ssbz DEVMETHOD_END 243160383Snetchild}; 244160383Snetchild 245160383Snetchildstatic driver_t emu_midi_driver = { 246160383Snetchild "midi", 247160383Snetchild emu_midi_methods, 248160383Snetchild sizeof(struct emu_midi_softc), 249160383Snetchild}; 250160383SnetchildDRIVER_MODULE(snd_emu10kx_midi, emu10kx, emu_midi_driver, emu_midi_devclass, 0, 0); 251160383SnetchildMODULE_DEPEND(snd_emu10kx_midi, snd_emu10kx, SND_EMU10KX_MINVER, SND_EMU10KX_PREFVER, SND_EMU10KX_MAXVER); 252160383SnetchildMODULE_DEPEND(snd_emu10kx_midi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 253160383SnetchildMODULE_VERSION(snd_emu10kx_midi, SND_EMU10KX_PREFVER); 254