xref: /openbsd/sys/dev/isa/sb.c (revision 404b540a)
1 /*	$OpenBSD: sb.c,v 1.25 2008/04/21 00:32:42 jakemsr Exp $	*/
2 /*	$NetBSD: sb.c,v 1.57 1998/01/12 09:43:46 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1991-1993 Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the Computer Systems
19  *	Engineering Group at Lawrence Berkeley Laboratory.
20  * 4. Neither the name of the University nor of the Laboratory may be used
21  *    to endorse or promote products derived from this software without
22  *    specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  */
37 
38 #include "midi.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/ioctl.h>
44 #include <sys/syslog.h>
45 #include <sys/device.h>
46 #include <sys/proc.h>
47 
48 #include <machine/cpu.h>
49 #include <machine/intr.h>
50 #include <machine/bus.h>
51 
52 #include <sys/audioio.h>
53 #include <dev/audio_if.h>
54 #include <dev/midi_if.h>
55 
56 #include <dev/isa/isavar.h>
57 #include <dev/isa/isadmavar.h>
58 
59 #include <dev/isa/sbreg.h>
60 #include <dev/isa/sbvar.h>
61 #include <dev/isa/sbdspvar.h>
62 
63 struct cfdriver sb_cd = {
64 	NULL, "sb", DV_DULL
65 };
66 
67 #if NMIDI > 0
68 int	sb_mpu401_open(void *, int, void (*iintr)(void *, int),
69 		       void (*ointr)(void *), void *arg);
70 void	sb_mpu401_close(void *);
71 int	sb_mpu401_output(void *, int);
72 void	sb_mpu401_getinfo(void *, struct midi_info *);
73 
74 struct midi_hw_if sb_midi_hw_if = {
75 	sbdsp_midi_open,
76 	sbdsp_midi_close,
77 	sbdsp_midi_output,
78 	0,			/* flush */
79 	sbdsp_midi_getinfo,
80 	0,			/* ioctl */
81 };
82 
83 struct midi_hw_if sb_mpu401_hw_if = {
84 	sb_mpu401_open,
85 	sb_mpu401_close,
86 	sb_mpu401_output,
87 	0,			/* flush */
88 	sb_mpu401_getinfo,
89 	0,			/* ioctl */
90 };
91 #endif
92 
93 struct audio_device sb_device = {
94 	"SoundBlaster",
95 	"x",
96 	"sb"
97 };
98 
99 int	sb_getdev(void *, struct audio_device *);
100 
101 /*
102  * Define our interface to the higher level audio driver.
103  */
104 
105 struct audio_hw_if sb_hw_if = {
106 	sbdsp_open,
107 	sbdsp_close,
108 	0,
109 	sbdsp_query_encoding,
110 	sbdsp_set_params,
111 	sbdsp_round_blocksize,
112 	0,
113 	0,
114 	0,
115 	0,
116 	0,
117 	sbdsp_haltdma,
118 	sbdsp_haltdma,
119 	sbdsp_speaker_ctl,
120 	sb_getdev,
121 	0,
122 	sbdsp_mixer_set_port,
123 	sbdsp_mixer_get_port,
124 	sbdsp_mixer_query_devinfo,
125 	sb_malloc,
126 	sb_free,
127 	sb_round,
128         sb_mappage,
129 	sbdsp_get_props,
130 	sbdsp_trigger_output,
131 	sbdsp_trigger_input,
132 	NULL
133 };
134 
135 #ifdef AUDIO_DEBUG
136 #define DPRINTF(x)	if (sbdebug) printf x
137 int	sbdebug = 0;
138 #else
139 #define DPRINTF(x)
140 #endif
141 
142 /*
143  * Probe / attach routines.
144  */
145 
146 
147 int
148 sbmatch(sc)
149 	struct sbdsp_softc *sc;
150 {
151 	static u_char drq_conf[8] = {
152 		0x01, 0x02, -1, 0x08, -1, 0x20, 0x40, 0x80
153 	};
154 
155 	static u_char irq_conf[11] = {
156 		-1, -1, 0x01, -1, -1, 0x02, -1, 0x04, -1, 0x01, 0x08
157 	};
158 
159 	if (sbdsp_probe(sc) == 0)
160 		return 0;
161 
162 	/*
163 	 * Cannot auto-discover DMA channel.
164 	 */
165 	if (ISSBPROCLASS(sc)) {
166 		if (!SBP_DRQ_VALID(sc->sc_drq8)) {
167 			DPRINTF(("%s: configured dma chan %d invalid\n",
168 			    sc->sc_dev.dv_xname, sc->sc_drq8));
169 			return 0;
170 		}
171 	} else {
172 		if (!SB_DRQ_VALID(sc->sc_drq8)) {
173 			DPRINTF(("%s: configured dma chan %d invalid\n",
174 			    sc->sc_dev.dv_xname, sc->sc_drq8));
175 			return 0;
176 		}
177 	}
178 
179         if (0 <= sc->sc_drq16 && sc->sc_drq16 <= 3)
180         	/*
181                  * XXX Some ViBRA16 cards seem to have two 8 bit DMA
182                  * channels.  I've no clue how to use them, so ignore
183                  * one of them for now.  -- augustss@netbsd.org
184                  */
185         	sc->sc_drq16 = -1;
186 
187 	if (ISSB16CLASS(sc)) {
188 		if (sc->sc_drq16 == -1)
189 			sc->sc_drq16 = sc->sc_drq8;
190 		if (!SB16_DRQ_VALID(sc->sc_drq16)) {
191 			DPRINTF(("%s: configured dma chan %d invalid\n",
192 			    sc->sc_dev.dv_xname, sc->sc_drq16));
193 			return 0;
194 		}
195 	} else
196 		sc->sc_drq16 = sc->sc_drq8;
197 
198 	if (ISSBPROCLASS(sc)) {
199 		if (!SBP_IRQ_VALID(sc->sc_irq)) {
200 			DPRINTF(("%s: configured irq %d invalid\n",
201 			    sc->sc_dev.dv_xname, sc->sc_irq));
202 			return 0;
203 		}
204 	} else {
205 		if (!SB_IRQ_VALID(sc->sc_irq)) {
206 			DPRINTF(("%s: configured irq %d invalid\n",
207 			    sc->sc_dev.dv_xname, sc->sc_irq));
208 			return 0;
209 		}
210 	}
211 
212 	if (ISSB16CLASS(sc)) {
213 		int w, r;
214 #if 0
215 		DPRINTF(("%s: old drq conf %02x\n", sc->sc_dev.dv_xname,
216 		    sbdsp_mix_read(sc, SBP_SET_DRQ)));
217 		DPRINTF(("%s: try drq conf %02x\n", sc->sc_dev.dv_xname,
218 		    drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8]));
219 #endif
220 		w = drq_conf[sc->sc_drq16] | drq_conf[sc->sc_drq8];
221 		sbdsp_mix_write(sc, SBP_SET_DRQ, w);
222 		r = sbdsp_mix_read(sc, SBP_SET_DRQ) & 0xeb;
223 		if (r != w) {
224 			DPRINTF(("%s: setting drq mask %02x failed, got %02x\n", sc->sc_dev.dv_xname, w, r));
225 			return 0;
226 		}
227 #if 0
228 		DPRINTF(("%s: new drq conf %02x\n", sc->sc_dev.dv_xname,
229 		    sbdsp_mix_read(sc, SBP_SET_DRQ)));
230 #endif
231 
232 #if 0
233 		DPRINTF(("%s: old irq conf %02x\n", sc->sc_dev.dv_xname,
234 		    sbdsp_mix_read(sc, SBP_SET_IRQ)));
235 		DPRINTF(("%s: try irq conf %02x\n", sc->sc_dev.dv_xname,
236 		    irq_conf[sc->sc_irq]));
237 #endif
238 		w = irq_conf[sc->sc_irq];
239 		sbdsp_mix_write(sc, SBP_SET_IRQ, w);
240 		r = sbdsp_mix_read(sc, SBP_SET_IRQ) & 0x0f;
241 		if (r != w) {
242 			DPRINTF(("%s: setting irq mask %02x failed, got %02x\n",
243 			    sc->sc_dev.dv_xname, w, r));
244 			return 0;
245 		}
246 #if 0
247 		DPRINTF(("%s: new irq conf %02x\n", sc->sc_dev.dv_xname,
248 		    sbdsp_mix_read(sc, SBP_SET_IRQ)));
249 #endif
250 	}
251 
252 	return 1;
253 }
254 
255 
256 void
257 sbattach(sc)
258 	struct sbdsp_softc *sc;
259 {
260 	struct audio_attach_args arg;
261 #if NMIDI > 0
262 	struct midi_hw_if *mhw = &sb_midi_hw_if;
263 #endif
264 
265 	sc->sc_ih = isa_intr_establish(sc->sc_ic, sc->sc_irq, IST_EDGE,
266 	    IPL_AUDIO, sbdsp_intr, sc, sc->sc_dev.dv_xname);
267 
268 	sbdsp_attach(sc);
269 
270 #if NMIDI > 0
271 	sc->sc_hasmpu = 0;
272 	if (ISSB16CLASS(sc) && sc->sc_mpu_sc.iobase != 0) {
273 		sc->sc_mpu_sc.iot = sc->sc_iot;
274 		if (mpu_find(&sc->sc_mpu_sc)) {
275 			sc->sc_hasmpu = 1;
276 			mhw = &sb_mpu401_hw_if;
277 		}
278 	}
279 	midi_attach_mi(mhw, sc, &sc->sc_dev);
280 #endif
281 
282 	audio_attach_mi(&sb_hw_if, sc, &sc->sc_dev);
283 
284 	arg.type = AUDIODEV_TYPE_OPL;
285 	arg.hwif = 0;
286 	arg.hdl = 0;
287 	(void)config_found(&sc->sc_dev, &arg, audioprint);
288 }
289 
290 /*
291  * Various routines to interface to higher level audio driver
292  */
293 
294 int
295 sb_getdev(addr, retp)
296 	void *addr;
297 	struct audio_device *retp;
298 {
299 	struct sbdsp_softc *sc = addr;
300 	static char *names[] = SB_NAMES;
301 	char *config;
302 
303 	if (sc->sc_model == SB_JAZZ)
304 		strlcpy(retp->name, "MV Jazz16", sizeof retp->name);
305 	else
306 		strlcpy(retp->name, "SoundBlaster", sizeof retp->name);
307 	snprintf(retp->version, sizeof retp->version, "%d.%02d",
308 		 SBVER_MAJOR(sc->sc_version),
309 		 SBVER_MINOR(sc->sc_version));
310 	if (0 <= sc->sc_model && sc->sc_model < sizeof names / sizeof names[0])
311 		config = names[sc->sc_model];
312 	else
313 		config = "??";
314 	strlcpy(retp->config, config, sizeof retp->config);
315 
316 	return 0;
317 }
318 
319 #if NMIDI > 0
320 
321 #define SBMPU(a) (&((struct sbdsp_softc *)addr)->sc_mpu_sc)
322 
323 int
324 sb_mpu401_open(addr, flags, iintr, ointr, arg)
325 	void *addr;
326 	int flags;
327 	void (*iintr)(void *, int);
328 	void (*ointr)(void *);
329 	void *arg;
330 {
331 	return mpu_open(SBMPU(addr), flags, iintr, ointr, arg);
332 }
333 
334 int
335 sb_mpu401_output(addr, d)
336 	void *addr;
337 	int d;
338 {
339 	return mpu_output(SBMPU(addr), d);
340 }
341 
342 void
343 sb_mpu401_close(addr)
344 	void *addr;
345 {
346 	mpu_close(SBMPU(addr));
347 }
348 
349 void
350 sb_mpu401_getinfo(addr, mi)
351 	void *addr;
352 	struct midi_info *mi;
353 {
354 	mi->name = "SB MPU-401 UART";
355 	mi->props = 0;
356 }
357 #endif
358