1 /* $NetBSD: wss_isa.c,v 1.26 2009/05/12 08:44:20 cegger Exp $ */
4 * Copyright (c) 1994 John Brezak
5 * Copyright (c) 1991-1993 Regents of the University of California.
9 * Copyright (c) 1996 Lennart Augustsson
10 * Based on code which is
11 * Copyright (c) 1994 Hannu Savolainen
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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.
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
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: wss_isa.c,v 1.26 2009/05/12 08:44:20 cegger Exp $");
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/errno.h>
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
58 #include <dev/isa/isavar.h>
59 #include <dev/isa/isadmavar.h>
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>
68 #define DPRINTF(x) if (wssdebug) printf x
74 static int wssfind(device_t
, struct wss_softc
*, int,
75 struct isa_attach_args
*);
77 static void madprobe(struct wss_softc
*, int);
78 static void madunmap(struct wss_softc
*);
79 static int detect_mad16(struct wss_softc
*, int);
81 int wss_isa_probe(device_t
, cfdata_t
, void *);
82 void wss_isa_attach(device_t
, device_t
, void *);
84 CFATTACH_DECL(wss_isa
, sizeof(struct wss_softc
),
85 wss_isa_probe
, wss_isa_attach
, NULL
, NULL
);
88 * Probe for the Microsoft Sound System hardware.
91 wss_isa_probe(device_t parent
, cfdata_t match
, void *aux
)
93 struct isa_attach_args
*ia
;
94 struct wss_softc probesc
, *sc
;
95 struct ad1848_softc
*ac
;
99 ac
= (struct ad1848_softc
*)&sc
->sc_ad1848
;
107 if (ISA_DIRECT_CONFIG(ia
))
110 memset(sc
, 0, sizeof *sc
);
111 ac
->sc_dev
.dv_cfdata
= match
;
112 if (wssfind(parent
, sc
, 1, aux
)) {
113 bus_space_unmap(sc
->sc_iot
, sc
->sc_ioh
, WSS_CODEC
);
114 ad1848_isa_unmap(&sc
->sc_ad1848
);
118 /* Everything is already unmapped */
123 wssfind(device_t parent
, struct wss_softc
*sc
, int probing
,
124 struct isa_attach_args
*ia
)
126 static u_char interrupt_bits
[12] = {
127 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
129 static u_char dma_bits
[4] = {1, 2, 0, 3};
130 struct ad1848_softc
*ac
;
131 int ndrq
, playdrq
, recdrq
;
133 ac
= &sc
->sc_ad1848
.sc_ad1848
;
134 sc
->sc_iot
= ia
->ia_iot
;
135 if (device_cfdata(&ac
->sc_dev
)->cf_flags
& 1)
136 madprobe(sc
, ia
->ia_io
[0].ir_addr
);
138 sc
->mad_chip_type
= MAD_NONE
;
141 if (!WSS_BASE_VALID(ia
->ia_io
[0].ir_addr
)) {
142 DPRINTF(("wss: configured iobase %x invalid\n", ia
->ia_iobase
));
147 /* Map the ports upto the AD1848 port */
148 if (bus_space_map(sc
->sc_iot
, ia
->ia_io
[0].ir_addr
, WSS_CODEC
,
152 ac
->sc_iot
= sc
->sc_iot
;
154 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */
155 if (ad1848_isa_mapprobe(&sc
->sc_ad1848
,
156 ia
->ia_io
[0].ir_addr
+ WSS_CODEC
) == 0)
160 /* Setup WSS interrupt and DMA */
161 if (!WSS_DRQ_VALID(ia
->ia_drq
[0].ir_drq
)) {
162 DPRINTF(("wss: configured DMA chan %d invalid\n",
163 ia
->ia_drq
[0].ir_drq
));
167 sc
->wss_playdrq
= ia
->ia_drq
[0].ir_drq
;
168 sc
->wss_ic
= ia
->ia_ic
;
170 if (sc
->wss_playdrq
!= ISA_UNKNOWN_DRQ
&&
171 !isa_drq_isfree(sc
->wss_ic
, sc
->wss_playdrq
))
175 if (!WSS_IRQ_VALID(ia
->ia_irq
[0].ir_irq
)) {
176 DPRINTF(("wss: configured interrupt %d invalid\n",
177 ia
->ia_irq
[0].ir_irq
));
182 sc
->wss_irq
= ia
->ia_irq
[0].ir_irq
;
184 playdrq
= ia
->ia_drq
[0].ir_drq
;
185 if (ia
->ia_ndrq
> 1) {
187 recdrq
= ia
->ia_drq
[1].ir_drq
;
190 recdrq
= ISA_UNKNOWN_DRQ
;
196 ac
->mode
> 1 && ndrq
> 1 &&
197 recdrq
!= ISA_UNKNOWN_DRQ
? recdrq
: playdrq
;
198 if (sc
->wss_recdrq
!= sc
->wss_playdrq
&& !isa_drq_isfree(sc
->wss_ic
,
204 ia
->ia_io
[0].ir_size
= WSS_NPORT
;
209 ia
->ia_drq
[0].ir_drq
= playdrq
;
211 ia
->ia_drq
[1].ir_drq
= recdrq
;
217 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, WSS_CONFIG
,
218 (interrupt_bits
[ia
->ia_irq
[0].ir_irq
] |
219 dma_bits
[ia
->ia_drq
[0].ir_drq
]));
224 bus_space_unmap(sc
->sc_iot
, sc
->sc_ioh
, WSS_CODEC
);
231 * Attach hardware to driver, attach hardware driver to audio
232 * pseudo-device driver .
235 wss_isa_attach(device_t parent
, device_t self
, void *aux
)
237 struct wss_softc
*sc
;
238 struct ad1848_softc
*ac
;
239 struct isa_attach_args
*ia
;
241 sc
= (struct wss_softc
*)self
;
242 ac
= (struct ad1848_softc
*)&sc
->sc_ad1848
;
243 ia
= (struct isa_attach_args
*)aux
;
244 if (!wssfind(parent
, sc
, 0, ia
)) {
245 aprint_error_dev(&ac
->sc_dev
, "wssfind failed\n");
249 sc
->wss_ic
= ia
->ia_ic
;
255 * Copyright by Hannu Savolainen 1994
257 * Redistribution and use in source and binary forms, with or without
258 * modification, are permitted provided that the following conditions are
259 * met: 1. Redistributions of source code must retain the above copyright
260 * notice, this list of conditions and the following disclaimer. 2.
261 * Redistributions in binary form must reproduce the above copyright notice,
262 * this list of conditions and the following disclaimer in the documentation
263 * and/or other materials provided with the distribution.
265 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
266 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
267 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
268 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
269 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
270 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
271 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
272 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
273 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
274 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280 * Initialization code for OPTi MAD16 compatible audio chips. Including
282 * OPTi 82C928 MAD16 (replaced by C929)
283 * OAK OTI-601D Mozart
284 * OPTi 82C929 MAD16 Pro
289 detect_mad16(struct wss_softc
*sc
, int chip_type
)
291 unsigned char tmp
, tmp2
;
293 sc
->mad_chip_type
= chip_type
;
295 * Check that reading a register doesn't return bus float (0xff)
296 * when the card is accessed using password. This may fail in case
297 * the card is in low power mode. Normally at least the power saving mode
300 if ((tmp
= mad_read(sc
, MC1_PORT
)) == 0xff) {
301 DPRINTF(("MC1_PORT returned 0xff\n"));
306 * Now check that the gate is closed on first I/O after writing
307 * the password. (This is how a MAD16 compatible card works).
309 if ((tmp2
= bus_space_read_1(sc
->sc_iot
, sc
->mad_ioh
, MC1_PORT
)) == tmp
) {
310 DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2
));
314 mad_write(sc
, MC1_PORT
, tmp
^ 0x80); /* Toggle a bit */
316 /* Compare the bit */
317 if ((tmp2
= mad_read(sc
, MC1_PORT
)) != (tmp
^ 0x80)) {
318 mad_write(sc
, MC1_PORT
, tmp
); /* Restore */
319 DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp
, tmp2
));
323 mad_write(sc
, MC1_PORT
, tmp
); /* Restore */
328 madprobe(struct wss_softc
*sc
, int iobase
)
330 static int valid_ports
[M_WSS_NPORTS
] =
331 { M_WSS_PORT0
, M_WSS_PORT1
, M_WSS_PORT2
, M_WSS_PORT3
};
334 /* Allocate bus space that the MAD chip wants */
335 if (bus_space_map(sc
->sc_iot
, MAD_BASE
, MAD_NPORT
, 0, &sc
->mad_ioh
))
337 if (bus_space_map(sc
->sc_iot
, MAD_REG1
, MAD_LEN1
, 0, &sc
->mad_ioh1
))
339 if (bus_space_map(sc
->sc_iot
, MAD_REG2
, MAD_LEN2
, 0, &sc
->mad_ioh2
))
341 if (bus_space_map(sc
->sc_iot
, MAD_REG3
, MAD_LEN3
, 0, &sc
->sc_opl_ioh
))
344 DPRINTF(("mad: Detect using password = 0xE2\n"));
345 if (!detect_mad16(sc
, MAD_82C928
)) {
346 /* No luck. Try different model */
347 DPRINTF(("mad: Detect using password = 0xE3\n"));
348 if (!detect_mad16(sc
, MAD_82C929
))
350 sc
->mad_chip_type
= MAD_82C929
;
351 DPRINTF(("mad: 82C929 detected\n"));
353 sc
->mad_chip_type
= MAD_82C928
;
354 if ((mad_read(sc
, MC3_PORT
) & 0x03) == 0x03) {
355 DPRINTF(("mad: Mozart detected\n"));
356 sc
->mad_chip_type
= MAD_OTI601D
;
358 DPRINTF(("mad: 82C928 detected?\n"));
359 sc
->mad_chip_type
= MAD_82C928
;
365 for (i
= MC1_PORT
; i
<= MC7_PORT
; i
++)
366 printf("mad: port %03x = %02x\n", i
, mad_read(sc
, i
));
369 /* Set the WSS address. */
370 for (i
= 0; i
< M_WSS_NPORTS
; i
++)
371 if (valid_ports
[i
] == iobase
)
373 if (i
>= M_WSS_NPORTS
) { /* Not a valid port */
374 printf("mad: Bad WSS base address 0x%x\n", iobase
);
378 /* enable WSS emulation at the I/O port, no joystick */
379 mad_write(sc
, MC1_PORT
, M_WSS_PORT_SELECT(i
) | MC1_JOYDISABLE
);
380 mad_write(sc
, MC2_PORT
, 0x03); /* ? */
381 mad_write(sc
, MC3_PORT
, 0xf0); /* Disable SB */
385 bus_space_unmap(sc
->sc_iot
, sc
->sc_opl_ioh
, MAD_LEN3
);
387 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh2
, MAD_LEN2
);
389 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh1
, MAD_LEN1
);
391 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh
, MAD_NPORT
);
393 sc
->mad_chip_type
= MAD_NONE
;
397 madunmap(struct wss_softc
*sc
)
400 if (sc
->mad_chip_type
== MAD_NONE
)
402 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh
, MAD_NPORT
);
403 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh1
, MAD_LEN1
);
404 bus_space_unmap(sc
->sc_iot
, sc
->mad_ioh2
, MAD_LEN2
);
405 bus_space_unmap(sc
->sc_iot
, sc
->sc_opl_ioh
, MAD_LEN3
);