Annotation of sys/dev/isa/pss.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pss.c,v 1.22 2003/04/27 11:22:53 ho Exp $ */
! 2: /* $NetBSD: pss.c,v 1.38 1998/01/12 09:43:44 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1994 John Brezak
! 6: * Copyright (c) 1991-1993 Regents of the University of California.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by the Computer Systems
! 20: * Engineering Group at Lawrence Berkeley Laboratory.
! 21: * 4. Neither the name of the University nor of the Laboratory may be used
! 22: * to endorse or promote products derived from this software without
! 23: * specific prior written permission.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 35: * SUCH DAMAGE.
! 36: *
! 37: */
! 38:
! 39: /*
! 40: * Copyright (c) 1993 Analog Devices Inc. All rights reserved
! 41: *
! 42: * Portions provided by Marc.Hoffman@analog.com and
! 43: * Greg.Yukna@analog.com .
! 44: *
! 45: */
! 46:
! 47: /*
! 48: * Todo:
! 49: * - Provide PSS driver to access DSP
! 50: * - Provide MIDI driver to access MPU
! 51: * - Finish support for CD drive (Sony and SCSI)
! 52: */
! 53:
! 54: #include <sys/param.h>
! 55: #include <sys/systm.h>
! 56: #include <sys/errno.h>
! 57: #include <sys/ioctl.h>
! 58: #include <sys/syslog.h>
! 59: #include <sys/device.h>
! 60: #include <sys/proc.h>
! 61: #include <sys/buf.h>
! 62:
! 63: #include <machine/cpu.h>
! 64: #include <machine/intr.h>
! 65: #include <machine/bus.h>
! 66:
! 67: #include <sys/audioio.h>
! 68: #include <dev/audio_if.h>
! 69:
! 70: #include <dev/isa/isavar.h>
! 71: #include <dev/isa/isadmavar.h>
! 72:
! 73: #include <dev/isa/ad1848var.h>
! 74: #include <dev/isa/wssreg.h>
! 75: #include <dev/isa/pssreg.h>
! 76:
! 77: /* XXX Default WSS base */
! 78: #define WSS_BASE_ADDRESS 0x0530
! 79:
! 80: /*
! 81: * Mixer devices
! 82: */
! 83: #define PSS_MIC_IN_LVL 0
! 84: #define PSS_LINE_IN_LVL 1
! 85: #define PSS_DAC_LVL 2
! 86: #define PSS_REC_LVL 3
! 87: #define PSS_MON_LVL 4
! 88: #define PSS_MASTER_VOL 5
! 89: #define PSS_MASTER_TREBLE 6
! 90: #define PSS_MASTER_BASS 7
! 91: #define PSS_MIC_IN_MUTE 8
! 92: #define PSS_LINE_IN_MUTE 9
! 93: #define PSS_DAC_MUTE 10
! 94:
! 95: #define PSS_OUTPUT_MODE 11
! 96: #define PSS_SPKR_MONO 0
! 97: #define PSS_SPKR_STEREO 1
! 98: #define PSS_SPKR_PSEUDO 2
! 99: #define PSS_SPKR_SPATIAL 3
! 100:
! 101: #define PSS_RECORD_SOURCE 12
! 102:
! 103: /* Classes */
! 104: #define PSS_INPUT_CLASS 13
! 105: #define PSS_RECORD_CLASS 14
! 106: #define PSS_MONITOR_CLASS 15
! 107: #define PSS_OUTPUT_CLASS 16
! 108:
! 109:
! 110: struct pss_softc {
! 111: struct device sc_dev; /* base device */
! 112: void *sc_ih; /* interrupt vectoring */
! 113:
! 114: int sc_iobase; /* I/O port base address */
! 115: int sc_drq; /* dma channel */
! 116:
! 117: struct ad1848_softc *ad1848_sc;
! 118:
! 119: int out_port;
! 120:
! 121: struct ad1848_volume master_volume;
! 122: int master_mode;
! 123:
! 124: int monitor_treble;
! 125: int monitor_bass;
! 126:
! 127: int mic_mute, cd_mute, dac_mute;
! 128: };
! 129:
! 130: #ifdef notyet
! 131: struct mpu_softc {
! 132: struct device sc_dev; /* base device */
! 133: void *sc_ih; /* interrupt vectoring */
! 134:
! 135: int sc_iobase; /* MIDI I/O port base address */
! 136: int sc_irq; /* MIDI interrupt */
! 137: };
! 138:
! 139: struct pcd_softc {
! 140: struct device sc_dev; /* base device */
! 141: void *sc_ih; /* interrupt vectoring */
! 142:
! 143: int sc_iobase; /* CD I/O port base address */
! 144: int sc_irq; /* CD interrupt */
! 145: };
! 146: #endif
! 147:
! 148: #ifdef AUDIO_DEBUG
! 149: #define DPRINTF(x) if (pssdebug) printf x
! 150: int pssdebug = 0;
! 151: #else
! 152: #define DPRINTF(x)
! 153: #endif
! 154:
! 155: int pssprobe(struct device *, void *, void *);
! 156: void pssattach(struct device *, struct device *, void *);
! 157:
! 158: int spprobe(struct device *, void *, void *);
! 159: void spattach(struct device *, struct device *, void *);
! 160:
! 161: #ifdef notyet
! 162: int mpuprobe(struct device *, void *, void *);
! 163: void mpuattach(struct device *, struct device *, void *);
! 164:
! 165: int pcdprobe(struct device *, void *, void *);
! 166: void pcdattach(struct device *, struct device *, void *);
! 167: #endif
! 168:
! 169: int pssintr(void *);
! 170: #ifdef notyet
! 171: int mpuintr(void *);
! 172: #endif
! 173:
! 174: int pss_speaker_ctl(void *, int);
! 175:
! 176: int pss_getdev(void *, struct audio_device *);
! 177:
! 178: int pss_mixer_set_port(void *, mixer_ctrl_t *);
! 179: int pss_mixer_get_port(void *, mixer_ctrl_t *);
! 180: int pss_query_devinfo(void *, mixer_devinfo_t *);
! 181:
! 182: #ifdef PSS_DSP
! 183: void pss_dspwrite(struct pss_softc *, int);
! 184: #endif
! 185: void pss_setaddr(int, int);
! 186: int pss_setint(int, int);
! 187: int pss_setdma(int, int);
! 188: int pss_testirq(struct pss_softc *, int);
! 189: int pss_testdma(struct pss_softc *, int);
! 190: #ifdef notyet
! 191: int pss_reset_dsp(struct pss_softc *);
! 192: int pss_download_dsp(struct pss_softc *, u_char *, int);
! 193: #endif
! 194: #ifdef AUDIO_DEBUG
! 195: void pss_dump_regs(struct pss_softc *);
! 196: #endif
! 197: int pss_set_master_gain(struct pss_softc *, struct ad1848_volume *);
! 198: int pss_set_master_mode(struct pss_softc *, int);
! 199: int pss_set_treble(struct pss_softc *, u_int);
! 200: int pss_set_bass(struct pss_softc *, u_int);
! 201: int pss_get_master_gain(struct pss_softc *, struct ad1848_volume *);
! 202: int pss_get_master_mode(struct pss_softc *, u_int *);
! 203: int pss_get_treble(struct pss_softc *, u_char *);
! 204: int pss_get_bass(struct pss_softc *, u_char *);
! 205:
! 206: #ifdef AUDIO_DEBUG
! 207: void wss_dump_regs(struct ad1848_softc *);
! 208: #endif
! 209:
! 210: /*
! 211: * Define our interface to the higher level audio driver.
! 212: */
! 213:
! 214: struct audio_hw_if pss_audio_if = {
! 215: ad1848_open,
! 216: ad1848_close,
! 217: NULL,
! 218: ad1848_query_encoding,
! 219: ad1848_set_params,
! 220: ad1848_round_blocksize,
! 221: ad1848_commit_settings,
! 222: ad1848_dma_init_output,
! 223: ad1848_dma_init_input,
! 224: ad1848_dma_output,
! 225: ad1848_dma_input,
! 226: ad1848_halt_out_dma,
! 227: ad1848_halt_in_dma,
! 228: pss_speaker_ctl,
! 229: pss_getdev,
! 230: NULL,
! 231: pss_mixer_set_port,
! 232: pss_mixer_get_port,
! 233: pss_query_devinfo,
! 234: ad1848_malloc,
! 235: ad1848_free,
! 236: ad1848_round,
! 237: ad1848_mappage,
! 238: ad1848_get_props,
! 239: NULL,
! 240: NULL
! 241: };
! 242:
! 243:
! 244: /* Interrupt translation for WSS config */
! 245: static u_char wss_interrupt_bits[16] = {
! 246: 0xff, 0xff, 0xff, 0xff,
! 247: 0xff, 0xff, 0xff, 0x08,
! 248: 0xff, 0x10, 0x18, 0x20,
! 249: 0xff, 0xff, 0xff, 0xff
! 250: };
! 251: /* ditto for WSS DMA channel */
! 252: static u_char wss_dma_bits[4] = {1, 2, 0, 3};
! 253:
! 254: struct cfattach pss_ca = {
! 255: sizeof(struct pss_softc), pssprobe, pssattach
! 256: };
! 257:
! 258: struct cfdriver pss_cd = {
! 259: NULL, "pss", DV_DULL, 1
! 260: };
! 261:
! 262: struct cfattach sp_ca = {
! 263: sizeof(struct ad1848_softc), spprobe, spattach
! 264: };
! 265:
! 266: struct cfdriver sp_cd = {
! 267: NULL, "sp", DV_DULL
! 268: };
! 269:
! 270: #ifdef notyet
! 271: struct cfattach mpu_ca = {
! 272: sizeof(struct mpu_softc), mpuprobe, mpuattach
! 273: };
! 274:
! 275: struct cfdriver mpu_cd = {
! 276: NULL, "mpu", DV_DULL
! 277: };
! 278:
! 279: struct cfattach pcd_ca = {
! 280: sizeof(struct pcd_softc), pcdprobe, pcdattach
! 281: };
! 282:
! 283: struct cfdriver pcd_cd = {
! 284: NULL, "pcd", DV_DULL
! 285: };
! 286: #endif
! 287:
! 288: struct audio_device pss_device = {
! 289: "pss,ad1848",
! 290: "",
! 291: "PSS"
! 292: };
! 293:
! 294: #ifdef PSS_DSP
! 295: void
! 296: pss_dspwrite(sc, data)
! 297: struct pss_softc *sc;
! 298: int data;
! 299: {
! 300: int i;
! 301: int pss_base = sc->sc_iobase;
! 302:
! 303: /*
! 304: * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
! 305: * called while interrupts are disabled. This means that the timer is
! 306: * disabled also. However the timeout situation is a abnormal condition.
! 307: * Normally the DSP should be ready to accept commands after just couple of
! 308: * loops.
! 309: */
! 310: for (i = 0; i < 5000000; i++) {
! 311: if (inw(pss_base+PSS_STATUS) & PSS_WRITE_EMPTY) {
! 312: outw(pss_base+PSS_DATA, data);
! 313: return;
! 314: }
! 315: }
! 316: printf ("pss: DSP Command (%04x) Timeout.\n", data);
! 317: }
! 318: #endif /* PSS_DSP */
! 319:
! 320: void
! 321: pss_setaddr(addr, configAddr)
! 322: int addr;
! 323: int configAddr;
! 324: {
! 325: int val;
! 326:
! 327: val = inw(configAddr);
! 328: val &= ADDR_MASK;
! 329: val |= (addr << 4);
! 330: outw(configAddr,val);
! 331: }
! 332:
! 333: /* pss_setint
! 334: * This function sets the correct bits in the
! 335: * configuration register to
! 336: * enable the chosen interrupt.
! 337: */
! 338: int
! 339: pss_setint(intNum, configAddress)
! 340: int intNum;
! 341: int configAddress;
! 342: {
! 343: int val;
! 344:
! 345: switch(intNum) {
! 346: case 3:
! 347: val = inw(configAddress);
! 348: val &= INT_MASK;
! 349: val |= INT_3_BITS;
! 350: break;
! 351: case 5:
! 352: val = inw(configAddress);
! 353: val &= INT_MASK;
! 354: val |= INT_5_BITS;
! 355: break;
! 356: case 7:
! 357: val = inw(configAddress);
! 358: val &= INT_MASK;
! 359: val |= INT_7_BITS;
! 360: break;
! 361: case 9:
! 362: val = inw(configAddress);
! 363: val &= INT_MASK;
! 364: val |= INT_9_BITS;
! 365: break;
! 366: case 10:
! 367: val = inw(configAddress);
! 368: val &= INT_MASK;
! 369: val |= INT_10_BITS;
! 370: break;
! 371: case 11:
! 372: val = inw(configAddress);
! 373: val &= INT_MASK;
! 374: val |= INT_11_BITS;
! 375: break;
! 376: case 12:
! 377: val = inw(configAddress);
! 378: val &= INT_MASK;
! 379: val |= INT_12_BITS;
! 380: break;
! 381: default:
! 382: DPRINTF(("pss_setint: invalid irq (%d)\n", intNum));
! 383: return 1;
! 384: }
! 385: outw(configAddress,val);
! 386: return 0;
! 387: }
! 388:
! 389: int
! 390: pss_setdma(dmaNum, configAddress)
! 391: int dmaNum;
! 392: int configAddress;
! 393: {
! 394: int val;
! 395:
! 396: switch(dmaNum) {
! 397: case 0:
! 398: val = inw(configAddress);
! 399: val &= DMA_MASK;
! 400: val |= DMA_0_BITS;
! 401: break;
! 402: case 1:
! 403: val = inw(configAddress);
! 404: val &= DMA_MASK;
! 405: val |= DMA_1_BITS;
! 406: break;
! 407: case 3:
! 408: val = inw(configAddress);
! 409: val &= DMA_MASK;
! 410: val |= DMA_3_BITS;
! 411: break;
! 412: case 5:
! 413: val = inw(configAddress);
! 414: val &= DMA_MASK;
! 415: val |= DMA_5_BITS;
! 416: break;
! 417: case 6:
! 418: val = inw(configAddress);
! 419: val &= DMA_MASK;
! 420: val |= DMA_6_BITS;
! 421: break;
! 422: case 7:
! 423: val = inw(configAddress);
! 424: val &= DMA_MASK;
! 425: val |= DMA_7_BITS;
! 426: break;
! 427: default:
! 428: DPRINTF(("pss_setdma: invalid drq (%d)\n", dmaNum));
! 429: return 1;
! 430: }
! 431: outw(configAddress, val);
! 432: return 0;
! 433: }
! 434:
! 435: /*
! 436: * This function tests an interrupt number to see if
! 437: * it is available. It takes the interrupt button
! 438: * as its argument and returns TRUE if the interrupt
! 439: * is ok.
! 440: */
! 441: int
! 442: pss_testirq(struct pss_softc *sc, int intNum)
! 443: {
! 444: int config = sc->sc_iobase + PSS_CONFIG;
! 445: int val;
! 446: int ret;
! 447: int i;
! 448:
! 449: /* Set the interrupt bits */
! 450: switch(intNum) {
! 451: case 3:
! 452: val = inw(config);
! 453: val &= INT_MASK; /* Special: 0 */
! 454: break;
! 455: case 5:
! 456: val = inw(config);
! 457: val &= INT_MASK;
! 458: val |= INT_TEST_BIT | INT_5_BITS;
! 459: break;
! 460: case 7:
! 461: val = inw(config);
! 462: val &= INT_MASK;
! 463: val |= INT_TEST_BIT | INT_7_BITS;
! 464: break;
! 465: case 9:
! 466: val = inw(config);
! 467: val &= INT_MASK;
! 468: val |= INT_TEST_BIT | INT_9_BITS;
! 469: break;
! 470: case 10:
! 471: val = inw(config);
! 472: val &= INT_MASK;
! 473: val |= INT_TEST_BIT | INT_10_BITS;
! 474: break;
! 475: case 11:
! 476: val = inw(config);
! 477: val &= INT_MASK;
! 478: val |= INT_TEST_BIT | INT_11_BITS;
! 479: break;
! 480: case 12:
! 481: val = inw(config);
! 482: val &= INT_MASK;
! 483: val |= INT_TEST_BIT | INT_12_BITS;
! 484: break;
! 485: default:
! 486: DPRINTF(("pss_testirq: invalid irq (%d)\n", intNum));
! 487: return 0;
! 488: }
! 489: outw(config, val);
! 490:
! 491: /* Check if the interrupt is in use */
! 492: /* Do it a few times in case there is a delay */
! 493: ret = 0;
! 494: for (i = 0; i < 5; i++) {
! 495: val = inw(config);
! 496: if (val & INT_TEST_PASS) {
! 497: ret = 1;
! 498: break;
! 499: }
! 500: }
! 501:
! 502: /* Clear the Test bit and the interrupt bits */
! 503: val = inw(config);
! 504: val &= INT_TEST_BIT_MASK & INT_MASK;
! 505: outw(config, val);
! 506: return(ret);
! 507: }
! 508:
! 509: /*
! 510: * This function tests a dma channel to see if
! 511: * it is available. It takes the DMA channel button
! 512: * as its argument and returns TRUE if the channel
! 513: * is ok.
! 514: */
! 515: int
! 516: pss_testdma(sc, dmaNum)
! 517: struct pss_softc *sc;
! 518: int dmaNum;
! 519: {
! 520: int config = sc->sc_iobase + PSS_CONFIG;
! 521: int val;
! 522: int i, ret;
! 523:
! 524: switch (dmaNum) {
! 525: case 0:
! 526: val = inw(config);
! 527: val &= DMA_MASK;
! 528: val |= DMA_TEST_BIT | DMA_0_BITS;
! 529: break;
! 530: case 1:
! 531: val = inw(config);
! 532: val &= DMA_MASK;
! 533: val |= DMA_TEST_BIT | DMA_1_BITS;
! 534: break;
! 535: case 3:
! 536: val = inw(config);
! 537: val &= DMA_MASK;
! 538: val |= DMA_TEST_BIT | DMA_3_BITS;
! 539: break;
! 540: case 5:
! 541: val = inw(config);
! 542: val &= DMA_MASK;
! 543: val |= DMA_TEST_BIT | DMA_5_BITS;
! 544: break;
! 545: case 6:
! 546: val = inw(config);
! 547: val &= DMA_MASK;
! 548: val |= DMA_TEST_BIT | DMA_6_BITS;
! 549: break;
! 550: case 7:
! 551: val = inw(config);
! 552: val &= DMA_MASK;
! 553: val |= DMA_TEST_BIT | DMA_7_BITS;
! 554: break;
! 555: default:
! 556: DPRINTF(("pss_testdma: invalid drq (%d)\n", dmaNum));
! 557: return 0;
! 558: }
! 559: outw(config, val);
! 560:
! 561: /* Check if the DMA channel is in use */
! 562: /* Do it a few times in case there is a delay */
! 563: ret = 0;
! 564: for (i = 0; i < 3; i++) {
! 565: val = inw(config);
! 566: if (val & DMA_TEST_PASS) {
! 567: ret = 1;
! 568: break;
! 569: }
! 570: }
! 571:
! 572: /* Clear the Test bit and the DMA bits */
! 573: val = inw(config);
! 574: val &= DMA_TEST_BIT_MASK & DMA_MASK;
! 575: outw(config, val);
! 576: return(ret);
! 577: }
! 578:
! 579: #ifdef notyet
! 580: int
! 581: pss_reset_dsp(sc)
! 582: struct pss_softc *sc;
! 583: {
! 584: u_long i;
! 585: int pss_base = sc->sc_iobase;
! 586:
! 587: outw(pss_base+PSS_CONTROL, PSS_RESET);
! 588:
! 589: for (i = 0; i < 32768; i++)
! 590: inw(pss_base+PSS_CONTROL);
! 591:
! 592: outw(pss_base+PSS_CONTROL, 0);
! 593:
! 594: return 1;
! 595: }
! 596:
! 597: /*
! 598: * This function loads an image into the PSS
! 599: * card. The function loads the file by
! 600: * resetting the dsp and feeding it the boot bytes.
! 601: * First you feed the ASIC the first byte of
! 602: * the boot sequence. The ASIC waits until it
! 603: * detects a BMS and RD and asserts BR
! 604: * and outputs the byte. The host must poll for
! 605: * the BG signal. It then feeds the ASIC another
! 606: * byte which removes BR.
! 607: */
! 608: int
! 609: pss_download_dsp(sc, block, size)
! 610: struct pss_softc *sc;
! 611: u_char *block;
! 612: int size;
! 613: {
! 614: int i, val, count;
! 615: int pss_base = sc->sc_iobase;
! 616:
! 617: DPRINTF(("pss: downloading boot code..."));
! 618:
! 619: /* Warn DSP software that a boot is coming */
! 620: outw(pss_base+PSS_DATA, 0x00fe);
! 621:
! 622: for (i = 0; i < 32768; i++)
! 623: if (inw(pss_base+PSS_DATA) == 0x5500)
! 624: break;
! 625: outw(pss_base+PSS_DATA, *block++);
! 626:
! 627: pss_reset_dsp(sc);
! 628:
! 629: DPRINTF(("start "));
! 630:
! 631: count = 1;
! 632: while(1) {
! 633: int j;
! 634: for (j=0; j<327670; j++) {
! 635: /* Wait for BG to appear */
! 636: if (inw(pss_base+PSS_STATUS) & PSS_FLAG3)
! 637: break;
! 638: }
! 639:
! 640: if (j==327670) {
! 641: /* It's ok we timed out when the file was empty */
! 642: if (count >= size)
! 643: break;
! 644: else {
! 645: printf("\npss: DownLoad timeout problems, byte %d=%d\n",
! 646: count, size);
! 647: return 0;
! 648: }
! 649: }
! 650: /* Send the next byte */
! 651: outw(pss_base+PSS_DATA, *block++);
! 652: count++;
! 653: }
! 654:
! 655: outw(pss_base+PSS_DATA, 0);
! 656: for (i = 0; i < 32768; i++)
! 657: (void) inw(pss_base+PSS_STATUS);
! 658:
! 659: DPRINTF(("downloaded\n"));
! 660:
! 661: for (i = 0; i < 32768; i++) {
! 662: val = inw(pss_base+PSS_STATUS);
! 663: if (val & PSS_READ_FULL)
! 664: break;
! 665: }
! 666:
! 667: /* now read the version */
! 668: for (i = 0; i < 32000; i++) {
! 669: val = inw(pss_base+PSS_STATUS);
! 670: if (val & PSS_READ_FULL)
! 671: break;
! 672: }
! 673: if (i == 32000)
! 674: return 0;
! 675:
! 676: (void) inw(pss_base+PSS_DATA);
! 677:
! 678: return 1;
! 679: }
! 680: #endif /* notyet */
! 681:
! 682: #ifdef AUDIO_DEBUG
! 683: void
! 684: wss_dump_regs(sc)
! 685: struct ad1848_softc *sc;
! 686: {
! 687:
! 688: printf("WSS reg: status=%02x\n",
! 689: (u_char)inb(sc->sc_iobase-WSS_CODEC+WSS_STATUS));
! 690: }
! 691:
! 692: void
! 693: pss_dump_regs(sc)
! 694: struct pss_softc *sc;
! 695: {
! 696:
! 697: printf("PSS regs: status=%04x vers=%04x ",
! 698: (u_short)inw(sc->sc_iobase+PSS_STATUS),
! 699: (u_short)inw(sc->sc_iobase+PSS_ID_VERS));
! 700:
! 701: printf("config=%04x wss_config=%04x\n",
! 702: (u_short)inw(sc->sc_iobase+PSS_CONFIG),
! 703: (u_short)inw(sc->sc_iobase+PSS_WSS_CONFIG));
! 704: }
! 705: #endif
! 706:
! 707: /*
! 708: * Probe for the PSS hardware.
! 709: */
! 710: int
! 711: pssprobe(parent, self, aux)
! 712: struct device *parent;
! 713: void *self;
! 714: void *aux;
! 715: {
! 716: struct pss_softc *sc = self;
! 717: struct isa_attach_args *ia = aux;
! 718: int iobase = ia->ia_iobase;
! 719:
! 720: if (!PSS_BASE_VALID(iobase)) {
! 721: DPRINTF(("pss: configured iobase %x invalid\n", iobase));
! 722: return 0;
! 723: }
! 724:
! 725: /* Need to probe for iobase when IOBASEUNK {0x220 0x240} */
! 726: if (iobase == IOBASEUNK) {
! 727:
! 728: iobase = 0x220;
! 729: if ((inw(iobase+PSS_ID_VERS) & 0xff00) == 0x4500)
! 730: goto pss_found;
! 731:
! 732: iobase = 0x240;
! 733: if ((inw(iobase+PSS_ID_VERS) & 0xff00) == 0x4500)
! 734: goto pss_found;
! 735:
! 736: DPRINTF(("pss: no PSS found (at 0x220 or 0x240)\n"));
! 737: return 0;
! 738: }
! 739: else if ((inw(iobase+PSS_ID_VERS) & 0xff00) != 0x4500) {
! 740: DPRINTF(("pss: not a PSS - %x\n", inw(iobase+PSS_ID_VERS)));
! 741: return 0;
! 742: }
! 743:
! 744: pss_found:
! 745: sc->sc_iobase = iobase;
! 746:
! 747: /* Clear WSS config */
! 748: pss_setaddr(WSS_BASE_ADDRESS, sc->sc_iobase+PSS_WSS_CONFIG); /* XXX! */
! 749: outb(WSS_BASE_ADDRESS+WSS_CONFIG, 0);
! 750:
! 751: /* Clear config registers (POR reset state) */
! 752: outw(sc->sc_iobase+PSS_CONFIG, 0);
! 753: outw(sc->sc_iobase+PSS_WSS_CONFIG, 0);
! 754: outw(sc->sc_iobase+SB_CONFIG, 0);
! 755: outw(sc->sc_iobase+MIDI_CONFIG, 0);
! 756: outw(sc->sc_iobase+CD_CONFIG, 0);
! 757:
! 758: if (ia->ia_irq == IRQUNK) {
! 759: int i;
! 760: for (i = 0; i < 16; i++) {
! 761: if (pss_testirq(sc, i) != 0)
! 762: break;
! 763: }
! 764: if (i == 16) {
! 765: DPRINTF(("pss: unable to locate free IRQ channel\n"));
! 766: return 0;
! 767: }
! 768: else {
! 769: ia->ia_irq = i;
! 770: DPRINTF(("pss: found IRQ %d free\n", i));
! 771: }
! 772: }
! 773: else {
! 774: if (pss_testirq(sc, ia->ia_irq) == 0) {
! 775: DPRINTF(("pss: configured IRQ unavailable (%d)\n", ia->ia_irq));
! 776: return 0;
! 777: }
! 778: }
! 779:
! 780: /* XXX Need to deal with DRQUNK */
! 781: if (pss_testdma(sc, ia->ia_drq) == 0) {
! 782: DPRINTF(("pss: configured DMA channel unavailable (%d)\n", ia->ia_drq));
! 783: return 0;
! 784: }
! 785:
! 786: ia->ia_iosize = PSS_NPORT;
! 787:
! 788: /* Initialize PSS irq and dma */
! 789: pss_setint(ia->ia_irq, sc->sc_iobase+PSS_CONFIG);
! 790: pss_setdma(sc->sc_drq, sc->sc_iobase+PSS_CONFIG);
! 791:
! 792: #ifdef notyet
! 793: /* Setup the Game port */
! 794: #ifdef PSS_GAMEPORT
! 795: DPRINTF(("Turning Game Port On.\n"));
! 796: outw(sc->sc_iobase+PSS_STATUS, inw(sc->sc_iobase+PSS_STATUS) | GAME_BIT);
! 797: #else
! 798: outw(sc->sc_iobase+PSS_STATUS, inw(sc->sc_iobase+PSS_STATUS) & GAME_BIT_MASK);
! 799: #endif
! 800:
! 801: /* Reset DSP */
! 802: pss_reset_dsp(sc);
! 803: #endif /* notyet */
! 804:
! 805: return 1;
! 806: }
! 807:
! 808: /*
! 809: * Probe for the Soundport (ad1848)
! 810: */
! 811: int
! 812: spprobe(parent, match, aux)
! 813: struct device *parent;
! 814: void *match, *aux;
! 815: {
! 816: struct ad1848_softc *sc = match;
! 817: struct pss_softc *pc = (void *) parent;
! 818: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 819: struct isa_attach_args *ia = aux;
! 820: u_char bits;
! 821: int i;
! 822:
! 823: sc->sc_iot = ia->ia_iot;
! 824: sc->sc_iobase = cf->cf_iobase + WSS_CODEC;
! 825:
! 826: /* Set WSS io address */
! 827: pss_setaddr(cf->cf_iobase, pc->sc_iobase+PSS_WSS_CONFIG);
! 828:
! 829: /* Is there an ad1848 chip at the WSS iobase ? */
! 830: if (ad1848_probe(sc) == 0) {
! 831: DPRINTF(("sp: no ad1848 ? iobase=%x\n", sc->sc_iobase));
! 832: return 0;
! 833: }
! 834:
! 835: /* Setup WSS interrupt and DMA if auto */
! 836: if (cf->cf_irq == IRQUNK) {
! 837:
! 838: /* Find unused IRQ for WSS */
! 839: for (i = 0; i < 12; i++) {
! 840: if (wss_interrupt_bits[i] != 0xff) {
! 841: if (pss_testirq(pc, i))
! 842: break;
! 843: }
! 844: }
! 845: if (i == 12) {
! 846: DPRINTF(("sp: unable to locate free IRQ for WSS\n"));
! 847: return 0;
! 848: }
! 849: else {
! 850: cf->cf_irq = i;
! 851: sc->sc_irq = i;
! 852: DPRINTF(("sp: found IRQ %d free\n", i));
! 853: }
! 854: }
! 855: else {
! 856: sc->sc_irq = cf->cf_irq;
! 857: if (pss_testirq(pc, sc->sc_irq) == 0) {
! 858: DPRINTF(("sp: configured IRQ unavailable (%d)\n", sc->sc_irq));
! 859: return 0;
! 860: }
! 861: }
! 862:
! 863: if (cf->cf_drq == DRQUNK) {
! 864: /* Find unused DMA channel for WSS */
! 865: for (i = 0; i < 4; i++) {
! 866: if (wss_dma_bits[i]) {
! 867: if (pss_testdma(pc, i))
! 868: break;
! 869: }
! 870: }
! 871: if (i == 4) {
! 872: DPRINTF(("sp: unable to locate free DMA channel for WSS\n"));
! 873: return 0;
! 874: }
! 875: else {
! 876: sc->sc_drq = cf->cf_drq = i;
! 877: DPRINTF(("sp: found DMA %d free\n", i));
! 878: }
! 879: }
! 880: else {
! 881: if (pss_testdma(pc, sc->sc_drq) == 0) {
! 882: DPRINTF(("sp: configured DMA channel unavailable (%d)\n", sc->sc_drq));
! 883: return 0;
! 884: }
! 885: sc->sc_drq = cf->cf_drq;
! 886: }
! 887: sc->sc_recdrq = sc->sc_drq;
! 888:
! 889: /* Set WSS config registers */
! 890: if ((bits = wss_interrupt_bits[sc->sc_irq]) == 0xff) {
! 891: DPRINTF(("sp: invalid interrupt configuration (irq=%d)\n", sc->sc_irq));
! 892: return 0;
! 893: }
! 894:
! 895: outb(sc->sc_iobase+WSS_CONFIG, (bits | 0x40));
! 896: if ((inb(sc->sc_iobase+WSS_STATUS) & 0x40) == 0) /* XXX What do these bits mean ? */
! 897: DPRINTF(("sp: IRQ %x\n", inb(sc->sc_iobase+WSS_STATUS)));
! 898:
! 899: outb(sc->sc_iobase+WSS_CONFIG, (bits | wss_dma_bits[sc->sc_drq]));
! 900:
! 901: pc->ad1848_sc = sc;
! 902: sc->parent = pc;
! 903:
! 904: return 1;
! 905: }
! 906:
! 907: #ifdef notyet
! 908: int
! 909: mpuprobe(parent, match, aux)
! 910: struct device *parent;
! 911: void *match, *aux;
! 912: {
! 913: struct mpu_softc *sc = match;
! 914: struct pss_softc *pc = (void *) parent;
! 915: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 916:
! 917: /* Check if midi is enabled; if it is check the interrupt */
! 918: sc->sc_iobase = cf->cf_iobase;
! 919:
! 920: if (cf->cf_irq == IRQUNK) {
! 921: int i;
! 922: for (i = 0; i < 16; i++) {
! 923: if (pss_testirq(pc, i) != 0)
! 924: break;
! 925: }
! 926: if (i == 16) {
! 927: printf("mpu: unable to locate free IRQ channel for MIDI\n");
! 928: return 0;
! 929: }
! 930: else {
! 931: cf->cf_irq = i;
! 932: sc->sc_irq = i;
! 933: DPRINTF(("mpu: found IRQ %d free\n", i));
! 934: }
! 935: }
! 936: else {
! 937: sc->sc_irq = cf->cf_irq;
! 938:
! 939: if (pss_testirq(pc, sc->sc_irq) == 0) {
! 940: printf("pss: configured MIDI IRQ unavailable (%d)\n", sc->sc_irq);
! 941: return 0;
! 942: }
! 943: }
! 944:
! 945: outw(pc->sc_iobase+MIDI_CONFIG,0);
! 946: DPRINTF(("pss: mpu port 0x%x irq %d\n", sc->sc_iobase, sc->sc_irq));
! 947: pss_setaddr(sc->sc_iobase, pc->sc_iobase+MIDI_CONFIG);
! 948: pss_setint(sc->sc_irq, pc->sc_iobase+MIDI_CONFIG);
! 949:
! 950: return 1;
! 951: }
! 952:
! 953: int
! 954: pcdprobe(parent, match, aux)
! 955: struct device *parent;
! 956: void *match, *aux;
! 957: {
! 958: struct pcd_softc *sc = match;
! 959: struct pss_softc *pc = (void *) parent;
! 960: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 961: u_short val;
! 962:
! 963: sc->sc_iobase = cf->cf_iobase;
! 964:
! 965: pss_setaddr(sc->sc_iobase, pc->sc_iobase+CD_CONFIG);
! 966:
! 967: /* Set the correct irq polarity. */
! 968: val = inw(pc->sc_iobase+CD_CONFIG);
! 969: outw(pc->sc_iobase+CD_CONFIG, 0);
! 970: val &= CD_POL_MASK;
! 971: val |= CD_POL_BIT; /* XXX if (pol) */
! 972: outw(pc->sc_iobase+CD_CONFIG, val);
! 973:
! 974: if (cf->cf_irq == IRQUNK) {
! 975: int i;
! 976: for (i = 0; i < 16; i++) {
! 977: if (pss_testirq(pc, i) != 0)
! 978: break;
! 979: }
! 980: if (i == 16) {
! 981: printf("pcd: unable to locate free IRQ channel for CD\n");
! 982: return 0;
! 983: }
! 984: else {
! 985: cf->cf_irq = i;
! 986: sc->sc_irq = i;
! 987: DPRINTF(("pcd: found IRQ %d free\n", i));
! 988: }
! 989: }
! 990: else {
! 991: sc->sc_irq = cf->cf_irq;
! 992:
! 993: if (pss_testirq(pc, sc->sc_irq) == 0) {
! 994: printf("pcd: configured CD IRQ unavailable (%d)\n", sc->sc_irq);
! 995: return 0;
! 996: }
! 997: return 1;
! 998: }
! 999: pss_setint(sc->sc_irq, pc->sc_iobase+CD_CONFIG);
! 1000:
! 1001: return 1;
! 1002: }
! 1003: #endif /* notyet */
! 1004:
! 1005: /*
! 1006: * Attach hardware to driver, attach hardware driver to audio
! 1007: * pseudo-device driver .
! 1008: */
! 1009: void
! 1010: pssattach(parent, self, aux)
! 1011: struct device *parent, *self;
! 1012: void *aux;
! 1013: {
! 1014: struct pss_softc *sc = (struct pss_softc *)self;
! 1015: struct isa_attach_args *ia = (struct isa_attach_args *)aux;
! 1016: int iobase = ia->ia_iobase;
! 1017: u_char vers;
! 1018: struct ad1848_volume vol = {150, 150};
! 1019:
! 1020: sc->sc_iobase = iobase;
! 1021: sc->sc_drq = ia->ia_drq;
! 1022:
! 1023: /* Setup interrupt handler for PSS */
! 1024: sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, IPL_AUDIO,
! 1025: pssintr, sc, sc->sc_dev.dv_xname);
! 1026:
! 1027: vers = (inw(sc->sc_iobase+PSS_ID_VERS)&0xff) - 1;
! 1028: printf(": ESC614%c\n", (vers > 0)?'A'+vers:' ');
! 1029:
! 1030: (void)config_found(self, ia->ia_ic, NULL); /* XXX */
! 1031:
! 1032: sc->out_port = PSS_MASTER_VOL;
! 1033:
! 1034: (void)pss_set_master_mode(sc, PSS_SPKR_STEREO);
! 1035: (void)pss_set_master_gain(sc, &vol);
! 1036: (void)pss_set_treble(sc, AUDIO_MAX_GAIN/2);
! 1037: (void)pss_set_bass(sc, AUDIO_MAX_GAIN/2);
! 1038:
! 1039: audio_attach_mi(&pss_audio_if, sc->ad1848_sc, &sc->ad1848_sc->sc_dev);
! 1040: }
! 1041:
! 1042: void
! 1043: spattach(parent, self, aux)
! 1044: struct device *parent, *self;
! 1045: void *aux;
! 1046: {
! 1047: struct ad1848_softc *sc = (struct ad1848_softc *)self;
! 1048: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 1049: isa_chipset_tag_t ic = aux; /* XXX */
! 1050: int iobase = cf->cf_iobase;
! 1051:
! 1052: sc->sc_iobase = iobase;
! 1053: sc->sc_drq = cf->cf_drq;
! 1054:
! 1055: sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO,
! 1056: ad1848_intr, sc, sc->sc_dev.dv_xname);
! 1057:
! 1058: sc->sc_isa = parent->dv_parent;
! 1059:
! 1060: ad1848_attach(sc);
! 1061:
! 1062: printf("\n");
! 1063: }
! 1064:
! 1065: #ifdef notyet
! 1066: void
! 1067: mpuattach(parent, self, aux)
! 1068: struct device *parent, *self;
! 1069: void *aux;
! 1070: {
! 1071: struct mpu_softc *sc = (struct mpu_softc *)self;
! 1072: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 1073: isa_chipset_tag_t ic = aux; /* XXX */
! 1074: int iobase = cf->cf_iobase;
! 1075:
! 1076: sc->sc_iobase = iobase;
! 1077:
! 1078: sc->sc_ih = isa_intr_establish(ic, cf->cf_irq, IST_EDGE, IPL_AUDIO,
! 1079: mpuintr, sc, sc->sc_dev.dv_xname);
! 1080:
! 1081: /* XXX might use pssprint func ?? */
! 1082: printf(" port 0x%x/%d irq %d\n",
! 1083: sc->sc_iobase, MIDI_NPORT, cf->cf_irq);
! 1084: }
! 1085:
! 1086: void
! 1087: pcdattach(parent, self, aux)
! 1088: struct device *parent, *self;
! 1089: void *aux;
! 1090: {
! 1091: struct pcd_softc *sc = (struct pcd_softc *)self;
! 1092: struct cfdata *cf = (void *)sc->sc_dev.dv_cfdata;
! 1093: int iobase = cf->cf_iobase;
! 1094:
! 1095: /*
! 1096: * The pss driver simply enables the cd interface. The CD
! 1097: * appropriate driver - scsi (aic6360) or Sony needs to be
! 1098: * used after this to handle the device.
! 1099: */
! 1100: sc->sc_iobase = iobase;
! 1101:
! 1102: /* XXX might use pssprint func ?? */
! 1103: printf(" port 0x%x/%d irq %d\n",
! 1104: sc->sc_iobase, 2, cf->cf_irq);
! 1105: }
! 1106: #endif /* notyet */
! 1107:
! 1108:
! 1109: int
! 1110: pss_set_master_gain(sc, gp)
! 1111: struct pss_softc *sc;
! 1112: struct ad1848_volume *gp;
! 1113: {
! 1114: DPRINTF(("pss_set_master_gain: %d:%d\n", gp->left, gp->right));
! 1115:
! 1116: #ifdef PSS_DSP
! 1117: if (gp->left > PHILLIPS_VOL_MAX)
! 1118: gp->left = PHILLIPS_VOL_MAX;
! 1119: if (gp->left < PHILLIPS_VOL_MIN)
! 1120: gp->left = PHILLIPS_VOL_MIN;
! 1121: if (gp->right > PHILLIPS_VOL_MAX)
! 1122: gp->right = PHILLIPS_VOL_MAX;
! 1123: if (gp->right < PHILLIPS_VOL_MIN)
! 1124: gp->right = PHILLIPS_VOL_MIN;
! 1125:
! 1126: pss_dspwrite(sc, SET_MASTER_COMMAND);
! 1127: pss_dspwrite(sc, MASTER_VOLUME_LEFT|(PHILLIPS_VOL_CONSTANT + gp->left / PHILLIPS_VOL_STEP));
! 1128: pss_dspwrite(sc, SET_MASTER_COMMAND);
! 1129: pss_dspwrite(sc, MASTER_VOLUME_RIGHT|(PHILLIPS_VOL_CONSTANT + gp->right / PHILLIPS_VOL_STEP));
! 1130: #endif
! 1131:
! 1132: sc->master_volume = *gp;
! 1133: return(0);
! 1134: }
! 1135:
! 1136: int
! 1137: pss_set_master_mode(sc, mode)
! 1138: struct pss_softc *sc;
! 1139: int mode;
! 1140: {
! 1141: short phillips_mode;
! 1142:
! 1143: DPRINTF(("pss_set_master_mode: %d\n", mode));
! 1144:
! 1145: if (mode == PSS_SPKR_STEREO)
! 1146: phillips_mode = PSS_STEREO;
! 1147: else if (mode == PSS_SPKR_PSEUDO)
! 1148: phillips_mode = PSS_PSEUDO;
! 1149: else if (mode == PSS_SPKR_SPATIAL)
! 1150: phillips_mode = PSS_SPATIAL;
! 1151: else if (mode == PSS_SPKR_MONO)
! 1152: phillips_mode = PSS_MONO;
! 1153: else
! 1154: return (EINVAL);
! 1155:
! 1156: #ifdef PSS_DSP
! 1157: pss_dspwrite(sc, SET_MASTER_COMMAND);
! 1158: pss_dspwrite(sc, MASTER_SWITCH | mode);
! 1159: #endif
! 1160:
! 1161: sc->master_mode = mode;
! 1162:
! 1163: return(0);
! 1164: }
! 1165:
! 1166: int
! 1167: pss_set_treble(sc, treb)
! 1168: struct pss_softc *sc;
! 1169: u_int treb;
! 1170: {
! 1171: DPRINTF(("pss_set_treble: %d\n", treb));
! 1172:
! 1173: #ifdef PSS_DSP
! 1174: if (treb > PHILLIPS_TREBLE_MAX)
! 1175: treb = PHILLIPS_TREBLE_MAX;
! 1176: if (treb < PHILLIPS_TREBLE_MIN)
! 1177: treb = PHILLIPS_TREBLE_MIN;
! 1178: pss_dspwrite(sc, SET_MASTER_COMMAND);
! 1179: pss_dspwrite(sc, MASTER_TREBLE|(PHILLIPS_TREBLE_CONSTANT + treb / PHILLIPS_TREBLE_STEP));
! 1180: #endif
! 1181:
! 1182: sc->monitor_treble = treb;
! 1183:
! 1184: return(0);
! 1185: }
! 1186:
! 1187: int
! 1188: pss_set_bass(sc, bass)
! 1189: struct pss_softc *sc;
! 1190: u_int bass;
! 1191: {
! 1192: DPRINTF(("pss_set_bass: %d\n", bass));
! 1193:
! 1194: #ifdef PSS_DSP
! 1195: if (bass > PHILLIPS_BASS_MAX)
! 1196: bass = PHILLIPS_BASS_MAX;
! 1197: if (bass < PHILLIPS_BASS_MIN)
! 1198: bass = PHILLIPS_BASS_MIN;
! 1199: pss_dspwrite(sc, SET_MASTER_COMMAND);
! 1200: pss_dspwrite(sc, MASTER_BASS|(PHILLIPS_BASS_CONSTANT + bass / PHILLIPS_BASS_STEP));
! 1201: #endif
! 1202:
! 1203: sc->monitor_bass = bass;
! 1204:
! 1205: return(0);
! 1206: }
! 1207:
! 1208: int
! 1209: pss_get_master_gain(sc, gp)
! 1210: struct pss_softc *sc;
! 1211: struct ad1848_volume *gp;
! 1212: {
! 1213: *gp = sc->master_volume;
! 1214: return(0);
! 1215: }
! 1216:
! 1217: int
! 1218: pss_get_master_mode(sc, mode)
! 1219: struct pss_softc *sc;
! 1220: u_int *mode;
! 1221: {
! 1222: *mode = sc->master_mode;
! 1223: return(0);
! 1224: }
! 1225:
! 1226: int
! 1227: pss_get_treble(sc, tp)
! 1228: struct pss_softc *sc;
! 1229: u_char *tp;
! 1230: {
! 1231: *tp = sc->monitor_treble;
! 1232: return(0);
! 1233: }
! 1234:
! 1235: int
! 1236: pss_get_bass(sc, bp)
! 1237: struct pss_softc *sc;
! 1238: u_char *bp;
! 1239: {
! 1240: *bp = sc->monitor_bass;
! 1241: return(0);
! 1242: }
! 1243:
! 1244: int
! 1245: pss_speaker_ctl(addr, newstate)
! 1246: void *addr;
! 1247: int newstate;
! 1248: {
! 1249: return(0);
! 1250: }
! 1251:
! 1252: int
! 1253: pssintr(arg)
! 1254: void *arg;
! 1255: {
! 1256: struct pss_softc *sc = arg;
! 1257: u_short sr;
! 1258:
! 1259: sr = inw(sc->sc_iobase+PSS_STATUS);
! 1260:
! 1261: DPRINTF(("pssintr: sc=%p st=%x\n", sc, sr));
! 1262:
! 1263: /* Acknowledge intr */
! 1264: outw(sc->sc_iobase+PSS_IRQ_ACK, 0);
! 1265:
! 1266: /* Is it one of ours ? */
! 1267: if (sr & (PSS_WRITE_EMPTY|PSS_READ_FULL|PSS_IRQ|PSS_DMQ_TC)) {
! 1268: /* XXX do something */
! 1269: return 1;
! 1270: }
! 1271:
! 1272: return 0;
! 1273: }
! 1274:
! 1275: #ifdef notyet
! 1276: int
! 1277: mpuintr(arg)
! 1278: void *arg;
! 1279: {
! 1280: struct mpu_softc *sc = arg;
! 1281: u_char sr;
! 1282:
! 1283: sr = inb(sc->sc_iobase+MIDI_STATUS_REG);
! 1284:
! 1285: printf("mpuintr: sc=%p sr=%x\n", sc, sr);
! 1286:
! 1287: /* XXX Need to clear intr */
! 1288: return 1;
! 1289: }
! 1290: #endif
! 1291:
! 1292: int
! 1293: pss_getdev(addr, retp)
! 1294: void *addr;
! 1295: struct audio_device *retp;
! 1296: {
! 1297: DPRINTF(("pss_getdev: retp=%p\n", retp));
! 1298:
! 1299: *retp = pss_device;
! 1300: return 0;
! 1301: }
! 1302:
! 1303: static ad1848_devmap_t mappings[] = {
! 1304: { PSS_MIC_IN_LVL, AD1848_KIND_LVL, AD1848_AUX2_CHANNEL },
! 1305: { PSS_LINE_IN_LVL, AD1848_KIND_LVL, AD1848_AUX1_CHANNEL },
! 1306: { PSS_DAC_LVL, AD1848_KIND_LVL, AD1848_DAC_CHANNEL },
! 1307: { PSS_MON_LVL, AD1848_KIND_LVL, AD1848_MONO_CHANNEL },
! 1308: { PSS_MIC_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX2_CHANNEL },
! 1309: { PSS_LINE_IN_MUTE, AD1848_KIND_MUTE, AD1848_AUX1_CHANNEL },
! 1310: { PSS_DAC_MUTE, AD1848_KIND_MUTE, AD1848_DAC_CHANNEL },
! 1311: { PSS_REC_LVL, AD1848_KIND_RECORDGAIN, -1 },
! 1312: { PSS_RECORD_SOURCE, AD1848_KIND_RECORDSOURCE, -1}
! 1313: };
! 1314:
! 1315: static int nummap = sizeof(mappings) / sizeof(mappings[0]);
! 1316:
! 1317: int
! 1318: pss_mixer_set_port(addr, cp)
! 1319: void *addr;
! 1320: mixer_ctrl_t *cp;
! 1321: {
! 1322: struct ad1848_softc *ac = addr;
! 1323: struct pss_softc *sc = ac->parent;
! 1324: struct ad1848_volume vol;
! 1325: int error = ad1848_mixer_set_port(ac, mappings, nummap, cp);
! 1326:
! 1327: if (error != ENXIO)
! 1328: return (error);
! 1329:
! 1330: switch (cp->dev) {
! 1331: case PSS_MASTER_VOL: /* master volume */
! 1332: if (cp->type == AUDIO_MIXER_VALUE) {
! 1333: if (ad1848_to_vol(cp, &vol))
! 1334: error = pss_set_master_gain(sc, &vol);
! 1335: }
! 1336: break;
! 1337:
! 1338: case PSS_OUTPUT_MODE:
! 1339: if (cp->type == AUDIO_MIXER_ENUM)
! 1340: error = pss_set_master_mode(sc, cp->un.ord);
! 1341: break;
! 1342:
! 1343: case PSS_MASTER_TREBLE: /* master treble */
! 1344: if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1)
! 1345: error = pss_set_treble(sc, (u_char)cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1346: break;
! 1347:
! 1348: case PSS_MASTER_BASS: /* master bass */
! 1349: if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1)
! 1350: error = pss_set_bass(sc, (u_char)cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
! 1351: break;
! 1352:
! 1353: default:
! 1354: return ENXIO;
! 1355: /*NOTREACHED*/
! 1356: }
! 1357:
! 1358: return 0;
! 1359: }
! 1360:
! 1361: int
! 1362: pss_mixer_get_port(addr, cp)
! 1363: void *addr;
! 1364: mixer_ctrl_t *cp;
! 1365: {
! 1366: struct ad1848_softc *ac = addr;
! 1367: struct pss_softc *sc = ac->parent;
! 1368: struct ad1848_volume vol;
! 1369: u_char eq;
! 1370: int error = ad1848_mixer_get_port(ac, mappings, nummap, cp);
! 1371:
! 1372: if (error != ENXIO)
! 1373: return (error);
! 1374:
! 1375: error = EINVAL;
! 1376:
! 1377: switch (cp->dev) {
! 1378: case PSS_MASTER_VOL: /* master volume */
! 1379: if (cp->type == AUDIO_MIXER_VALUE) {
! 1380: error = pss_get_master_gain(sc, &vol);
! 1381: if (!error)
! 1382: ad1848_from_vol(cp, &vol);
! 1383: }
! 1384: break;
! 1385:
! 1386: case PSS_MASTER_TREBLE: /* master treble */
! 1387: if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
! 1388: error = pss_get_treble(sc, &eq);
! 1389: if (!error)
! 1390: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = eq;
! 1391: }
! 1392: break;
! 1393:
! 1394: case PSS_MASTER_BASS: /* master bass */
! 1395: if (cp->type == AUDIO_MIXER_VALUE && cp->un.value.num_channels == 1) {
! 1396: error = pss_get_bass(sc, &eq);
! 1397: if (!error)
! 1398: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = eq;
! 1399: }
! 1400: break;
! 1401:
! 1402: case PSS_OUTPUT_MODE:
! 1403: if (cp->type == AUDIO_MIXER_ENUM)
! 1404: error = pss_get_master_mode(sc, &cp->un.ord);
! 1405: break;
! 1406:
! 1407: default:
! 1408: error = ENXIO;
! 1409: break;
! 1410: }
! 1411:
! 1412: return(error);
! 1413: }
! 1414:
! 1415: int
! 1416: pss_query_devinfo(addr, dip)
! 1417: void *addr;
! 1418: mixer_devinfo_t *dip;
! 1419: {
! 1420: DPRINTF(("pss_query_devinfo: index=%d\n", dip->index));
! 1421:
! 1422: switch(dip->index) {
! 1423: case PSS_MIC_IN_LVL: /* Microphone */
! 1424: dip->type = AUDIO_MIXER_VALUE;
! 1425: dip->mixer_class = PSS_INPUT_CLASS;
! 1426: dip->prev = AUDIO_MIXER_LAST;
! 1427: dip->next = PSS_MIC_IN_MUTE;
! 1428: strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
! 1429: dip->un.v.num_channels = 2;
! 1430: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1431: sizeof dip->un.v.units.name);
! 1432: break;
! 1433:
! 1434: case PSS_LINE_IN_LVL: /* line/CD */
! 1435: dip->type = AUDIO_MIXER_VALUE;
! 1436: dip->mixer_class = PSS_INPUT_CLASS;
! 1437: dip->prev = AUDIO_MIXER_LAST;
! 1438: dip->next = PSS_LINE_IN_MUTE;
! 1439: strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
! 1440: dip->un.v.num_channels = 2;
! 1441: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1442: sizeof dip->un.v.units.name);
! 1443: break;
! 1444:
! 1445: case PSS_DAC_LVL: /* dacout */
! 1446: dip->type = AUDIO_MIXER_VALUE;
! 1447: dip->mixer_class = PSS_INPUT_CLASS;
! 1448: dip->prev = AUDIO_MIXER_LAST;
! 1449: dip->next = PSS_DAC_MUTE;
! 1450: strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
! 1451: dip->un.v.num_channels = 2;
! 1452: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1453: sizeof dip->un.v.units.name);
! 1454: break;
! 1455:
! 1456: case PSS_REC_LVL: /* record level */
! 1457: dip->type = AUDIO_MIXER_VALUE;
! 1458: dip->mixer_class = PSS_RECORD_CLASS;
! 1459: dip->prev = AUDIO_MIXER_LAST;
! 1460: dip->next = PSS_RECORD_SOURCE;
! 1461: strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
! 1462: dip->un.v.num_channels = 2;
! 1463: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1464: sizeof dip->un.v.units.name);
! 1465: break;
! 1466:
! 1467: case PSS_MON_LVL: /* monitor level */
! 1468: dip->type = AUDIO_MIXER_VALUE;
! 1469: dip->mixer_class = PSS_MONITOR_CLASS;
! 1470: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1471: strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
! 1472: dip->un.v.num_channels = 1;
! 1473: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1474: sizeof dip->un.v.units.name);
! 1475: break;
! 1476:
! 1477: case PSS_MASTER_VOL: /* master volume */
! 1478: dip->type = AUDIO_MIXER_VALUE;
! 1479: dip->mixer_class = PSS_OUTPUT_CLASS;
! 1480: dip->prev = AUDIO_MIXER_LAST;
! 1481: dip->next = PSS_OUTPUT_MODE;
! 1482: strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
! 1483: dip->un.v.num_channels = 2;
! 1484: strlcpy(dip->un.v.units.name, AudioNvolume,
! 1485: sizeof dip->un.v.units.name);
! 1486: break;
! 1487:
! 1488: case PSS_MASTER_TREBLE: /* master treble */
! 1489: dip->type = AUDIO_MIXER_VALUE;
! 1490: dip->mixer_class = PSS_OUTPUT_CLASS;
! 1491: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1492: strlcpy(dip->label.name, AudioNtreble, sizeof dip->label.name);
! 1493: dip->un.v.num_channels = 1;
! 1494: strlcpy(dip->un.v.units.name, AudioNtreble,
! 1495: sizeof dip->un.v.units.name);
! 1496: break;
! 1497:
! 1498: case PSS_MASTER_BASS: /* master bass */
! 1499: dip->type = AUDIO_MIXER_VALUE;
! 1500: dip->mixer_class = PSS_OUTPUT_CLASS;
! 1501: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1502: strlcpy(dip->label.name, AudioNbass, sizeof dip->label.name);
! 1503: dip->un.v.num_channels = 1;
! 1504: strlcpy(dip->un.v.units.name, AudioNbass, sizeof dip->un.v.units.name);
! 1505: break;
! 1506:
! 1507: case PSS_OUTPUT_CLASS: /* output class descriptor */
! 1508: dip->type = AUDIO_MIXER_CLASS;
! 1509: dip->mixer_class = PSS_OUTPUT_CLASS;
! 1510: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1511: strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
! 1512: break;
! 1513:
! 1514: case PSS_INPUT_CLASS: /* input class descriptor */
! 1515: dip->type = AUDIO_MIXER_CLASS;
! 1516: dip->mixer_class = PSS_INPUT_CLASS;
! 1517: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1518: strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
! 1519: break;
! 1520:
! 1521: case PSS_MONITOR_CLASS: /* monitor class descriptor */
! 1522: dip->type = AUDIO_MIXER_CLASS;
! 1523: dip->mixer_class = PSS_MONITOR_CLASS;
! 1524: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1525: strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
! 1526: break;
! 1527:
! 1528: case PSS_RECORD_CLASS: /* record source class */
! 1529: dip->type = AUDIO_MIXER_CLASS;
! 1530: dip->mixer_class = PSS_RECORD_CLASS;
! 1531: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 1532: strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
! 1533: break;
! 1534:
! 1535: case PSS_MIC_IN_MUTE:
! 1536: dip->mixer_class = PSS_INPUT_CLASS;
! 1537: dip->type = AUDIO_MIXER_ENUM;
! 1538: dip->prev = PSS_MIC_IN_LVL;
! 1539: dip->next = AUDIO_MIXER_LAST;
! 1540: goto mute;
! 1541:
! 1542: case PSS_LINE_IN_MUTE:
! 1543: dip->mixer_class = PSS_INPUT_CLASS;
! 1544: dip->type = AUDIO_MIXER_ENUM;
! 1545: dip->prev = PSS_LINE_IN_LVL;
! 1546: dip->next = AUDIO_MIXER_LAST;
! 1547: goto mute;
! 1548:
! 1549: case PSS_DAC_MUTE:
! 1550: dip->mixer_class = PSS_INPUT_CLASS;
! 1551: dip->type = AUDIO_MIXER_ENUM;
! 1552: dip->prev = PSS_DAC_LVL;
! 1553: dip->next = AUDIO_MIXER_LAST;
! 1554: mute:
! 1555: strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
! 1556: dip->un.e.num_mem = 2;
! 1557: strlcpy(dip->un.e.member[0].label.name, AudioNoff,
! 1558: sizeof dip->un.e.member[0].label.name);
! 1559: dip->un.e.member[0].ord = 0;
! 1560: strlcpy(dip->un.e.member[1].label.name, AudioNon,
! 1561: sizeof dip->un.e.member[1].label.name);
! 1562: dip->un.e.member[1].ord = 1;
! 1563: break;
! 1564:
! 1565: case PSS_OUTPUT_MODE:
! 1566: dip->mixer_class = PSS_OUTPUT_CLASS;
! 1567: dip->type = AUDIO_MIXER_ENUM;
! 1568: dip->prev = PSS_MASTER_VOL;
! 1569: dip->next = AUDIO_MIXER_LAST;
! 1570: strlcpy(dip->label.name, AudioNmode, sizeof dip->label.name);
! 1571: dip->un.e.num_mem = 4;
! 1572: strlcpy(dip->un.e.member[0].label.name, AudioNmono,
! 1573: sizeof dip->un.e.member[0].label.name);
! 1574: dip->un.e.member[0].ord = PSS_SPKR_MONO;
! 1575: strlcpy(dip->un.e.member[1].label.name, AudioNstereo,
! 1576: sizeof dip->un.e.member[1].label.name);
! 1577: dip->un.e.member[1].ord = PSS_SPKR_STEREO;
! 1578: strlcpy(dip->un.e.member[2].label.name, AudioNpseudo,
! 1579: sizeof dip->un.e.member[2].label.name);
! 1580: dip->un.e.member[2].ord = PSS_SPKR_PSEUDO;
! 1581: strlcpy(dip->un.e.member[3].label.name, AudioNspatial,
! 1582: sizeof dip->un.e.member[3].label.name);
! 1583: dip->un.e.member[3].ord = PSS_SPKR_SPATIAL;
! 1584: break;
! 1585:
! 1586: case PSS_RECORD_SOURCE:
! 1587: dip->mixer_class = PSS_RECORD_CLASS;
! 1588: dip->type = AUDIO_MIXER_ENUM;
! 1589: dip->prev = PSS_REC_LVL;
! 1590: dip->next = AUDIO_MIXER_LAST;
! 1591: strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
! 1592: dip->un.e.num_mem = 3;
! 1593: strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
! 1594: sizeof dip->un.e.member[0].label.name);
! 1595: dip->un.e.member[0].ord = PSS_MIC_IN_LVL;
! 1596: strlcpy(dip->un.e.member[1].label.name, AudioNcd,
! 1597: sizeof dip->un.e.member[1].label.name);
! 1598: dip->un.e.member[1].ord = PSS_LINE_IN_LVL;
! 1599: strlcpy(dip->un.e.member[2].label.name, AudioNdac,
! 1600: sizeof dip->un.e.member[2].label.name);
! 1601: dip->un.e.member[2].ord = PSS_DAC_LVL;
! 1602: break;
! 1603:
! 1604: default:
! 1605: return ENXIO;
! 1606: /*NOTREACHED*/
! 1607: }
! 1608: DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
! 1609:
! 1610: return 0;
! 1611: }
CVSweb