[BACK]Return to wss.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/wss.c, Revision 1.1.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