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$
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