1 /* $NetBSD: wss.c,v 1.26 1997/06/06 23:44:09 thorpej 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; /* handle */ 132 }; 133 134 struct audio_device wss_device = { 135 "wss,ad1848", 136 "", 137 "WSS" 138 }; 139 140 int wssopen __P((dev_t, int)); 141 int wss_getdev __P((void *, struct audio_device *)); 142 int wss_setfd __P((void *, int)); 143 144 int wss_set_out_port __P((void *, int)); 145 int wss_get_out_port __P((void *)); 146 int wss_set_in_port __P((void *, int)); 147 int wss_get_in_port __P((void *)); 148 int wss_mixer_set_port __P((void *, mixer_ctrl_t *)); 149 int wss_mixer_get_port __P((void *, mixer_ctrl_t *)); 150 int wss_query_devinfo __P((void *, mixer_devinfo_t *)); 151 152 static int wss_to_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); 153 static int wss_from_vol __P((mixer_ctrl_t *, struct ad1848_volume *)); 154 155 static int madprobe __P((struct wss_softc *, int)); 156 static void madprobedone __P((struct wss_softc *)); 157 158 /* 159 * Define our interface to the higher level audio driver. 160 */ 161 162 struct audio_hw_if wss_hw_if = { 163 wssopen, 164 ad1848_close, 165 NULL, 166 ad1848_query_encoding, 167 ad1848_set_params, 168 ad1848_round_blocksize, 169 wss_set_out_port, 170 wss_get_out_port, 171 wss_set_in_port, 172 wss_get_in_port, 173 ad1848_commit_settings, 174 ad1848_dma_output, 175 ad1848_dma_input, 176 ad1848_halt_out_dma, 177 ad1848_halt_in_dma, 178 ad1848_cont_out_dma, 179 ad1848_cont_in_dma, 180 NULL, 181 wss_getdev, 182 wss_setfd, 183 wss_mixer_set_port, 184 wss_mixer_get_port, 185 wss_query_devinfo, 186 0, /* not full-duplex */ 187 0 188 }; 189 190 int wssprobe __P((struct device *, void *, void *)); 191 void wssattach __P((struct device *, struct device *, void *)); 192 193 struct cfattach wss_ca = { 194 sizeof(struct wss_softc), wssprobe, wssattach 195 }; 196 197 struct cfdriver wss_cd = { 198 NULL, "wss", DV_DULL 199 }; 200 201 /* 202 * Probe for the Microsoft Sound System hardware. 203 */ 204 int 205 wssprobe(parent, match, aux) 206 struct device *parent; 207 void *match, *aux; 208 { 209 register struct wss_softc *sc = match; 210 register struct isa_attach_args *ia = aux; 211 static u_char interrupt_bits[12] = { 212 -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 213 }; 214 static u_char dma_bits[4] = {1, 2, 0, 3}; 215 216 sc->sc_iot = ia->ia_iot; 217 if (sc->sc_dev.dv_cfdata->cf_flags & 1) 218 sc->mad_chip_type = madprobe(sc, ia->ia_iobase); 219 else 220 sc->mad_chip_type = MAD_NONE; 221 222 if (!WSS_BASE_VALID(ia->ia_iobase)) { 223 DPRINTF(("wss: configured iobase %x invalid\n", ia->ia_iobase)); 224 return 0; 225 } 226 227 /* map the ports upto the AD1488 port */ 228 if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh)) 229 return 0; 230 231 sc->sc_ad1848.sc_iot = sc->sc_iot; 232 sc->sc_ad1848.sc_iobase = ia->ia_iobase + WSS_CODEC; 233 234 /* Is there an ad1848 chip at (WSS iobase + WSS_CODEC)? */ 235 if (ad1848_probe(&sc->sc_ad1848) == 0) 236 goto bad; 237 238 ia->ia_iosize = WSS_NPORT; 239 240 /* Setup WSS interrupt and DMA */ 241 if (!WSS_DRQ_VALID(ia->ia_drq)) { 242 DPRINTF(("wss: configured dma chan %d invalid\n", ia->ia_drq)); 243 goto bad; 244 } 245 sc->wss_drq = ia->ia_drq; 246 247 #ifdef NEWCONFIG 248 /* 249 * If the IRQ wasn't compiled in, auto-detect it. 250 */ 251 if (ia->ia_irq == IRQUNK) { 252 ia->ia_irq = isa_discoverintr(ad1848_forceintr, &sc->sc_ad1848); 253 if (!WSS_IRQ_VALID(ia->ia_irq)) { 254 printf("wss: couldn't auto-detect interrupt\n"); 255 goto bad; 256 } 257 } 258 else 259 #endif 260 if (!WSS_IRQ_VALID(ia->ia_irq)) { 261 DPRINTF(("wss: configured interrupt %d invalid\n", ia->ia_irq)); 262 goto bad; 263 } 264 265 sc->wss_irq = ia->ia_irq; 266 267 bus_space_write_1(sc->sc_iot, sc->sc_ioh, WSS_CONFIG, 268 (interrupt_bits[ia->ia_irq] | dma_bits[ia->ia_drq])); 269 270 if (sc->mad_chip_type != MAD_NONE) 271 madprobedone(sc); 272 273 return 1; 274 275 bad: 276 bus_space_unmap(sc->sc_iot, sc->sc_ioh, WSS_CODEC); 277 if (sc->mad_chip_type != MAD_NONE) 278 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT); 279 return 0; 280 } 281 282 /* 283 * Attach hardware to driver, attach hardware driver to audio 284 * pseudo-device driver . 285 */ 286 void 287 wssattach(parent, self, aux) 288 struct device *parent, *self; 289 void *aux; 290 { 291 register struct wss_softc *sc = (struct wss_softc *)self; 292 struct isa_attach_args *ia = (struct isa_attach_args *)aux; 293 int version; 294 int err; 295 296 sc->sc_ad1848.sc_recdrq = ia->ia_drq; 297 sc->sc_ad1848.sc_isa = parent; 298 299 #ifdef NEWCONFIG 300 isa_establish(&sc->sc_id, &sc->sc_dev); 301 #endif 302 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO, 303 ad1848_intr, &sc->sc_ad1848); 304 305 ad1848_attach(&sc->sc_ad1848); 306 307 version = bus_space_read_1(sc->sc_iot, sc->sc_ioh, WSS_STATUS) & WSS_VERSMASK; 308 printf(" (vers %d)", version); 309 if (sc->mad_chip_type != MAD_NONE) 310 printf(", %s", 311 sc->mad_chip_type == MAD_82C929 ? "82C929" : 312 sc->mad_chip_type == MAD_82C928 ? "82C928" : 313 "OTI-601D"); 314 printf("\n"); 315 316 sc->sc_ad1848.parent = sc; 317 318 if ((err = audio_hardware_attach(&wss_hw_if, &sc->sc_ad1848)) != 0) 319 printf("wss: could not attach to audio pseudo-device driver (%d)\n", err); 320 } 321 322 static int 323 wss_to_vol(cp, vol) 324 mixer_ctrl_t *cp; 325 struct ad1848_volume *vol; 326 { 327 if (cp->un.value.num_channels == 1) { 328 vol->left = vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 329 return(1); 330 } 331 else if (cp->un.value.num_channels == 2) { 332 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 333 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 334 return(1); 335 } 336 return(0); 337 } 338 339 static int 340 wss_from_vol(cp, vol) 341 mixer_ctrl_t *cp; 342 struct ad1848_volume *vol; 343 { 344 if (cp->un.value.num_channels == 1) { 345 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left; 346 return(1); 347 } 348 else if (cp->un.value.num_channels == 2) { 349 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left; 350 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right; 351 return(1); 352 } 353 return(0); 354 } 355 356 int 357 wssopen(dev, flags) 358 dev_t dev; 359 int flags; 360 { 361 struct wss_softc *sc; 362 int unit = AUDIOUNIT(dev); 363 364 if (unit >= wss_cd.cd_ndevs) 365 return ENODEV; 366 367 sc = wss_cd.cd_devs[unit]; 368 if (!sc) 369 return ENXIO; 370 371 return ad1848_open(&sc->sc_ad1848, dev, flags); 372 } 373 374 int 375 wss_getdev(addr, retp) 376 void *addr; 377 struct audio_device *retp; 378 { 379 *retp = wss_device; 380 return 0; 381 } 382 383 int 384 wss_setfd(addr, flag) 385 void *addr; 386 int flag; 387 { 388 /* Can't do full-duplex */ 389 return(ENOTTY); 390 } 391 392 393 int 394 wss_set_out_port(addr, port) 395 void *addr; 396 int port; 397 { 398 DPRINTF(("wss_set_out_port:\n")); 399 return(EINVAL); 400 } 401 402 int 403 wss_get_out_port(addr) 404 void *addr; 405 { 406 DPRINTF(("wss_get_out_port:\n")); 407 return(WSS_DAC_LVL); 408 } 409 410 int 411 wss_set_in_port(addr, port) 412 void *addr; 413 int port; 414 { 415 register struct ad1848_softc *ac = addr; 416 417 DPRINTF(("wss_set_in_port: %d\n", port)); 418 419 switch(port) { 420 case WSS_MIC_IN_LVL: 421 port = MIC_IN_PORT; 422 break; 423 case WSS_LINE_IN_LVL: 424 port = LINE_IN_PORT; 425 break; 426 case WSS_DAC_LVL: 427 port = DAC_IN_PORT; 428 break; 429 default: 430 return(EINVAL); 431 /*NOTREACHED*/ 432 } 433 434 return(ad1848_set_rec_port(ac, port)); 435 } 436 437 int 438 wss_get_in_port(addr) 439 void *addr; 440 { 441 register struct ad1848_softc *ac = addr; 442 int port = WSS_MIC_IN_LVL; 443 444 switch(ad1848_get_rec_port(ac)) { 445 case MIC_IN_PORT: 446 port = WSS_MIC_IN_LVL; 447 break; 448 case LINE_IN_PORT: 449 port = WSS_LINE_IN_LVL; 450 break; 451 case DAC_IN_PORT: 452 port = WSS_DAC_LVL; 453 break; 454 } 455 456 DPRINTF(("wss_get_in_port: %d\n", port)); 457 458 return(port); 459 } 460 461 int 462 wss_mixer_set_port(addr, cp) 463 void *addr; 464 mixer_ctrl_t *cp; 465 { 466 register struct ad1848_softc *ac = addr; 467 register struct wss_softc *sc = ac->parent; 468 struct ad1848_volume vol; 469 int error = EINVAL; 470 471 DPRINTF(("wss_mixer_set_port: dev=%d type=%d\n", cp->dev, cp->type)); 472 473 switch (cp->dev) { 474 case WSS_MIC_IN_LVL: /* Microphone */ 475 if (cp->type == AUDIO_MIXER_VALUE) { 476 if (wss_to_vol(cp, &vol)) 477 error = ad1848_set_aux2_gain(ac, &vol); 478 } 479 break; 480 481 case WSS_MIC_IN_MUTE: /* Microphone */ 482 if (cp->type == AUDIO_MIXER_ENUM) { 483 sc->mic_mute = cp->un.ord; 484 DPRINTF(("mic mute %d\n", cp->un.ord)); 485 error = 0; 486 } 487 break; 488 489 case WSS_LINE_IN_LVL: /* linein/CD */ 490 if (cp->type == AUDIO_MIXER_VALUE) { 491 if (wss_to_vol(cp, &vol)) 492 error = ad1848_set_aux1_gain(ac, &vol); 493 } 494 break; 495 496 case WSS_LINE_IN_MUTE: /* linein/CD */ 497 if (cp->type == AUDIO_MIXER_ENUM) { 498 sc->cd_mute = cp->un.ord; 499 DPRINTF(("CD mute %d\n", cp->un.ord)); 500 error = 0; 501 } 502 break; 503 504 case WSS_DAC_LVL: /* dac out */ 505 if (cp->type == AUDIO_MIXER_VALUE) { 506 if (wss_to_vol(cp, &vol)) 507 error = ad1848_set_out_gain(ac, &vol); 508 } 509 break; 510 511 case WSS_DAC_MUTE: /* dac out */ 512 if (cp->type == AUDIO_MIXER_ENUM) { 513 sc->dac_mute = cp->un.ord; 514 DPRINTF(("DAC mute %d\n", cp->un.ord)); 515 error = 0; 516 } 517 break; 518 519 case WSS_REC_LVL: /* record level */ 520 if (cp->type == AUDIO_MIXER_VALUE) { 521 if (wss_to_vol(cp, &vol)) 522 error = ad1848_set_rec_gain(ac, &vol); 523 } 524 break; 525 526 case WSS_RECORD_SOURCE: 527 if (cp->type == AUDIO_MIXER_ENUM) { 528 error = ad1848_set_rec_port(ac, cp->un.ord); 529 } 530 break; 531 532 case WSS_MON_LVL: 533 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) { 534 vol.left = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; 535 error = ad1848_set_mon_gain(ac, &vol); 536 } 537 break; 538 539 default: 540 return ENXIO; 541 /*NOTREACHED*/ 542 } 543 544 return 0; 545 } 546 547 int 548 wss_mixer_get_port(addr, cp) 549 void *addr; 550 mixer_ctrl_t *cp; 551 { 552 register struct ad1848_softc *ac = addr; 553 register struct wss_softc *sc = ac->parent; 554 struct ad1848_volume vol; 555 int error = EINVAL; 556 557 DPRINTF(("wss_mixer_get_port: port=%d\n", cp->dev)); 558 559 switch (cp->dev) { 560 case WSS_MIC_IN_LVL: /* Microphone */ 561 if (cp->type == AUDIO_MIXER_VALUE) { 562 error = ad1848_get_aux2_gain(ac, &vol); 563 if (!error) 564 wss_from_vol(cp, &vol); 565 } 566 break; 567 568 case WSS_MIC_IN_MUTE: 569 if (cp->type == AUDIO_MIXER_ENUM) { 570 cp->un.ord = sc->mic_mute; 571 error = 0; 572 } 573 break; 574 575 case WSS_LINE_IN_LVL: /* linein/CD */ 576 if (cp->type == AUDIO_MIXER_VALUE) { 577 error = ad1848_get_aux1_gain(ac, &vol); 578 if (!error) 579 wss_from_vol(cp, &vol); 580 } 581 break; 582 583 case WSS_LINE_IN_MUTE: 584 if (cp->type == AUDIO_MIXER_ENUM) { 585 cp->un.ord = sc->cd_mute; 586 error = 0; 587 } 588 break; 589 590 case WSS_DAC_LVL: /* dac out */ 591 if (cp->type == AUDIO_MIXER_VALUE) { 592 error = ad1848_get_out_gain(ac, &vol); 593 if (!error) 594 wss_from_vol(cp, &vol); 595 } 596 break; 597 598 case WSS_DAC_MUTE: 599 if (cp->type == AUDIO_MIXER_ENUM) { 600 cp->un.ord = sc->dac_mute; 601 error = 0; 602 } 603 break; 604 605 case WSS_REC_LVL: /* record level */ 606 if (cp->type == AUDIO_MIXER_VALUE) { 607 error = ad1848_get_rec_gain(ac, &vol); 608 if (!error) 609 wss_from_vol(cp, &vol); 610 } 611 break; 612 613 case WSS_RECORD_SOURCE: 614 if (cp->type == AUDIO_MIXER_ENUM) { 615 cp->un.ord = ad1848_get_rec_port(ac); 616 error = 0; 617 } 618 break; 619 620 case WSS_MON_LVL: /* monitor level */ 621 if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) { 622 error = ad1848_get_mon_gain(ac, &vol); 623 if (!error) 624 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol.left; 625 } 626 break; 627 628 default: 629 error = ENXIO; 630 break; 631 } 632 633 return(error); 634 } 635 636 int 637 wss_query_devinfo(addr, dip) 638 void *addr; 639 register mixer_devinfo_t *dip; 640 { 641 DPRINTF(("wss_query_devinfo: index=%d\n", dip->index)); 642 643 switch(dip->index) { 644 case WSS_MIC_IN_LVL: /* Microphone */ 645 dip->type = AUDIO_MIXER_VALUE; 646 dip->mixer_class = WSS_INPUT_CLASS; 647 dip->prev = AUDIO_MIXER_LAST; 648 dip->next = WSS_MIC_IN_MUTE; 649 strcpy(dip->label.name, AudioNmicrophone); 650 dip->un.v.num_channels = 2; 651 strcpy(dip->un.v.units.name, AudioNvolume); 652 break; 653 654 case WSS_LINE_IN_LVL: /* line/CD */ 655 dip->type = AUDIO_MIXER_VALUE; 656 dip->mixer_class = WSS_INPUT_CLASS; 657 dip->prev = AUDIO_MIXER_LAST; 658 dip->next = WSS_LINE_IN_MUTE; 659 strcpy(dip->label.name, AudioNcd); 660 dip->un.v.num_channels = 2; 661 strcpy(dip->un.v.units.name, AudioNvolume); 662 break; 663 664 case WSS_DAC_LVL: /* dacout */ 665 dip->type = AUDIO_MIXER_VALUE; 666 dip->mixer_class = WSS_INPUT_CLASS; 667 dip->prev = AUDIO_MIXER_LAST; 668 dip->next = WSS_DAC_MUTE; 669 strcpy(dip->label.name, AudioNdac); 670 dip->un.v.num_channels = 2; 671 strcpy(dip->un.v.units.name, AudioNvolume); 672 break; 673 674 case WSS_REC_LVL: /* record level */ 675 dip->type = AUDIO_MIXER_VALUE; 676 dip->mixer_class = WSS_RECORD_CLASS; 677 dip->prev = AUDIO_MIXER_LAST; 678 dip->next = WSS_RECORD_SOURCE; 679 strcpy(dip->label.name, AudioNrecord); 680 dip->un.v.num_channels = 2; 681 strcpy(dip->un.v.units.name, AudioNvolume); 682 break; 683 684 case WSS_MON_LVL: /* monitor level */ 685 dip->type = AUDIO_MIXER_VALUE; 686 dip->mixer_class = WSS_MONITOR_CLASS; 687 dip->next = dip->prev = AUDIO_MIXER_LAST; 688 strcpy(dip->label.name, AudioNmonitor); 689 dip->un.v.num_channels = 1; 690 strcpy(dip->un.v.units.name, AudioNvolume); 691 break; 692 693 case WSS_INPUT_CLASS: /* input class descriptor */ 694 dip->type = AUDIO_MIXER_CLASS; 695 dip->mixer_class = WSS_INPUT_CLASS; 696 dip->next = dip->prev = AUDIO_MIXER_LAST; 697 strcpy(dip->label.name, AudioCInputs); 698 break; 699 700 case WSS_MONITOR_CLASS: /* monitor class descriptor */ 701 dip->type = AUDIO_MIXER_CLASS; 702 dip->mixer_class = WSS_MONITOR_CLASS; 703 dip->next = dip->prev = AUDIO_MIXER_LAST; 704 strcpy(dip->label.name, AudioCMonitor); 705 break; 706 707 case WSS_RECORD_CLASS: /* record source class */ 708 dip->type = AUDIO_MIXER_CLASS; 709 dip->mixer_class = WSS_RECORD_CLASS; 710 dip->next = dip->prev = AUDIO_MIXER_LAST; 711 strcpy(dip->label.name, AudioCRecord); 712 break; 713 714 case WSS_MIC_IN_MUTE: 715 dip->mixer_class = WSS_INPUT_CLASS; 716 dip->type = AUDIO_MIXER_ENUM; 717 dip->prev = WSS_MIC_IN_LVL; 718 dip->next = AUDIO_MIXER_LAST; 719 goto mute; 720 721 case WSS_LINE_IN_MUTE: 722 dip->mixer_class = WSS_INPUT_CLASS; 723 dip->type = AUDIO_MIXER_ENUM; 724 dip->prev = WSS_LINE_IN_LVL; 725 dip->next = AUDIO_MIXER_LAST; 726 goto mute; 727 728 case WSS_DAC_MUTE: 729 dip->mixer_class = WSS_INPUT_CLASS; 730 dip->type = AUDIO_MIXER_ENUM; 731 dip->prev = WSS_DAC_LVL; 732 dip->next = AUDIO_MIXER_LAST; 733 mute: 734 strcpy(dip->label.name, AudioNmute); 735 dip->un.e.num_mem = 2; 736 strcpy(dip->un.e.member[0].label.name, AudioNoff); 737 dip->un.e.member[0].ord = 0; 738 strcpy(dip->un.e.member[1].label.name, AudioNon); 739 dip->un.e.member[1].ord = 1; 740 break; 741 742 case WSS_RECORD_SOURCE: 743 dip->mixer_class = WSS_RECORD_CLASS; 744 dip->type = AUDIO_MIXER_ENUM; 745 dip->prev = WSS_REC_LVL; 746 dip->next = AUDIO_MIXER_LAST; 747 strcpy(dip->label.name, AudioNsource); 748 dip->un.e.num_mem = 3; 749 strcpy(dip->un.e.member[0].label.name, AudioNmicrophone); 750 dip->un.e.member[0].ord = WSS_MIC_IN_LVL; 751 strcpy(dip->un.e.member[1].label.name, AudioNcd); 752 dip->un.e.member[1].ord = WSS_LINE_IN_LVL; 753 strcpy(dip->un.e.member[2].label.name, AudioNdac); 754 dip->un.e.member[2].ord = WSS_DAC_LVL; 755 break; 756 757 default: 758 return ENXIO; 759 /*NOTREACHED*/ 760 } 761 DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); 762 763 return 0; 764 } 765 766 /* 767 * Initialization code for OPTi MAD16 compatible audio chips. Including 768 * 769 * OPTi 82C928 MAD16 (replaced by C929) 770 * OAK OTI-601D Mozart 771 * OPTi 82C929 MAD16 Pro 772 * 773 */ 774 static unsigned int mad_read __P((struct wss_softc *, int, int)); 775 static void mad_write __P((struct wss_softc *, int, int, int)); 776 static int detect_mad16 __P((struct wss_softc *, int)); 777 778 static unsigned int 779 mad_read(sc, chip_type, port) 780 struct wss_softc *sc; 781 int chip_type; 782 int port; 783 { 784 unsigned int tmp; 785 int s = splaudio(); /* don't want an interrupt between outb&inb */ 786 787 switch (chip_type) { /* Output password */ 788 case MAD_82C928: 789 case MAD_OTI601D: 790 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928); 791 break; 792 case MAD_82C929: 793 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929); 794 break; 795 } 796 tmp = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, port); 797 splx(s); 798 return tmp; 799 } 800 801 static void 802 mad_write(sc, chip_type, port, value) 803 struct wss_softc *sc; 804 int chip_type; 805 int port; 806 int value; 807 { 808 int s = splaudio(); /* don't want an interrupt between outb&outb */ 809 810 switch (chip_type) { /* Output password */ 811 case MAD_82C928: 812 case MAD_OTI601D: 813 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_928); 814 break; 815 case MAD_82C929: 816 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, MC_PASSWD_REG, M_PASSWD_929); 817 break; 818 } 819 bus_space_write_1(sc->sc_iot, sc->sc_mad_ioh, port, value & 0xff); 820 splx(s); 821 } 822 823 static int 824 detect_mad16(sc, chip_type) 825 struct wss_softc *sc; 826 int chip_type; 827 { 828 unsigned char tmp, tmp2; 829 830 /* 831 * Check that reading a register doesn't return bus float (0xff) 832 * when the card is accessed using password. This may fail in case 833 * the card is in low power mode. Normally at least the power saving mode 834 * bit should be 0. 835 */ 836 if ((tmp = mad_read(sc, chip_type, MC1_PORT)) == 0xff) { 837 DPRINTF(("MC1_PORT returned 0xff\n")); 838 return 0; 839 } 840 841 /* 842 * Now check that the gate is closed on first I/O after writing 843 * the password. (This is how a MAD16 compatible card works). 844 */ 845 if ((tmp2 = bus_space_read_1(sc->sc_iot, sc->sc_mad_ioh, MC1_PORT)) == tmp) { /* It didn't close */ 846 DPRINTF(("MC1_PORT didn't close after read (0x%02x)\n", tmp2)); 847 return 0; 848 } 849 850 mad_write(sc, chip_type, MC1_PORT, tmp ^ 0x80); /* Toggle a bit */ 851 852 /* Compare the bit */ 853 if ((tmp2 = mad_read(sc, chip_type, MC1_PORT)) != (tmp ^ 0x80)) { 854 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */ 855 DPRINTF(("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2)); 856 return 0; 857 } 858 859 mad_write(sc, chip_type, MC1_PORT, tmp); /* Restore */ 860 return 1; 861 } 862 863 static int 864 madprobe(sc, iobase) 865 struct wss_softc *sc; 866 int iobase; 867 { 868 static int valid_ports[M_WSS_NPORTS] = 869 { M_WSS_PORT0, M_WSS_PORT1, M_WSS_PORT2, M_WSS_PORT3 }; 870 int i; 871 int chip_type; 872 873 if (bus_space_map(sc->sc_iot, MAD_BASE, MAD_NPORT, 0, &sc->sc_mad_ioh)) 874 return MAD_NONE; 875 876 DPRINTF(("mad: Detect using password = 0xE2\n")); 877 if (!detect_mad16(sc, MAD_82C928)) { 878 /* No luck. Try different model */ 879 DPRINTF(("mad: Detect using password = 0xE3\n")); 880 if (!detect_mad16(sc, MAD_82C929)) 881 goto bad; 882 chip_type = MAD_82C929; 883 DPRINTF(("mad: 82C929 detected\n")); 884 } else { 885 if ((mad_read(sc, MAD_82C928, MC3_PORT) & 0x03) == 0x03) { 886 DPRINTF(("mad: Mozart detected\n")); 887 chip_type = MAD_OTI601D; 888 } else { 889 DPRINTF(("mad: 82C928 detected?\n")); 890 chip_type = MAD_82C928; 891 } 892 } 893 894 #ifdef AUDIO_DEBUG 895 if (wssdebug) 896 for (i = MC1_PORT; i <= MC7_PORT; i++) 897 printf("mad: port %03x = %02x\n", i, mad_read(sc, chip_type, i)); 898 #endif 899 900 /* Set the WSS address. */ 901 for (i = 0; i < 4; i++) 902 if (valid_ports[i] == iobase) 903 break; 904 if (i > 3) { /* Not a valid port */ 905 printf("mad: Bad WSS base address 0x%x\n", iobase); 906 goto bad; 907 } 908 /* enable WSS emulation at the I/O port, keep joystck */ 909 mad_write(sc, chip_type, MC1_PORT, M_WSS_PORT_SELECT(i)); 910 911 mad_write(sc, chip_type, MC2_PORT, 0x03); /* ? */ 912 mad_write(sc, chip_type, MC3_PORT, 0xf0); /* Disable SB */ 913 914 return chip_type; 915 bad: 916 bus_space_unmap(sc->sc_iot, sc->sc_mad_ioh, MAD_NPORT); 917 return MAD_NONE; 918 } 919 920 static void 921 madprobedone(sc) 922 struct wss_softc *sc; 923 { 924 int chip_type = sc->mad_chip_type; 925 unsigned char cs4231_mode; 926 927 cs4231_mode = 928 strncmp(sc->sc_ad1848.chip_name, "CS4248", 6) == 0 || 929 strncmp(sc->sc_ad1848.chip_name, "CS4231", 6) == 0 ? 0x02 : 0; 930 931 if (chip_type == MAD_82C929) { 932 mad_write(sc, chip_type, MC4_PORT, 0xa2); 933 mad_write(sc, chip_type, MC5_PORT, 0xA5 | cs4231_mode); 934 mad_write(sc, chip_type, MC6_PORT, 0x03); /* Disable MPU401 */ 935 } else { 936 mad_write(sc, chip_type, MC4_PORT, 0x02); 937 mad_write(sc, chip_type, MC5_PORT, 0x30 | cs4231_mode); 938 } 939 940 #ifdef AUDIO_DEBUG 941 if (wssdebug) { 942 int i; 943 for (i = MC1_PORT; i <= MC7_PORT; i++) 944 DPRINTF(("port %03x after init = %02x\n", i, mad_read(sc, chip_type, i))); 945 } 946 #endif 947 } 948