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