xref: /netbsd-src/sys/dev/isa/wss_isa.c (revision 5e4c038a45edbc7d63b7c2daa76e29f88b64a4e3)
1 /*	$NetBSD: wss_isa.c,v 1.12 2002/01/07 21:47:14 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 John Brezak
5  * Copyright (c) 1991-1993 Regents of the University of California.
6  * All rights reserved.
7  *
8  * MAD support:
9  * Copyright (c) 1996 Lennart Augustsson
10  * Based on code which is
11  * Copyright (c) 1994 Hannu Savolainen
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the Computer Systems
24  *	Engineering Group at Lawrence Berkeley Laboratory.
25  * 4. Neither the name of the University nor of the Laboratory may be used
26  *    to endorse or promote products derived from this software without
27  *    specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  */
42 
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: wss_isa.c,v 1.12 2002/01/07 21:47:14 thorpej Exp $");
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/errno.h>
50 
51 #include <machine/cpu.h>
52 #include <machine/intr.h>
53 #include <machine/bus.h>
54 
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
57 
58 #include <dev/isa/isavar.h>
59 #include <dev/isa/isadmavar.h>
60 
61 #include <dev/ic/ad1848reg.h>
62 #include <dev/isa/ad1848var.h>
63 #include <dev/isa/wssreg.h>
64 #include <dev/isa/wssvar.h>
65 #include <dev/isa/madreg.h>
66 
67 #ifdef AUDIO_DEBUG
68 #define DPRINTF(x)	if (wssdebug) printf x
69 extern int	wssdebug;
70 #else
71 #define DPRINTF(x)
72 #endif
73 
74 static int	wssfind __P((struct device *, struct wss_softc *, int,
75 		    struct isa_attach_args *));
76 
77 static void	madprobe __P((struct wss_softc *, int));
78 static void	madunmap __P((struct wss_softc *));
79 static int	detect_mad16 __P((struct wss_softc *, int));
80 
81 int		wss_isa_probe __P((struct device *, struct cfdata *, void *));
82 void		wss_isa_attach __P((struct device *, struct device *, void *));
83 
84 struct cfattach wss_isa_ca = {
85 	sizeof(struct wss_softc), wss_isa_probe, wss_isa_attach
86 };
87 
88 /*
89  * Probe for the Microsoft Sound System hardware.
90  */
91 int
92 wss_isa_probe(parent, match, aux)
93     struct device *parent;
94     struct cfdata *match;
95     void *aux;
96 {
97     struct isa_attach_args *ia = aux;
98     struct wss_softc probesc, *sc = &probesc;
99     struct ad1848_softc *ac = (struct ad1848_softc *)&sc->sc_ad1848;
100 
101     if (ia->ia_nio < 1)
102 	return 0;
103     if (ia->ia_nirq < 1)
104 	return 0;
105     if (ia->ia_ndrq < 1)
106 	return 0;
107 
108     if (ISA_DIRECT_CONFIG(ia))
109 	return 0;
110 
111     memset(sc, 0, sizeof *sc);
112     ac->sc_dev.dv_cfdata = match;
113     if (wssfind(parent, sc, 1, aux)) {
114         bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC);
115         ad1848_isa_unmap(&sc->sc_ad1848);
116         madunmap(sc);
117         return 1;
118     } else
119         /* Everything is already unmapped */
120         return 0;
121 }
122 
123 static int
124 wssfind(parent, sc, probing, ia)
125     struct device *parent;
126     struct wss_softc *sc;
127     int probing;
128     struct isa_attach_args *ia;
129 {
130     struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848;
131     static u_char interrupt_bits[12] = {
132 	-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
133     };
134     static u_char dma_bits[4] = {1, 2, 0, 3};
135     int ndrq, playdrq, recdrq;
136 
137     sc->sc_iot = ia->ia_iot;
138     if (ac->sc_dev.dv_cfdata->cf_flags & 1)
139 	madprobe(sc, ia->ia_io[0].ir_addr);
140     else
141 	sc->mad_chip_type = MAD_NONE;
142 
143 #if 0
144     if (!WSS_BASE_VALID(ia->ia_io[0].ir_addr)) {
145 	DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase));
146 	goto bad1;
147     }
148 #endif
149 
150     /* Map the ports upto the AD1848 port */
151     if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, WSS_CODEC,
152         0, &sc->sc_ioh))
153 	goto bad1;
154 
155     ac->sc_iot = sc->sc_iot;
156 
157     /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */
158     if (ad1848_isa_mapprobe(&sc->sc_ad1848,
159         ia->ia_io[0].ir_addr + WSS_CODEC) == 0)
160 	goto bad;
161 
162 #if 0
163     /* Setup WSS interrupt and DMA */
164     if (!WSS_DRQ_VALID(ia->ia_drq[0].ir_drq)) {
165 	DPRINTF(("wss: configured dma chan %d invalid\n",
166 	    ia->ia_drq[0].ir_drq));
167 	goto bad;
168     }
169 #endif
170     sc->wss_playdrq = ia->ia_drq[0].ir_drq;
171     sc->wss_ic      = ia->ia_ic;
172 
173     if (sc->wss_playdrq != ISACF_DRQ_DEFAULT &&
174         !isa_drq_isfree(sc->wss_ic, sc->wss_playdrq))
175 	    goto bad;
176 
177 #if 0
178     if (!WSS_IRQ_VALID(ia->ia_irq[0].ir_irq)) {
179 	DPRINTF(("wss: configured interrupt %d invalid\n",
180 	    ia->ia_irq[0].ir_irq));
181 	goto bad;
182     }
183 #endif
184 
185     sc->wss_irq = ia->ia_irq[0].ir_irq;
186 
187     playdrq = ia->ia_drq[0].ir_drq;
188     if (ia->ia_ndrq > 1) {
189 	ndrq = 2;
190 	recdrq = ia->ia_drq[1].ir_drq;
191     } else {
192 	ndrq = 1;
193 	recdrq = ISACF_IRQ_DEFAULT;
194     }
195 
196     if (ac->mode <= 1)
197 	ndrq = 1;
198     sc->wss_recdrq =
199 	ac->mode > 1 && ndrq > 1 &&
200 	recdrq != ISACF_DRQ_DEFAULT ? recdrq : playdrq;
201     if (sc->wss_recdrq != sc->wss_playdrq && !isa_drq_isfree(sc->wss_ic,
202       sc->wss_recdrq))
203 	goto bad;
204 
205     if (probing) {
206 	ia->ia_nio = 1;
207 	ia->ia_io[0].ir_size = WSS_NPORT;
208 
209 	ia->ia_nirq = 1;
210 
211 	ia->ia_ndrq = ndrq;
212 	ia->ia_drq[0].ir_drq = playdrq;
213 	if (ndrq > 1)
214 	    ia->ia_drq[1].ir_drq = recdrq;
215 
216 	ia->ia_niomem = 0;
217     }
218 
219     /* XXX recdrq */
220     bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG,
221 		      (interrupt_bits[ia->ia_irq[0].ir_irq] |
222 		       dma_bits[ia->ia_drq[0].ir_drq]));
223 
224     return 1;
225 
226 bad:
227     bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC);
228 bad1:
229     madunmap(sc);
230     return 0;
231 }
232 
233 /*
234  * Attach hardware to driver, attach hardware driver to audio
235  * pseudo-device driver .
236  */
237 void
238 wss_isa_attach(parent, self, aux)
239     struct device *parent, *self;
240     void *aux;
241 {
242     struct wss_softc *sc = (struct wss_softc *)self;
243     struct ad1848_softc *ac = (struct ad1848_softc *)&sc->sc_ad1848;
244     struct isa_attach_args *ia = (struct isa_attach_args *)aux;
245 
246     if (!wssfind(parent, sc, 0, ia)) {
247         printf("%s: wssfind failed\n", ac->sc_dev.dv_xname);
248         return;
249     }
250 
251     sc->wss_ic = ia->ia_ic;
252 
253     wssattach(sc);
254 }
255 
256 /*
257  * Copyright by Hannu Savolainen 1994
258  *
259  * Redistribution and use in source and binary forms, with or without
260  * modification, are permitted provided that the following conditions are
261  * met: 1. Redistributions of source code must retain the above copyright
262  * notice, this list of conditions and the following disclaimer. 2.
263  * Redistributions in binary form must reproduce the above copyright notice,
264  * this list of conditions and the following disclaimer in the documentation
265  * and/or other materials provided with the distribution.
266  *
267  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
268  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
269  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
270  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
271  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
273  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
274  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
275  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
276  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277  * SUCH DAMAGE.
278  *
279  */
280 
281 /*
282  * Initialization code for OPTi MAD16 compatible audio chips. Including
283  *
284  *      OPTi 82C928     MAD16           (replaced by C929)
285  *      OAK OTI-601D    Mozart
286  *      OPTi 82C929     MAD16 Pro
287  *	OPTi 82C931
288  */
289 
290 static int
291 detect_mad16(sc, chip_type)
292     struct wss_softc *sc;
293     int chip_type;
294 {
295     unsigned char tmp, tmp2;
296 
297     sc->mad_chip_type = chip_type;
298     /*
299      * Check that reading a register doesn't return bus float (0xff)
300      * when the card is accessed using password. This may fail in case
301      * the card is in low power mode. Normally at least the power saving mode
302      * bit should be 0.
303      */
304     if ((tmp = mad_read(sc, MC1_PORT)) == 0xff) {
305 	DPRINTF(("MC1_PORT returned 0xff\n"));
306 	return 0;
307     }
308 
309     /*
310      * Now check that the gate is closed on first I/O after writing
311      * the password. (This is how a MAD16 compatible card works).
312      */
313     if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->mad_ioh, MC1_PORT)) == tmp)	{
314 	DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
315 	return 0;
316     }
317 
318     mad_write(sc, MC1_PORT, tmp ^ 0x80);	/* Toggle a bit */
319 
320     /* Compare the bit */
321     if ((tmp2 = mad_read(sc, MC1_PORT)) != (tmp ^ 0x80)) {
322 	mad_write(sc, MC1_PORT, tmp);	/* Restore */
323 	DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
324 	return 0;
325     }
326 
327     mad_write(sc, MC1_PORT, tmp);	/* Restore */
328     return 1;
329 }
330 
331 static void
332 madprobe(sc, iobase)
333     struct wss_softc *sc;
334     int iobase;
335 {
336     static int valid_ports[M_WSS_NPORTS] =
337         { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 };
338     int i;
339 
340     /* Allocate bus space that the MAD chip wants */
341     if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->mad_ioh))
342 	goto bad0;
343     if (bus_space_map(sc->sc_iot, MAD_REG1, MAD_LEN1, 0, &sc->mad_ioh1))
344         goto bad1;
345     if (bus_space_map(sc->sc_iot, MAD_REG2, MAD_LEN2, 0, &sc->mad_ioh2))
346         goto bad2;
347     if (bus_space_map(sc->sc_iot, MAD_REG3, MAD_LEN3, 0, &sc->sc_opl_ioh))
348         goto bad3;
349 
350     DPRINTF(("mad: Detect using password = 0xE2\n"));
351     if (!detect_mad16(sc, MAD_82C928)) {
352 	/* No luck. Try different model */
353 	DPRINTF(("mad: Detect using password = 0xE3\n"));
354 	if (!detect_mad16(sc, MAD_82C929))
355 	    goto bad;
356 	sc->mad_chip_type = MAD_82C929;
357 	DPRINTF(("mad: 82C929 detected\n"));
358     } else {
359 	sc->mad_chip_type = MAD_82C928;
360 	if ((mad_read(sc, MC3_PORT) & 0x03) == 0x03) {
361 	    DPRINTF(("mad: Mozart detected\n"));
362 	    sc->mad_chip_type = MAD_OTI601D;
363 	} else {
364 	    DPRINTF(("mad: 82C928 detected?\n"));
365 	    sc->mad_chip_type = MAD_82C928;
366 	}
367     }
368 
369 #ifdef AUDIO_DEBUG
370     if (wssdebug)
371 	for (i = MC1_PORT; i <= MC7_PORT; i++)
372 	    printf("mad: port %03x = %02x\n", i, mad_read(sc, i));
373 #endif
374 
375     /* Set the WSS address. */
376     for (i = 0; i < M_WSS_NPORTS; i++)
377 	if (valid_ports[i] == iobase)
378 	    break;
379     if (i >= M_WSS_NPORTS) {		/* Not a valid port */
380 	printf("mad: Bad WSS base address 0x%x\n", iobase);
381 	goto bad;
382     }
383     sc->mad_ioindex = i;
384     /* enable WSS emulation at the I/O port, no joystick */
385     mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(i) | MC1_JOYDISABLE);
386     mad_write(sc, MC2_PORT, 0x03); /* ? */
387     mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */
388     return;
389 
390 bad:
391     bus_space_unmap(sc->sc_iot, sc->sc_opl_ioh, MAD_LEN3);
392 bad3:
393     bus_space_unmap(sc->sc_iot, sc->mad_ioh2, MAD_LEN2);
394 bad2:
395     bus_space_unmap(sc->sc_iot, sc->mad_ioh1, MAD_LEN1);
396 bad1:
397     bus_space_unmap(sc->sc_iot, sc->mad_ioh, MAD_NPORT);
398 bad0:
399     sc->mad_chip_type = MAD_NONE;
400 }
401 
402 static void
403 madunmap(sc)
404     struct wss_softc *sc;
405 {
406     if (sc->mad_chip_type == MAD_NONE)
407         return;
408     bus_space_unmap(sc->sc_iot, sc->mad_ioh, MAD_NPORT);
409     bus_space_unmap(sc->sc_iot, sc->mad_ioh1, MAD_LEN1);
410     bus_space_unmap(sc->sc_iot, sc->mad_ioh2, MAD_LEN2);
411     bus_space_unmap(sc->sc_iot, sc->sc_opl_ioh, MAD_LEN3);
412 }
413