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