1 /* $NetBSD: wss_isa.c,v 1.27 2009/05/12 09:10:16 cegger 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.27 2009/05/12 09:10:16 cegger 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 <sys/cpu.h> 52 #include <sys/intr.h> 53 #include <sys/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(device_t, struct wss_softc *, int, 75 struct isa_attach_args *); 76 77 static void madprobe(struct wss_softc *, int); 78 static void madunmap(struct wss_softc *); 79 static int detect_mad16(struct wss_softc *, int); 80 81 int wss_isa_probe(device_t, cfdata_t, void *); 82 void wss_isa_attach(device_t, device_t, void *); 83 84 CFATTACH_DECL(wss_isa, sizeof(struct wss_softc), 85 wss_isa_probe, wss_isa_attach, NULL, NULL); 86 87 /* 88 * Probe for the Microsoft Sound System hardware. 89 */ 90 int 91 wss_isa_probe(device_t parent, cfdata_t match, void *aux) 92 { 93 struct isa_attach_args *ia; 94 struct wss_softc probesc, *sc; 95 struct ad1848_softc *ac; 96 97 ia = aux; 98 sc = &probesc; 99 ac = (struct ad1848_softc *)&sc->sc_ad1848; 100 if (ia->ia_nio < 1) 101 return 0; 102 if (ia->ia_nirq < 1) 103 return 0; 104 if (ia->ia_ndrq < 1) 105 return 0; 106 107 if (ISA_DIRECT_CONFIG(ia)) 108 return 0; 109 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); 115 madunmap(sc); 116 return 1; 117 } else 118 /* Everything is already unmapped */ 119 return 0; 120 } 121 122 static int 123 wssfind(device_t parent, struct wss_softc *sc, int probing, 124 struct isa_attach_args *ia) 125 { 126 static u_char interrupt_bits[12] = { 127 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 128 }; 129 static u_char dma_bits[4] = {1, 2, 0, 3}; 130 struct ad1848_softc *ac; 131 int ndrq, playdrq, recdrq; 132 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); 137 else 138 sc->mad_chip_type = MAD_NONE; 139 140 #if 0 141 if (!WSS_BASE_VALID(ia->ia_io[0].ir_addr)) { 142 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); 143 goto bad1; 144 } 145 #endif 146 147 /* Map the ports upto the AD1848 port */ 148 if (bus_space_map(sc->sc_iot, ia->ia_io[0].ir_addr, WSS_CODEC, 149 0, &sc->sc_ioh)) 150 goto bad1; 151 152 ac->sc_iot = sc->sc_iot; 153 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) 157 goto bad; 158 159 #if 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)); 164 goto bad; 165 } 166 #endif 167 sc->wss_playdrq = ia->ia_drq[0].ir_drq; 168 sc->wss_ic = ia->ia_ic; 169 170 if (sc->wss_playdrq != ISA_UNKNOWN_DRQ && 171 !isa_drq_isfree(sc->wss_ic, sc->wss_playdrq)) 172 goto bad; 173 174 #if 0 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)); 178 goto bad; 179 } 180 #endif 181 182 sc->wss_irq = ia->ia_irq[0].ir_irq; 183 184 playdrq = ia->ia_drq[0].ir_drq; 185 if (ia->ia_ndrq > 1) { 186 ndrq = 2; 187 recdrq = ia->ia_drq[1].ir_drq; 188 } else { 189 ndrq = 1; 190 recdrq = ISA_UNKNOWN_DRQ; 191 } 192 193 if (ac->mode <= 1) 194 ndrq = 1; 195 sc->wss_recdrq = 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, 199 sc->wss_recdrq)) 200 goto bad; 201 202 if (probing) { 203 ia->ia_nio = 1; 204 ia->ia_io[0].ir_size = WSS_NPORT; 205 206 ia->ia_nirq = 1; 207 208 ia->ia_ndrq = ndrq; 209 ia->ia_drq[0].ir_drq = playdrq; 210 if (ndrq > 1) 211 ia->ia_drq[1].ir_drq = recdrq; 212 213 ia->ia_niomem = 0; 214 } 215 216 /* XXX 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])); 220 221 return 1; 222 223 bad: 224 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); 225 bad1: 226 madunmap(sc); 227 return 0; 228 } 229 230 /* 231 * Attach hardware to driver, attach hardware driver to audio 232 * pseudo-device driver . 233 */ 234 void 235 wss_isa_attach(device_t parent, device_t self, void *aux) 236 { 237 struct wss_softc *sc; 238 struct ad1848_softc *ac; 239 struct isa_attach_args *ia; 240 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"); 246 return; 247 } 248 249 sc->wss_ic = ia->ia_ic; 250 251 wssattach(sc); 252 } 253 254 /* 255 * Copyright by Hannu Savolainen 1994 256 * 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. 264 * 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 275 * SUCH DAMAGE. 276 * 277 */ 278 279 /* 280 * Initialization code for OPTi MAD16 compatible audio chips. Including 281 * 282 * OPTi 82C928 MAD16 (replaced by C929) 283 * OAK OTI-601D Mozart 284 * OPTi 82C929 MAD16 Pro 285 * OPTi 82C931 286 */ 287 288 static int 289 detect_mad16(struct wss_softc *sc, int chip_type) 290 { 291 unsigned char tmp, tmp2; 292 293 sc->mad_chip_type = chip_type; 294 /* 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 298 * bit should be 0. 299 */ 300 if ((tmp = mad_read(sc, MC1_PORT)) == 0xff) { 301 DPRINTF(("MC1_PORT returned 0xff\n")); 302 return 0; 303 } 304 305 /* 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). 308 */ 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)); 311 return 0; 312 } 313 314 mad_write(sc, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ 315 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)); 320 return 0; 321 } 322 323 mad_write(sc, MC1_PORT, tmp); /* Restore */ 324 return 1; 325 } 326 327 static void 328 madprobe(struct wss_softc *sc, int iobase) 329 { 330 static int valid_ports[M_WSS_NPORTS] = 331 { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 }; 332 int i; 333 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)) 336 goto bad0; 337 if (bus_space_map(sc->sc_iot, MAD_REG1, MAD_LEN1, 0, &sc->mad_ioh1)) 338 goto bad1; 339 if (bus_space_map(sc->sc_iot, MAD_REG2, MAD_LEN2, 0, &sc->mad_ioh2)) 340 goto bad2; 341 if (bus_space_map(sc->sc_iot, MAD_REG3, MAD_LEN3, 0, &sc->sc_opl_ioh)) 342 goto bad3; 343 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)) 349 goto bad; 350 sc->mad_chip_type = MAD_82C929; 351 DPRINTF(("mad: 82C929 detected\n")); 352 } else { 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; 357 } else { 358 DPRINTF(("mad: 82C928 detected?\n")); 359 sc->mad_chip_type = MAD_82C928; 360 } 361 } 362 363 #ifdef AUDIO_DEBUG 364 if (wssdebug) 365 for (i = MC1_PORT; i <= MC7_PORT; i++) 366 printf("mad: port %03x = %02x\n", i, mad_read(sc, i)); 367 #endif 368 369 /* Set the WSS address. */ 370 for (i = 0; i < M_WSS_NPORTS; i++) 371 if (valid_ports[i] == iobase) 372 break; 373 if (i >= M_WSS_NPORTS) { /* Not a valid port */ 374 printf("mad: Bad WSS base address 0x%x\n", iobase); 375 goto bad; 376 } 377 sc->mad_ioindex = i; 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 */ 382 return; 383 384 bad: 385 bus_space_unmap(sc->sc_iot, sc->sc_opl_ioh, MAD_LEN3); 386 bad3: 387 bus_space_unmap(sc->sc_iot, sc->mad_ioh2, MAD_LEN2); 388 bad2: 389 bus_space_unmap(sc->sc_iot, sc->mad_ioh1, MAD_LEN1); 390 bad1: 391 bus_space_unmap(sc->sc_iot, sc->mad_ioh, MAD_NPORT); 392 bad0: 393 sc->mad_chip_type = MAD_NONE; 394 } 395 396 static void 397 madunmap(struct wss_softc *sc) 398 { 399 400 if (sc->mad_chip_type == MAD_NONE) 401 return; 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); 406 } 407