1 /* $NetBSD: wss.c,v 1.57 1999/02/18 17:27:39 mycroft 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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the Computer Systems 19 * Engineering Group at Lawrence Berkeley Laboratory. 20 * 4. Neither the name of the University nor of the Laboratory may be used 21 * to endorse or promote products derived from this software without 22 * specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/device.h> 41 #include <sys/errno.h> 42 43 #include <machine/cpu.h> 44 #include <machine/intr.h> 45 #include <machine/bus.h> 46 47 #include <sys/audioio.h> 48 #include <dev/audio_if.h> 49 50 #include <dev/isa/isavar.h> 51 #include <dev/isa/isadmavar.h> 52 53 #include <dev/ic/ad1848reg.h> 54 #include <dev/ic/cs4231reg.h> 55 #include <dev/isa/ad1848var.h> 56 #include <dev/isa/cs4231var.h> 57 #include <dev/isa/wssreg.h> 58 #include <dev/isa/wssvar.h> 59 #include <dev/isa/madreg.h> 60 61 #ifdef AUDIO_DEBUG 62 #define DPRINTF(x) if (wssdebug) printf x 63 int wssdebug = 0; 64 #else 65 #define DPRINTF(x) 66 #endif 67 68 struct audio_device wss_device = { 69 "wss,ad1848", 70 "", 71 "WSS" 72 }; 73 74 int wss_getdev __P((void *, struct audio_device *)); 75 76 int wss_mixer_set_port __P((void *, mixer_ctrl_t *)); 77 int wss_mixer_get_port __P((void *, mixer_ctrl_t *)); 78 int wss_query_devinfo __P((void *, mixer_devinfo_t *)); 79 80 /* 81 * Define our interface to the higher level audio driver. 82 */ 83 84 struct audio_hw_if wss_hw_if = { 85 ad1848_isa_open, 86 ad1848_isa_close, 87 NULL, 88 ad1848_query_encoding, 89 ad1848_set_params, 90 ad1848_round_blocksize, 91 ad1848_commit_settings, 92 NULL, 93 NULL, 94 NULL, 95 NULL, 96 ad1848_isa_halt_output, 97 ad1848_isa_halt_input, 98 NULL, 99 wss_getdev, 100 NULL, 101 wss_mixer_set_port, 102 wss_mixer_get_port, 103 wss_query_devinfo, 104 ad1848_isa_malloc, 105 ad1848_isa_free, 106 ad1848_isa_round_buffersize, 107 ad1848_isa_mappage, 108 ad1848_isa_get_props, 109 ad1848_isa_trigger_output, 110 ad1848_isa_trigger_input, 111 }; 112 113 /* 114 * Attach hardware to driver, attach hardware driver to audio 115 * pseudo-device driver . 116 */ 117 void 118 wssattach(sc) 119 struct wss_softc *sc; 120 { 121 struct ad1848_softc *ac = &sc->sc_ad1848.sc_ad1848; 122 123 #if 0 /* loses on CS423X chips */ 124 int version; 125 #endif 126 127 madattach(sc); 128 129 sc->sc_ad1848.sc_ih = isa_intr_establish(sc->wss_ic, sc->wss_irq, 130 IST_EDGE, 131 IPL_AUDIO, ad1848_isa_intr, 132 &sc->sc_ad1848); 133 134 ad1848_isa_attach(&sc->sc_ad1848); 135 136 #if 0 /* loses on CS423X chips */ 137 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) 138 & WSS_VERSMASK; 139 printf(" (vers %d)", version); 140 #endif 141 142 switch(sc->mad_chip_type) { 143 case MAD_82C928: 144 printf(", 82C928"); 145 break; 146 case MAD_OTI601D: 147 printf(", OTI-601D"); 148 break; 149 case MAD_82C929: 150 printf(", 82C929"); 151 break; 152 case MAD_82C931: 153 printf(", 82C931"); 154 break; 155 default: 156 break; 157 } 158 printf("\n"); 159 160 ac->parent = sc; 161 162 audio_attach_mi(&wss_hw_if, &sc->sc_ad1848, &ac->sc_dev); 163 164 if (sc->mad_chip_type != MAD_NONE) { 165 struct audio_attach_args arg; 166 arg.type = AUDIODEV_TYPE_OPL; 167 arg.hwif = 0; 168 arg.hdl = 0; 169 (void)config_found(&ac->sc_dev, &arg, audioprint); 170 } 171 } 172 173 int 174 wss_getdev(addr, retp) 175 void *addr; 176 struct audio_device *retp; 177 { 178 *retp = wss_device; 179 return 0; 180 } 181 182 static ad1848_devmap_t mappings[] = { 183 { WSS_MIC_IN_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL }, 184 { WSS_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL }, 185 { WSS_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL }, 186 { WSS_MONITOR_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL }, 187 { WSS_MIC_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL }, 188 { WSS_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL }, 189 { WSS_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL }, 190 { WSS_MONITOR_MUTE, AD1848_KIND_MUTE, AD1848_MONO_CHANNEL }, 191 { WSS_REC_LVL, AD1848_KIND_RECORDGAIN, -1 }, 192 { WSS_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1} 193 }; 194 195 static int nummap = sizeof(mappings) / sizeof(mappings[0]); 196 197 int 198 wss_mixer_set_port(addr, cp) 199 void *addr; 200 mixer_ctrl_t *cp; 201 { 202 struct ad1848_softc *ac = addr; 203 204 return (ad1848_mixer_set_port(ac, mappings, nummap, cp)); 205 } 206 207 int 208 wss_mixer_get_port(addr, cp) 209 void *addr; 210 mixer_ctrl_t *cp; 211 { 212 struct ad1848_softc *ac = addr; 213 214 return (ad1848_mixer_get_port(ac, mappings, nummap, cp)); 215 } 216 217 int 218 wss_query_devinfo(addr, dip) 219 void *addr; 220 mixer_devinfo_t *dip; 221 { 222 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index)); 223 224 switch(dip->index) { 225 case WSS_MIC_IN_LVL: /* Microphone */ 226 dip->type = AUDIO_MIXER_VALUE; 227 dip->mixer_class = WSS_INPUT_CLASS; 228 dip->prev = AUDIO_MIXER_LAST; 229 dip->next = WSS_MIC_IN_MUTE; 230 strcpy(dip->label.name, AudioNmicrophone); 231 dip->un.v.num_channels = 2; 232 strcpy(dip->un.v.units.name, AudioNvolume); 233 break; 234 235 case WSS_LINE_IN_LVL: /* line/CD */ 236 dip->type = AUDIO_MIXER_VALUE; 237 dip->mixer_class = WSS_INPUT_CLASS; 238 dip->prev = AUDIO_MIXER_LAST; 239 dip->next = WSS_LINE_IN_MUTE; 240 strcpy(dip->label.name, AudioNcd); 241 dip->un.v.num_channels = 2; 242 strcpy(dip->un.v.units.name, AudioNvolume); 243 break; 244 245 case WSS_DAC_LVL: /* dacout */ 246 dip->type = AUDIO_MIXER_VALUE; 247 dip->mixer_class = WSS_INPUT_CLASS; 248 dip->prev = AUDIO_MIXER_LAST; 249 dip->next = WSS_DAC_MUTE; 250 strcpy(dip->label.name, AudioNdac); 251 dip->un.v.num_channels = 2; 252 strcpy(dip->un.v.units.name, AudioNvolume); 253 break; 254 255 case WSS_REC_LVL: /* record level */ 256 dip->type = AUDIO_MIXER_VALUE; 257 dip->mixer_class = WSS_RECORD_CLASS; 258 dip->prev = AUDIO_MIXER_LAST; 259 dip->next = WSS_RECORD_SOURCE; 260 strcpy(dip->label.name, AudioNrecord); 261 dip->un.v.num_channels = 2; 262 strcpy(dip->un.v.units.name, AudioNvolume); 263 break; 264 265 case WSS_MONITOR_LVL: /* monitor level */ 266 dip->type = AUDIO_MIXER_VALUE; 267 dip->mixer_class = WSS_MONITOR_CLASS; 268 dip->prev = AUDIO_MIXER_LAST; 269 dip->next = WSS_MONITOR_MUTE; 270 strcpy(dip->label.name, AudioNmonitor); 271 dip->un.v.num_channels = 1; 272 strcpy(dip->un.v.units.name, AudioNvolume); 273 break; 274 275 case WSS_INPUT_CLASS: /* input class descriptor */ 276 dip->type = AUDIO_MIXER_CLASS; 277 dip->mixer_class = WSS_INPUT_CLASS; 278 dip->next = dip->prev = AUDIO_MIXER_LAST; 279 strcpy(dip->label.name, AudioCinputs); 280 break; 281 282 case WSS_MONITOR_CLASS: /* monitor class descriptor */ 283 dip->type = AUDIO_MIXER_CLASS; 284 dip->mixer_class = WSS_MONITOR_CLASS; 285 dip->next = dip->prev = AUDIO_MIXER_LAST; 286 strcpy(dip->label.name, AudioCmonitor); 287 break; 288 289 case WSS_RECORD_CLASS: /* record source class */ 290 dip->type = AUDIO_MIXER_CLASS; 291 dip->mixer_class = WSS_RECORD_CLASS; 292 dip->next = dip->prev = AUDIO_MIXER_LAST; 293 strcpy(dip->label.name, AudioCrecord); 294 break; 295 296 case WSS_MIC_IN_MUTE: 297 dip->mixer_class = WSS_INPUT_CLASS; 298 dip->type = AUDIO_MIXER_ENUM; 299 dip->prev = WSS_MIC_IN_LVL; 300 dip->next = AUDIO_MIXER_LAST; 301 goto mute; 302 303 case WSS_LINE_IN_MUTE: 304 dip->mixer_class = WSS_INPUT_CLASS; 305 dip->type = AUDIO_MIXER_ENUM; 306 dip->prev = WSS_LINE_IN_LVL; 307 dip->next = AUDIO_MIXER_LAST; 308 goto mute; 309 310 case WSS_DAC_MUTE: 311 dip->mixer_class = WSS_INPUT_CLASS; 312 dip->type = AUDIO_MIXER_ENUM; 313 dip->prev = WSS_DAC_LVL; 314 dip->next = AUDIO_MIXER_LAST; 315 goto mute; 316 317 case WSS_MONITOR_MUTE: 318 dip->mixer_class = WSS_MONITOR_CLASS; 319 dip->type = AUDIO_MIXER_ENUM; 320 dip->prev = WSS_MONITOR_LVL; 321 dip->next = AUDIO_MIXER_LAST; 322 mute: 323 strcpy(dip->label.name, AudioNmute); 324 dip->un.e.num_mem = 2; 325 strcpy(dip->un.e.member[0].label.name, AudioNoff); 326 dip->un.e.member[0].ord = 0; 327 strcpy(dip->un.e.member[1].label.name, AudioNon); 328 dip->un.e.member[1].ord = 1; 329 break; 330 331 case WSS_RECORD_SOURCE: 332 dip->mixer_class = WSS_RECORD_CLASS; 333 dip->type = AUDIO_MIXER_ENUM; 334 dip->prev = WSS_REC_LVL; 335 dip->next = AUDIO_MIXER_LAST; 336 strcpy(dip->label.name, AudioNsource); 337 dip->un.e.num_mem = 3; 338 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 339 dip->un.e.member[0].ord = WSS_MIC_IN_LVL; 340 strcpy(dip->un.e.member[1].label.name, AudioNcd); 341 dip->un.e.member[1].ord = WSS_LINE_IN_LVL; 342 strcpy(dip->un.e.member[2].label.name, AudioNdac); 343 dip->un.e.member[2].ord = WSS_DAC_LVL; 344 break; 345 346 default: 347 return ENXIO; 348 /*NOTREACHED*/ 349 } 350 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 351 352 return 0; 353 } 354 355 356 /* 357 * Copyright by Hannu Savolainen 1994 358 * 359 * Redistribution and use in source and binary forms, with or without 360 * modification, are permitted provided that the following conditions are 361 * met: 1. Redistributions of source code must retain the above copyright 362 * notice, this list of conditions and the following disclaimer. 2. 363 * Redistributions in binary form must reproduce the above copyright notice, 364 * this list of conditions and the following disclaimer in the documentation 365 * and/or other materials provided with the distribution. 366 * 367 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 368 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 369 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 370 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 371 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 372 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 373 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 374 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 375 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 376 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 377 * SUCH DAMAGE. 378 * 379 */ 380 /* 381 * Initialization code for OPTi MAD16 compatible audio chips. Including 382 * 383 * OPTi 82C928 MAD16 (replaced by C929) 384 * OAK OTI-601D Mozart 385 * OPTi 82C929 MAD16 Pro 386 * 387 */ 388 389 u_int 390 mad_read(sc, port) 391 struct wss_softc *sc; 392 int port; 393 { 394 u_int tmp; 395 int pwd; 396 int s; 397 398 switch (sc->mad_chip_type) { /* Output password */ 399 case MAD_82C928: 400 case MAD_OTI601D: 401 pwd = M_PASSWD_928; 402 break; 403 case MAD_82C929: 404 pwd = M_PASSWD_929; 405 break; 406 case MAD_82C931: 407 pwd = M_PASSWD_931; 408 break; 409 default: 410 panic("mad_read: Bad chip type=%d\n", sc->mad_chip_type); 411 } 412 s = splaudio(); /* don't want an interrupt between outb&inb */ 413 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); 414 tmp = bus_space_read_1(sc->sc_iot, sc->mad_ioh, port); 415 splx(s); 416 return tmp; 417 } 418 419 void 420 mad_write(sc, port, value) 421 struct wss_softc *sc; 422 int port; 423 int value; 424 { 425 int pwd; 426 int s; 427 428 switch (sc->mad_chip_type) { /* Output password */ 429 case MAD_82C928: 430 case MAD_OTI601D: 431 pwd = M_PASSWD_928; 432 break; 433 case MAD_82C929: 434 pwd = M_PASSWD_929; 435 break; 436 case MAD_82C931: 437 pwd = M_PASSWD_931; 438 break; 439 default: 440 panic("mad_write: Bad chip type=%d\n", sc->mad_chip_type); 441 } 442 s = splaudio(); 443 bus_space_write_1(sc->sc_iot, sc->mad_ioh, MC_PASSWD_REG, pwd); 444 bus_space_write_1(sc->sc_iot, sc->mad_ioh, port, value & 0xff); 445 splx(s); 446 } 447 448 void 449 madattach(sc) 450 struct wss_softc *sc; 451 { 452 struct ad1848_softc *ac = (struct ad1848_softc *)&sc->sc_ad1848; 453 unsigned char cs4231_mode; 454 int joy; 455 456 if (sc->mad_chip_type == MAD_NONE) 457 return; 458 459 /* Do we want the joystick disabled? */ 460 joy = ac->sc_dev.dv_cfdata->cf_flags & 2 ? MC1_JOYDISABLE : 0; 461 462 /* enable WSS emulation at the I/O port */ 463 mad_write(sc, MC1_PORT, M_WSS_PORT_SELECT(sc->mad_ioindex) | joy); 464 mad_write(sc, MC2_PORT, MC2_NO_CD_DRQ); /* disable CD */ 465 mad_write(sc, MC3_PORT, 0xf0); /* Disable SB */ 466 467 cs4231_mode = 468 strncmp(ac->chip_name, "CS4248", 6) == 0 || 469 strncmp(ac->chip_name, "CS4231", 6) == 0 ? 0x02 : 0; 470 471 if (sc->mad_chip_type == MAD_82C929) { 472 mad_write(sc, MC4_PORT, 0x92); 473 mad_write(sc, MC5_PORT, 0xA5 | cs4231_mode); 474 mad_write(sc, MC6_PORT, 0x03); /* Disable MPU401 */ 475 } else { 476 mad_write(sc, MC4_PORT, 0x02); 477 mad_write(sc, MC5_PORT, 0x30 | cs4231_mode); 478 } 479 480 #ifdef AUDIO_DEBUG 481 if (wssdebug) { 482 int i; 483 for (i = MC1_PORT; i <= MC7_PORT; i++) 484 DPRINTF(("port %03x after init = %02x\n", 485 i, mad_read(sc, i))); 486 } 487 #endif 488 } 489