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