1 /* $NetBSD: wss.c,v 1.40 1997/11/30 15:24:59 drochner 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) 1995 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 * Copyright by Hannu Savolainen 1994 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions are 47 * met: 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 2. 49 * Redistributions in binary form must reproduce the above copyright notice, 50 * this list of conditions and the following disclaimer in the documentation 51 * and/or other materials provided with the distribution. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 54 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 55 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 56 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 57 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 59 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 60 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 */ 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/errno.h> 70 #include <sys/ioctl.h> 71 #include <sys/syslog.h> 72 #include <sys/device.h> 73 #include <sys/proc.h> 74 #include <sys/buf.h> 75 76 #include <machine/cpu.h> 77 #include <machine/intr.h> 78 #include <machine/bus.h> 79 #include <machine/pio.h> 80 81 #include <sys/audioio.h> 82 #include <dev/audio_if.h> 83 84 #include <dev/isa/isavar.h> 85 #include <dev/isa/isadmavar.h> 86 87 #include <dev/ic/ad1848reg.h> 88 #include <dev/isa/ad1848var.h> 89 #include <dev/isa/wssreg.h> 90 #include <dev/isa/madreg.h> 91 92 /* 93 * Mixer devices 94 */ 95 #define WSS_MIC_IN_LVL 0 96 #define WSS_LINE_IN_LVL 1 97 #define WSS_DAC_LVL 2 98 #define WSS_REC_LVL 3 99 #define WSS_MON_LVL 4 100 #define WSS_MIC_IN_MUTE 5 101 #define WSS_LINE_IN_MUTE 6 102 #define WSS_DAC_MUTE 7 103 104 #define WSS_RECORD_SOURCE 8 105 106 /* Classes */ 107 #define WSS_INPUT_CLASS 9 108 #define WSS_RECORD_CLASS 10 109 #define WSS_MONITOR_CLASS 11 110 111 #ifdef AUDIO_DEBUG 112 #define DPRINTF(x) if (wssdebug) printf x 113 int wssdebug = 0; 114 #else 115 #define DPRINTF(x) 116 #endif 117 118 struct wss_softc { 119 struct device sc_dev; /* base device */ 120 struct isadev sc_id; /* ISA device */ 121 void *sc_ih; /* interrupt vectoring */ 122 bus_space_tag_t sc_iot; /* tag */ 123 bus_space_handle_t sc_ioh; /* handle */ 124 125 struct ad1848_softc sc_ad1848; 126 #define wss_irq sc_ad1848.sc_irq 127 #define wss_drq sc_ad1848.sc_drq 128 129 int mic_mute, cd_mute, dac_mute; 130 int mad_chip_type; /* chip type if MAD emulation of WSS */ 131 bus_space_handle_t sc_mad_ioh; /* MAD handle */ 132 bus_space_handle_t sc_mad_ioh1, sc_mad_ioh2, sc_mad_ioh3; 133 }; 134 135 struct audio_device wss_device = { 136 "wss,ad1848", 137 "", 138 "WSS" 139 }; 140 141 int wss_getdev __P((void *, struct audio_device *)); 142 143 int wss_mixer_set_port __P((void *, mixer_ctrl_t *)); 144 int wss_mixer_get_port __P((void *, mixer_ctrl_t *)); 145 int wss_query_devinfo __P((void *, mixer_devinfo_t *)); 146 147 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); 148 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); 149 150 static int wssfind __P((struct device *, struct wss_softc *, struct isa_attach_args *)); 151 152 static int madprobe __P((struct wss_softc *, int)); 153 static void madattach __P((struct wss_softc *)); 154 static void madunmap __P((struct wss_softc *)); 155 156 /* 157 * Define our interface to the higher level audio driver. 158 */ 159 160 struct audio_hw_if wss_hw_if = { 161 ad1848_open, 162 ad1848_close, 163 NULL, 164 ad1848_query_encoding, 165 ad1848_set_params, 166 ad1848_round_blocksize, 167 ad1848_commit_settings, 168 ad1848_dma_init_output, 169 ad1848_dma_init_input, 170 ad1848_dma_output, 171 ad1848_dma_input, 172 ad1848_halt_out_dma, 173 ad1848_halt_in_dma, 174 NULL, 175 wss_getdev, 176 NULL, 177 wss_mixer_set_port, 178 wss_mixer_get_port, 179 wss_query_devinfo, 180 ad1848_malloc, 181 ad1848_free, 182 ad1848_round, 183 ad1848_mappage, 184 ad1848_get_props, 185 }; 186 187 #ifdef __BROKEN_INDIRECT_CONFIG 188 int wssprobe __P((struct device *, void *, void *)); 189 #else 190 int wssprobe __P((struct device *, struct cfdata *, void *)); 191 #endif 192 void wssattach __P((struct device *, struct device *, void *)); 193 194 struct cfattach wss_ca = { 195 sizeof(struct wss_softc), wssprobe, wssattach 196 }; 197 198 struct cfdriver wss_cd = { 199 NULL, "wss", DV_DULL 200 }; 201 202 /* 203 * Probe for the Microsoft Sound System hardware. 204 */ 205 int 206 wssprobe(parent, match, aux) 207 struct device *parent; 208 #ifdef __BROKEN_INDIRECT_CONFIG 209 void *match; 210 #else 211 struct cfdata *match; 212 #endif 213 void *aux; 214 { 215 struct wss_softc probesc, *sc = &probesc; 216 217 bzero(sc, sizeof *sc); 218 #ifdef __BROKEN_INDIRECT_CONFIG 219 sc->sc_dev.dv_cfdata = ((struct device *)match)->dv_cfdata; 220 #else 221 sc->sc_dev.dv_cfdata = match; 222 #endif 223 if (wssfind(parent, sc, aux)) { 224 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); 225 ad1848_unmap(&sc->sc_ad1848); 226 madunmap(sc); 227 return 1; 228 } else 229 /* Everything is already unmapped */ 230 return 0; 231 } 232 233 static int 234 wssfind(parent, sc, ia) 235 struct device *parent; 236 struct wss_softc *sc; 237 struct isa_attach_args *ia; 238 { 239 static u_char interrupt_bits[12] = { 240 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 241 }; 242 static u_char dma_bits[4] = {1, 2, 0, 3}; 243 244 sc->sc_iot = ia->ia_iot; 245 if (sc->sc_dev.dv_cfdata->cf_flags & 1) 246 sc->mad_chip_type = madprobe(sc, ia->ia_iobase); 247 else 248 sc->mad_chip_type = MAD_NONE; 249 250 if (!WSS_BASE_VALID(ia->ia_iobase)) { 251 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); 252 goto bad1; 253 } 254 255 /* Map the ports upto the AD1848 port */ 256 if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh)) 257 goto bad1; 258 259 sc->sc_ad1848.sc_iot = sc->sc_iot; 260 sc->sc_ad1848.sc_iobase = ia->ia_iobase + WSS_CODEC; 261 262 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */ 263 if (ad1848_probe(&sc->sc_ad1848) == 0) 264 goto bad; 265 266 ia->ia_iosize = WSS_NPORT; 267 268 /* Setup WSS interrupt and DMA */ 269 if (!WSS_DRQ_VALID(ia->ia_drq)) { 270 DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq)); 271 goto bad; 272 } 273 sc->wss_drq = ia->ia_drq; 274 275 /* XXX reqdrq? */ 276 if (sc->wss_drq != -1 && isa_drq_isfree(parent, sc->wss_drq) == 0) 277 goto bad; 278 279 #ifdef NEWCONFIG 280 /* 281 * If the IRQ wasn't compiled in, auto-detect it. 282 */ 283 if (ia->ia_irq == IRQUNK) { 284 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848); 285 if (!WSS_IRQ_VALID(ia->ia_irq)) { 286 printf("wss: couldn't auto-detect interrupt\n"); 287 goto bad; 288 } 289 } 290 else 291 #endif 292 if (!WSS_IRQ_VALID(ia->ia_irq)) { 293 DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq)); 294 goto bad; 295 } 296 297 sc->wss_irq = ia->ia_irq; 298 299 bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG, 300 (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq])); 301 302 if (sc->sc_ad1848.mode <= 1) 303 ia->ia_drq2 = -1; 304 return 1; 305 306 bad: 307 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); 308 bad1: 309 madunmap(sc); 310 return 0; 311 } 312 313 /* 314 * Attach hardware to driver, attach hardware driver to audio 315 * pseudo-device driver . 316 */ 317 void 318 wssattach(parent, self, aux) 319 struct device *parent, *self; 320 void *aux; 321 { 322 struct wss_softc *sc = (struct wss_softc *)self; 323 struct isa_attach_args *ia = (struct isa_attach_args *)aux; 324 int version; 325 326 if (!wssfind(parent, sc, ia)) { 327 printf("%s: wssfind failed\n", sc->sc_dev.dv_xname); 328 return; 329 } 330 331 madattach(sc); 332 333 sc->sc_ad1848.sc_recdrq = sc->sc_ad1848.mode > 1 && ia->ia_drq2 != -1 ? ia->ia_drq2 : ia->ia_drq; 334 sc->sc_ad1848.sc_isa = parent; 335 336 #ifdef NEWCONFIG 337 isa_establish(&sc->sc_id, &sc->sc_dev); 338 #endif 339 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, 340 ad1848_intr, &sc->sc_ad1848); 341 342 ad1848_attach(&sc->sc_ad1848); 343 344 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK; 345 printf(" (vers %d)", version); 346 if (sc->mad_chip_type != MAD_NONE) 347 printf(", %s", 348 sc->mad_chip_type == MAD_82C929 ? "82C929" : 349 sc->mad_chip_type == MAD_82C928 ? "82C928" : 350 "OTI-601D"); 351 printf("\n"); 352 353 sc->sc_ad1848.parent = sc; 354 355 audio_attach_mi(&wss_hw_if, 0, &sc->sc_ad1848, &sc->sc_dev); 356 } 357 358 static int 359 wss_to_vol(cp, vol) 360 mixer_ctrl_t *cp; 361 struct ad1848_volume *vol; 362 { 363 if (cp->un.value.num_channels == 1) { 364 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 365 return(1); 366 } 367 else if (cp->un.value.num_channels == 2) { 368 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 369 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 370 return(1); 371 } 372 return(0); 373 } 374 375 static int 376 wss_from_vol(cp, vol) 377 mixer_ctrl_t *cp; 378 struct ad1848_volume *vol; 379 { 380 if (cp->un.value.num_channels == 1) { 381 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left; 382 return(1); 383 } 384 else if (cp->un.value.num_channels == 2) { 385 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left; 386 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right; 387 return(1); 388 } 389 return(0); 390 } 391 392 int 393 wss_getdev(addr, retp) 394 void *addr; 395 struct audio_device *retp; 396 { 397 *retp = wss_device; 398 return 0; 399 } 400 401 int 402 wss_mixer_set_port(addr, cp) 403 void *addr; 404 mixer_ctrl_t *cp; 405 { 406 struct ad1848_softc *ac = addr; 407 struct wss_softc *sc = ac->parent; 408 struct ad1848_volume vol; 409 int error = EINVAL; 410 411 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type)); 412 413 switch (cp->dev) { 414 case WSS_MIC_IN_LVL: /* Microphone */ 415 if (cp->type == AUDIO_MIXER_VALUE) { 416 if (wss_to_vol(cp, &vol)) 417 error = ad1848_set_aux2_gain(ac, &vol); 418 } 419 break; 420 421 case WSS_MIC_IN_MUTE: /* Microphone */ 422 if (cp->type == AUDIO_MIXER_ENUM) { 423 sc->mic_mute = cp->un.ord; 424 DPRINTF(("mic mute %d\n", cp->un.ord)); 425 error = 0; 426 } 427 break; 428 429 case WSS_LINE_IN_LVL: /* linein/CD */ 430 if (cp->type == AUDIO_MIXER_VALUE) { 431 if (wss_to_vol(cp, &vol)) 432 error = ad1848_set_aux1_gain(ac, &vol); 433 } 434 break; 435 436 case WSS_LINE_IN_MUTE: /* linein/CD */ 437 if (cp->type == AUDIO_MIXER_ENUM) { 438 sc->cd_mute = cp->un.ord; 439 DPRINTF(("CD mute %d\n", cp->un.ord)); 440 error = 0; 441 } 442 break; 443 444 case WSS_DAC_LVL: /* dac out */ 445 if (cp->type == AUDIO_MIXER_VALUE) { 446 if (wss_to_vol(cp, &vol)) 447 error = ad1848_set_out_gain(ac, &vol); 448 } 449 break; 450 451 case WSS_DAC_MUTE: /* dac out */ 452 if (cp->type == AUDIO_MIXER_ENUM) { 453 sc->dac_mute = cp->un.ord; 454 DPRINTF(("DAC mute %d\n", cp->un.ord)); 455 error = 0; 456 } 457 break; 458 459 case WSS_REC_LVL: /* record level */ 460 if (cp->type == AUDIO_MIXER_VALUE) { 461 if (wss_to_vol(cp, &vol)) 462 error = ad1848_set_rec_gain(ac, &vol); 463 } 464 break; 465 466 case WSS_RECORD_SOURCE: 467 if (cp->type == AUDIO_MIXER_ENUM) { 468 error = ad1848_set_rec_port(ac, cp->un.ord); 469 } 470 break; 471 472 case WSS_MON_LVL: 473 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) { 474 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 475 error = ad1848_set_mon_gain(ac, &vol); 476 } 477 break; 478 479 default: 480 return ENXIO; 481 /*NOTREACHED*/ 482 } 483 484 return 0; 485 } 486 487 int 488 wss_mixer_get_port(addr, cp) 489 void *addr; 490 mixer_ctrl_t *cp; 491 { 492 struct ad1848_softc *ac = addr; 493 struct wss_softc *sc = ac->parent; 494 struct ad1848_volume vol; 495 int error = EINVAL; 496 497 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev)); 498 499 switch (cp->dev) { 500 case WSS_MIC_IN_LVL: /* Microphone */ 501 if (cp->type == AUDIO_MIXER_VALUE) { 502 error = ad1848_get_aux2_gain(ac, &vol); 503 if (!error) 504 wss_from_vol(cp, &vol); 505 } 506 break; 507 508 case WSS_MIC_IN_MUTE: 509 if (cp->type == AUDIO_MIXER_ENUM) { 510 cp->un.ord = sc->mic_mute; 511 error = 0; 512 } 513 break; 514 515 case WSS_LINE_IN_LVL: /* linein/CD */ 516 if (cp->type == AUDIO_MIXER_VALUE) { 517 error = ad1848_get_aux1_gain(ac, &vol); 518 if (!error) 519 wss_from_vol(cp, &vol); 520 } 521 break; 522 523 case WSS_LINE_IN_MUTE: 524 if (cp->type == AUDIO_MIXER_ENUM) { 525 cp->un.ord = sc->cd_mute; 526 error = 0; 527 } 528 break; 529 530 case WSS_DAC_LVL: /* dac out */ 531 if (cp->type == AUDIO_MIXER_VALUE) { 532 error = ad1848_get_out_gain(ac, &vol); 533 if (!error) 534 wss_from_vol(cp, &vol); 535 } 536 break; 537 538 case WSS_DAC_MUTE: 539 if (cp->type == AUDIO_MIXER_ENUM) { 540 cp->un.ord = sc->dac_mute; 541 error = 0; 542 } 543 break; 544 545 case WSS_REC_LVL: /* record level */ 546 if (cp->type == AUDIO_MIXER_VALUE) { 547 error = ad1848_get_rec_gain(ac, &vol); 548 if (!error) 549 wss_from_vol(cp, &vol); 550 } 551 break; 552 553 case WSS_RECORD_SOURCE: 554 if (cp->type == AUDIO_MIXER_ENUM) { 555 cp->un.ord = ad1848_get_rec_port(ac); 556 error = 0; 557 } 558 break; 559 560 case WSS_MON_LVL: /* monitor level */ 561 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) { 562 error = ad1848_get_mon_gain(ac, &vol); 563 if (!error) 564 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left; 565 } 566 break; 567 568 default: 569 error = ENXIO; 570 break; 571 } 572 573 return(error); 574 } 575 576 int 577 wss_query_devinfo(addr, dip) 578 void *addr; 579 mixer_devinfo_t *dip; 580 { 581 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index)); 582 583 switch(dip->index) { 584 case WSS_MIC_IN_LVL: /* Microphone */ 585 dip->type = AUDIO_MIXER_VALUE; 586 dip->mixer_class = WSS_INPUT_CLASS; 587 dip->prev = AUDIO_MIXER_LAST; 588 dip->next = WSS_MIC_IN_MUTE; 589 strcpy(dip->label.name, AudioNmicrophone); 590 dip->un.v.num_channels = 2; 591 strcpy(dip->un.v.units.name, AudioNvolume); 592 break; 593 594 case WSS_LINE_IN_LVL: /* line/CD */ 595 dip->type = AUDIO_MIXER_VALUE; 596 dip->mixer_class = WSS_INPUT_CLASS; 597 dip->prev = AUDIO_MIXER_LAST; 598 dip->next = WSS_LINE_IN_MUTE; 599 strcpy(dip->label.name, AudioNcd); 600 dip->un.v.num_channels = 2; 601 strcpy(dip->un.v.units.name, AudioNvolume); 602 break; 603 604 case WSS_DAC_LVL: /* dacout */ 605 dip->type = AUDIO_MIXER_VALUE; 606 dip->mixer_class = WSS_INPUT_CLASS; 607 dip->prev = AUDIO_MIXER_LAST; 608 dip->next = WSS_DAC_MUTE; 609 strcpy(dip->label.name, AudioNdac); 610 dip->un.v.num_channels = 2; 611 strcpy(dip->un.v.units.name, AudioNvolume); 612 break; 613 614 case WSS_REC_LVL: /* record level */ 615 dip->type = AUDIO_MIXER_VALUE; 616 dip->mixer_class = WSS_RECORD_CLASS; 617 dip->prev = AUDIO_MIXER_LAST; 618 dip->next = WSS_RECORD_SOURCE; 619 strcpy(dip->label.name, AudioNrecord); 620 dip->un.v.num_channels = 2; 621 strcpy(dip->un.v.units.name, AudioNvolume); 622 break; 623 624 case WSS_MON_LVL: /* monitor level */ 625 dip->type = AUDIO_MIXER_VALUE; 626 dip->mixer_class = WSS_MONITOR_CLASS; 627 dip->next = dip->prev = AUDIO_MIXER_LAST; 628 strcpy(dip->label.name, AudioNmonitor); 629 dip->un.v.num_channels = 1; 630 strcpy(dip->un.v.units.name, AudioNvolume); 631 break; 632 633 case WSS_INPUT_CLASS: /* input class descriptor */ 634 dip->type = AUDIO_MIXER_CLASS; 635 dip->mixer_class = WSS_INPUT_CLASS; 636 dip->next = dip->prev = AUDIO_MIXER_LAST; 637 strcpy(dip->label.name, AudioCinputs); 638 break; 639 640 case WSS_MONITOR_CLASS: /* monitor class descriptor */ 641 dip->type = AUDIO_MIXER_CLASS; 642 dip->mixer_class = WSS_MONITOR_CLASS; 643 dip->next = dip->prev = AUDIO_MIXER_LAST; 644 strcpy(dip->label.name, AudioCmonitor); 645 break; 646 647 case WSS_RECORD_CLASS: /* record source class */ 648 dip->type = AUDIO_MIXER_CLASS; 649 dip->mixer_class = WSS_RECORD_CLASS; 650 dip->next = dip->prev = AUDIO_MIXER_LAST; 651 strcpy(dip->label.name, AudioCrecord); 652 break; 653 654 case WSS_MIC_IN_MUTE: 655 dip->mixer_class = WSS_INPUT_CLASS; 656 dip->type = AUDIO_MIXER_ENUM; 657 dip->prev = WSS_MIC_IN_LVL; 658 dip->next = AUDIO_MIXER_LAST; 659 goto mute; 660 661 case WSS_LINE_IN_MUTE: 662 dip->mixer_class = WSS_INPUT_CLASS; 663 dip->type = AUDIO_MIXER_ENUM; 664 dip->prev = WSS_LINE_IN_LVL; 665 dip->next = AUDIO_MIXER_LAST; 666 goto mute; 667 668 case WSS_DAC_MUTE: 669 dip->mixer_class = WSS_INPUT_CLASS; 670 dip->type = AUDIO_MIXER_ENUM; 671 dip->prev = WSS_DAC_LVL; 672 dip->next = AUDIO_MIXER_LAST; 673 mute: 674 strcpy(dip->label.name, AudioNmute); 675 dip->un.e.num_mem = 2; 676 strcpy(dip->un.e.member[0].label.name, AudioNoff); 677 dip->un.e.member[0].ord = 0; 678 strcpy(dip->un.e.member[1].label.name, AudioNon); 679 dip->un.e.member[1].ord = 1; 680 break; 681 682 case WSS_RECORD_SOURCE: 683 dip->mixer_class = WSS_RECORD_CLASS; 684 dip->type = AUDIO_MIXER_ENUM; 685 dip->prev = WSS_REC_LVL; 686 dip->next = AUDIO_MIXER_LAST; 687 strcpy(dip->label.name, AudioNsource); 688 dip->un.e.num_mem = 3; 689 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 690 dip->un.e.member[0].ord = WSS_MIC_IN_LVL; 691 strcpy(dip->un.e.member[1].label.name, AudioNcd); 692 dip->un.e.member[1].ord = WSS_LINE_IN_LVL; 693 strcpy(dip->un.e.member[2].label.name, AudioNdac); 694 dip->un.e.member[2].ord = WSS_DAC_LVL; 695 break; 696 697 default: 698 return ENXIO; 699 /*NOTREACHED*/ 700 } 701 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 702 703 return 0; 704 } 705 706 /* 707 * Initialization code for OPTi MAD16 compatible audio chips. Including 708 * 709 * OPTi 82C928 MAD16 (replaced by C929) 710 * OAK OTI-601D Mozart 711 * OPTi 82C929 MAD16 Pro 712 * 713 */ 714 static unsigned int mad_read __P((struct wss_softc *, int, int)); 715 static void mad_write __P((struct wss_softc *, int, int, int)); 716 static int detect_mad16 __P((struct wss_softc *, int)); 717 718 static unsigned int 719 mad_read(sc, chip_type, port) 720 struct wss_softc *sc; 721 int chip_type; 722 int port; 723 { 724 unsigned int tmp; 725 int s = splaudio(); /* don't want an interrupt between outb&inb */ 726 727 switch (chip_type) { /* Output password */ 728 case MAD_82C928: 729 case MAD_OTI601D: 730 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928); 731 break; 732 case MAD_82C929: 733 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929); 734 break; 735 } 736 tmp = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, port); 737 splx(s); 738 return tmp; 739 } 740 741 static void 742 mad_write(sc, chip_type, port, value) 743 struct wss_softc *sc; 744 int chip_type; 745 int port; 746 int value; 747 { 748 int s = splaudio(); /* don't want an interrupt between outb&outb */ 749 750 switch (chip_type) { /* Output password */ 751 case MAD_82C928: 752 case MAD_OTI601D: 753 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928); 754 break; 755 case MAD_82C929: 756 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929); 757 break; 758 } 759 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, port, value & 0xff); 760 splx(s); 761 } 762 763 static int 764 detect_mad16(sc, chip_type) 765 struct wss_softc *sc; 766 int chip_type; 767 { 768 unsigned char tmp, tmp2; 769 770 /* 771 * Check that reading a register doesn't return bus float (0xff) 772 * when the card is accessed using password. This may fail in case 773 * the card is in low power mode. Normally at least the power saving mode 774 * bit should be 0. 775 */ 776 if ((tmp = mad_read(sc, chip_type, MC1_PORT)) == 0xff) { 777 DPRINTF(("MC1_PORT returned 0xff\n")); 778 return 0; 779 } 780 781 /* 782 * Now check that the gate is closed on first I/O after writing 783 * the password. (This is how a MAD16 compatible card works). 784 */ 785 if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, MC1_PORT)) == tmp) { /* It didn't close */ 786 DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); 787 return 0; 788 } 789 790 mad_write(sc, chip_type, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ 791 792 /* Compare the bit */ 793 if ((tmp2 = mad_read(sc, chip_type, MC1_PORT)) != (tmp ^ 0x80)) { 794 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */ 795 DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); 796 return 0; 797 } 798 799 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */ 800 return 1; 801 } 802 803 static int 804 madprobe(sc, iobase) 805 struct wss_softc *sc; 806 int iobase; 807 { 808 static int valid_ports[M_WSS_NPORTS] = 809 { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 }; 810 int i; 811 int chip_type; 812 813 if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->sc_mad_ioh)) 814 return MAD_NONE; 815 816 /* Allocate bus space that the MAD chip wants */ 817 if (bus_space_map(sc->sc_iot, MAD_REG1, MAD_LEN1, 0, &sc->sc_mad_ioh1)) 818 goto bad1; 819 if (bus_space_map(sc->sc_iot, MAD_REG2, MAD_LEN2, 0, &sc->sc_mad_ioh2)) 820 goto bad2; 821 if (bus_space_map(sc->sc_iot, MAD_REG3, MAD_LEN3, 0, &sc->sc_mad_ioh3)) 822 goto bad3; 823 824 DPRINTF(("mad: Detect using password = 0xE2\n")); 825 if (!detect_mad16(sc, MAD_82C928)) { 826 /* No luck. Try different model */ 827 DPRINTF(("mad: Detect using password = 0xE3\n")); 828 if (!detect_mad16(sc, MAD_82C929)) 829 goto bad; 830 chip_type = MAD_82C929; 831 DPRINTF(("mad: 82C929 detected\n")); 832 } else { 833 if ((mad_read(sc, MAD_82C928, MC3_PORT) & 0x03) == 0x03) { 834 DPRINTF(("mad: Mozart detected\n")); 835 chip_type = MAD_OTI601D; 836 } else { 837 DPRINTF(("mad: 82C928 detected?\n")); 838 chip_type = MAD_82C928; 839 } 840 } 841 842 #ifdef AUDIO_DEBUG 843 if (wssdebug) 844 for (i = MC1_PORT; i <= MC7_PORT; i++) 845 printf("mad: port %03x = %02x\n", i, mad_read(sc, chip_type, i)); 846 #endif 847 848 /* Set the WSS address. */ 849 for (i = 0; i < M_WSS_NPORTS; i++) 850 if (valid_ports[i] == iobase) 851 break; 852 if (i >= M_WSS_NPORTS) { /* Not a valid port */ 853 printf("mad: Bad WSS base address 0x%x\n", iobase); 854 goto bad; 855 } 856 /* enable WSS emulation at the I/O port, no joystick */ 857 mad_write(sc, chip_type, MC1_PORT, M_WSS_PORT_SELECT(i) | MC1_JOYDISABLE); 858 859 mad_write(sc, chip_type, MC2_PORT, 0x03); /* ? */ 860 mad_write(sc, chip_type, MC3_PORT, 0xf0); /* Disable SB */ 861 862 return chip_type; 863 bad: 864 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh3, MAD_LEN3); 865 bad3: 866 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh2, MAD_LEN2); 867 bad2: 868 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh1, MAD_LEN1); 869 bad1: 870 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT); 871 return MAD_NONE; 872 } 873 874 static void 875 madunmap(sc) 876 struct wss_softc *sc; 877 { 878 if (sc->mad_chip_type == MAD_NONE) 879 return; 880 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT); 881 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh1, MAD_LEN1); 882 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh2, MAD_LEN2); 883 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh3, MAD_LEN3); 884 } 885 886 static void 887 madattach(sc) 888 struct wss_softc *sc; 889 { 890 int chip_type = sc->mad_chip_type; 891 unsigned char cs4231_mode; 892 893 if (chip_type == MAD_NONE) 894 return; 895 896 cs4231_mode = 897 strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 || 898 strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0; 899 900 if (chip_type == MAD_82C929) { 901 mad_write(sc, chip_type, MC4_PORT, 0xa2); 902 mad_write(sc, chip_type, MC5_PORT, 0xA5 | cs4231_mode); 903 mad_write(sc, chip_type, MC6_PORT, 0x03); /* Disable MPU401 */ 904 } else { 905 mad_write(sc, chip_type, MC4_PORT, 0x02); 906 mad_write(sc, chip_type, MC5_PORT, 0x30 | cs4231_mode); 907 } 908 909 #ifdef AUDIO_DEBUG 910 if (wssdebug) { 911 int i; 912 for (i = MC1_PORT; i <= MC7_PORT; i++) 913 DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, chip_type, i))); 914 } 915 #endif 916 } 917