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

Annotation of sys/dev/isa/pas.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pas.c,v 1.24 2003/04/27 11:22:53 ho Exp $     */
        !             2: /*     $NetBSD: pas.c,v 1.37 1998/01/12 09:43:43 thorpej Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1991-1993 Regents of the University of California.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the Computer Systems
        !            19:  *     Engineering Group at Lawrence Berkeley Laboratory.
        !            20:  * 4. Neither the name of the University nor of the Laboratory may be used
        !            21:  *    to endorse or promote products derived from this software without
        !            22:  *    specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  */
        !            37: /*
        !            38:  * jfw 7/13/97 - The soundblaster code requires the generic bus-space
        !            39:  * structures to be set up properly.  Rather than go to the effort of making
        !            40:  * code for a dead line fully generic, properly set up the SB structures and
        !            41:  * leave the rest x86/ISA/default-configuration specific.  If you have a
        !            42:  * REAL computer, go buy a REAL sound card.
        !            43:  */
        !            44: /*
        !            45:  * Todo:
        !            46:  *     - look at other PAS drivers (for PAS native support)
        !            47:  *     - use common sb.c once emulation is setup
        !            48:  */
        !            49:
        !            50: #include <sys/param.h>
        !            51: #include <sys/systm.h>
        !            52: #include <sys/errno.h>
        !            53: #include <sys/ioctl.h>
        !            54: #include <sys/syslog.h>
        !            55: #include <sys/device.h>
        !            56: #include <sys/proc.h>
        !            57:
        !            58: #include <machine/cpu.h>
        !            59: #include <machine/intr.h>
        !            60: #include <machine/bus.h>
        !            61:
        !            62: #include <sys/audioio.h>
        !            63: #include <dev/audio_if.h>
        !            64: #include <dev/midi_if.h>
        !            65:
        !            66: #include <dev/isa/isavar.h>
        !            67: #include <dev/isa/isadmavar.h>
        !            68:
        !            69: #include <dev/isa/sbdspvar.h>
        !            70: #include <dev/isa/sbreg.h>
        !            71:
        !            72: #define DEFINE_TRANSLATIONS
        !            73: #include <dev/isa/pasreg.h>
        !            74:
        !            75: #ifdef AUDIO_DEBUG
        !            76: #define DPRINTF(x)     if (pasdebug) printf x
        !            77: int    pasdebug = 0;
        !            78: #else
        !            79: #define DPRINTF(x)
        !            80: #endif
        !            81:
        !            82: /*
        !            83:  * Software state, per SoundBlaster card.
        !            84:  * The soundblaster has multiple functionality, which we must demultiplex.
        !            85:  * One approach is to have one major device number for the soundblaster card,
        !            86:  * and use different minor numbers to indicate which hardware function
        !            87:  * we want.  This would make for one large driver.  Instead our approach
        !            88:  * is to partition the design into a set of drivers that share an underlying
        !            89:  * piece of hardware.  Most things are hard to share, for example, the audio
        !            90:  * and midi ports.  For audio, we might want to mix two processes' signals,
        !            91:  * and for midi we might want to merge streams (this is hard due to
        !            92:  * running status).  Moreover, we should be able to re-use the high-level
        !            93:  * modules with other kinds of hardware.  In this module, we only handle the
        !            94:  * most basic communications with the sb card.
        !            95:  */
        !            96: struct pas_softc {
        !            97:        struct sbdsp_softc sc_sbdsp;    /* use sc_dev, sc_id, sc_ih,
        !            98:                                         *     sc_iobase, sc_irq, sc_drq
        !            99:                                         * from here */
        !           100:        int model;      /* unique to PAS */
        !           101:        int rev;
        !           102:
        !           103: };
        !           104:
        !           105: int    pas_getdev(void *, struct audio_device *);
        !           106: void   pasconf(int, int, int, int);
        !           107:
        !           108:
        !           109: /*
        !           110:  * Define our interface to the higher level audio driver.
        !           111:  */
        !           112:
        !           113: struct audio_hw_if pas_hw_if = {
        !           114:        sbdsp_open,
        !           115:        sbdsp_close,
        !           116:        0,
        !           117:        sbdsp_query_encoding,
        !           118:        sbdsp_set_params,
        !           119:        sbdsp_round_blocksize,
        !           120:        0,
        !           121:        0,
        !           122:        0,
        !           123:        0,
        !           124:        0,
        !           125:        sbdsp_haltdma,
        !           126:        sbdsp_haltdma,
        !           127:        sbdsp_speaker_ctl,
        !           128:        pas_getdev,
        !           129:        0,
        !           130:        sbdsp_mixer_set_port,
        !           131:        sbdsp_mixer_get_port,
        !           132:        sbdsp_mixer_query_devinfo,
        !           133:        sb_malloc,
        !           134:        sb_free,
        !           135:        sb_round,
        !           136:         sb_mappage,
        !           137:        sbdsp_get_props,
        !           138:        sbdsp_trigger_output,
        !           139:        sbdsp_trigger_input
        !           140: };
        !           141:
        !           142: /* The Address Translation code is used to convert I/O register addresses to
        !           143:    be relative to the given base -register */
        !           144:
        !           145: static char *pasnames[] = {
        !           146:        "",
        !           147:        "Plus",
        !           148:        "CDPC",
        !           149:        "16",
        !           150:        "16Basic"
        !           151: };
        !           152:
        !           153: static struct audio_device pas_device = {
        !           154:        "PAS,??",
        !           155:        "",
        !           156:        "pas"
        !           157: };
        !           158:
        !           159: /*XXX assume default I/O base address */
        !           160: #define pasread(p) inb(p)
        !           161: #define paswrite(d, p) outb(p, d)
        !           162:
        !           163: void
        !           164: pasconf(model, sbbase, sbirq, sbdrq)
        !           165:        int model;
        !           166:        int sbbase;
        !           167:        int sbirq;
        !           168:        int sbdrq;
        !           169: {
        !           170:        paswrite(0x00, INTERRUPT_MASK);
        !           171:        /* Local timer control register */
        !           172:        paswrite(0x36, SAMPLE_COUNTER_CONTROL);
        !           173:        /* Sample rate timer (16 bit) */
        !           174:        paswrite(0x36, SAMPLE_RATE_TIMER);
        !           175:        paswrite(0, SAMPLE_RATE_TIMER);
        !           176:        /* Local timer control register */
        !           177:        paswrite(0x74, SAMPLE_COUNTER_CONTROL);
        !           178:        /* Sample count register (16 bit) */
        !           179:        paswrite(0x74, SAMPLE_BUFFER_COUNTER);
        !           180:        paswrite(0, SAMPLE_BUFFER_COUNTER);
        !           181:
        !           182:        paswrite(P_C_PCM_MONO | P_C_PCM_DAC_MODE |
        !           183:                  P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R,
        !           184:                  PCM_CONTROL);
        !           185:        paswrite(S_M_PCM_RESET | S_M_FM_RESET |
        !           186:                  S_M_SB_RESET | S_M_MIXER_RESET, SERIAL_MIXER);
        !           187:
        !           188: /*XXX*/
        !           189:        paswrite(I_C_1_BOOT_RESET_ENABLE|1, IO_CONFIGURATION_1);
        !           190:
        !           191:        paswrite(I_C_2_PCM_DMA_DISABLED, IO_CONFIGURATION_2);
        !           192:        paswrite(I_C_3_PCM_IRQ_DISABLED, IO_CONFIGURATION_3);
        !           193:
        !           194: #ifdef BROKEN_BUS_CLOCK
        !           195:        paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND |
        !           196:                  S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
        !           197: #else
        !           198:        paswrite(S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND,
        !           199:                  SYSTEM_CONFIGURATION_1);
        !           200: #endif
        !           201:
        !           202:        /*XXX*/
        !           203:        paswrite(0, SYSTEM_CONFIGURATION_2);
        !           204:        paswrite(0, SYSTEM_CONFIGURATION_3);
        !           205:
        !           206:        /* Sets mute off and selects filter rate of 17.897 kHz */
        !           207:        paswrite(F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);
        !           208:
        !           209:        if (model == PAS_16 || model == PAS_16BASIC)
        !           210:                paswrite(8, PRESCALE_DIVIDER);
        !           211:        else
        !           212:                paswrite(0, PRESCALE_DIVIDER);
        !           213:
        !           214:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_PCM, PARALLEL_MIXER);
        !           215:        paswrite(5, PARALLEL_MIXER);
        !           216:
        !           217:        /*
        !           218:         * Setup SoundBlaster emulation.
        !           219:         */
        !           220:        paswrite((sbbase >> 4) & 0xf, EMULATION_ADDRESS);
        !           221:        paswrite(E_C_SB_IRQ_translate[sbirq] | E_C_SB_DMA_translate[sbdrq],
        !           222:                 EMULATION_CONFIGURATION);
        !           223:        paswrite(C_E_SB_ENABLE, COMPATIBILITY_ENABLE);
        !           224:
        !           225:        /*
        !           226:         * Set mid-range levels.
        !           227:         */
        !           228:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
        !           229:        paswrite(P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_NONE, PARALLEL_MIXER);
        !           230:
        !           231:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_A, PARALLEL_MIXER);
        !           232:        paswrite(50, PARALLEL_MIXER);
        !           233:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_MASTER_B, PARALLEL_MIXER);
        !           234:        paswrite(50, PARALLEL_MIXER);
        !           235:
        !           236:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_SB, PARALLEL_MIXER);
        !           237:        paswrite(P_M_MV508_OUTPUTMIX | 30, PARALLEL_MIXER);
        !           238:
        !           239:        paswrite(P_M_MV508_ADDRESS | P_M_MV508_MIXER | P_M_MV508_MIC, PARALLEL_MIXER);
        !           240:        paswrite(P_M_MV508_INPUTMIX | 30, PARALLEL_MIXER);
        !           241: }
        !           242:
        !           243: int    pasprobe(struct device *, void *, void *);
        !           244: void   pasattach(struct device *, struct device *, void *);
        !           245:
        !           246: struct cfattach pas_ca = {
        !           247:        sizeof(struct pas_softc), pasprobe, pasattach
        !           248: };
        !           249:
        !           250: struct cfdriver pas_cd = {
        !           251:        NULL, "pas", DV_DULL
        !           252: };
        !           253:
        !           254: /*
        !           255:  * Probe / attach routines.
        !           256:  */
        !           257:
        !           258: /*
        !           259:  * Probe for the soundblaster hardware.
        !           260:  */
        !           261: int
        !           262: pasprobe(parent, match, aux)
        !           263:        struct device *parent;
        !           264:        void *match, *aux;
        !           265: {
        !           266:        struct pas_softc *sc = match;
        !           267:        struct isa_attach_args *ia = aux;
        !           268:        int iobase;
        !           269:        u_char id, t;
        !           270:
        !           271:         /* ensure we can set this up as a sound blaster */
        !           272:                if (!SB_BASE_VALID(ia->ia_iobase)) {
        !           273:                DPRINTF(("pas: configured SB iobase 0x%x invalid\n", ia->ia_iobase));
        !           274:                return 0;
        !           275:        }
        !           276:
        !           277:        /*
        !           278:         * WARNING: Setting an option like W:1 or so that disables
        !           279:         * warm boot reset of the card will screw up this detect code
        !           280:         * something fierce.  Adding code to handle this means possibly
        !           281:         * interfering with other cards on the bus if you have something
        !           282:         * on base port 0x388.  SO be forewarned.
        !           283:         */
        !           284:        /* Talk to first board */
        !           285:        outb(MASTER_DECODE, 0xbc);
        !           286:        /* Set base address */
        !           287:
        !           288: #if 0
        !           289:        /* XXX Need to setup pseudo device */
        !           290:        /* XXX What are good io addrs ? */
        !           291:        if (iobase != PAS_DEFAULT_BASE) {
        !           292:                DPRINTF(("pas: configured iobase %d invalid\n", iobase));
        !           293:                return 0;
        !           294:        }
        !           295: #else
        !           296:        /* Start out talking to native PAS */
        !           297:        iobase = PAS_DEFAULT_BASE;
        !           298: #endif
        !           299:
        !           300:        outb(MASTER_DECODE, iobase >> 2);
        !           301:        /* One wait-state */
        !           302:        paswrite(1, WAIT_STATE);
        !           303:
        !           304:        id = pasread(INTERRUPT_MASK);
        !           305:        if (id == 0xff || id == 0xfe) {
        !           306:                /* sanity */
        !           307:                DPRINTF(("pas: bogus card id\n"));
        !           308:                return 0;
        !           309:        }
        !           310:        /*
        !           311:         * We probably have a PAS-series board, now check for a
        !           312:         * PAS2-series board by trying to change the board revision
        !           313:         * bits.  PAS2-series hardware won't let you do this because
        !           314:         * the bits are read-only.
        !           315:         */
        !           316:        t = id ^ 0xe0;
        !           317:        paswrite(t, INTERRUPT_MASK);
        !           318:        t = inb(INTERRUPT_MASK);
        !           319:        paswrite(id, INTERRUPT_MASK);
        !           320:
        !           321:        if (t != id) {
        !           322:                /* Not a PAS2 */
        !           323:                DPRINTF(("pas: detected card but PAS2 test failed\n"));
        !           324:                return 0;
        !           325:        }
        !           326:        /*XXX*/
        !           327:        t = pasread(OPERATION_MODE_1) & 0xf;
        !           328:        sc->model = O_M_1_to_card[t];
        !           329:        if (sc->model != 0) {
        !           330:                sc->rev = pasread(BOARD_REV_ID);
        !           331:        }
        !           332:        else {
        !           333:                DPRINTF(("pas: bogus model id\n"));
        !           334:                return 0;
        !           335:        }
        !           336:
        !           337:         if (sc->model >= 0) {
        !           338:                 if (ia->ia_irq == IRQUNK) {
        !           339:                         DPRINTF(("pas: sb emulation requires known irq\n"));
        !           340:                         return (0);
        !           341:                 }
        !           342:                 pasconf(sc->model, ia->ia_iobase, ia->ia_irq, 1);
        !           343:         } else {
        !           344:                 DPRINTF(("pas: could not probe pas\n"));
        !           345:                 return (0);
        !           346:         }
        !           347:
        !           348:        /* Now a SoundBlaster, so set up proper bus-space hooks
        !           349:          * appropriately
        !           350:          */
        !           351:
        !           352:        sc->sc_sbdsp.sc_iobase = ia->ia_iobase;
        !           353:        sc->sc_sbdsp.sc_iot = ia->ia_iot;
        !           354:
        !           355:        /* Map i/o space [we map 24 ports which is the max of the sb and pro */
        !           356:        if (bus_space_map(sc->sc_sbdsp.sc_iot, ia->ia_iobase, SBP_NPORT, 0,
        !           357:            &sc->sc_sbdsp.sc_ioh)) {
        !           358:                DPRINTF(("pas: can't map i/o space 0x%x/%d in probe\n",
        !           359:                    ia->ia_iobase, SBP_NPORT));
        !           360:                return 0;
        !           361:        }
        !           362:
        !           363:        if (sbdsp_reset(&sc->sc_sbdsp) < 0) {
        !           364:                DPRINTF(("pas: couldn't reset card\n"));
        !           365:                goto unmap;
        !           366:        }
        !           367:
        !           368:        /*
        !           369:         * Cannot auto-discover DMA channel.
        !           370:         */
        !           371:        if (!SB_DRQ_VALID(ia->ia_drq)) {
        !           372:                DPRINTF(("pas: configured dma chan %d invalid\n", ia->ia_drq));
        !           373:                goto unmap;
        !           374:        }
        !           375:        if (!SB_IRQ_VALID(ia->ia_irq)) {
        !           376:                DPRINTF(("pas: configured irq chan %d invalid\n", ia->ia_irq));
        !           377:                goto unmap;
        !           378:        }
        !           379:
        !           380:        sc->sc_sbdsp.sc_irq = ia->ia_irq;
        !           381:        sc->sc_sbdsp.sc_drq8 = ia->ia_drq;
        !           382:        sc->sc_sbdsp.sc_drq16 = -1; /* XXX */
        !           383:        sc->sc_sbdsp.sc_ic = ia->ia_ic;
        !           384:
        !           385:        if (sbdsp_probe(&sc->sc_sbdsp) == 0) {
        !           386:                DPRINTF(("pas: sbdsp probe failed\n"));
        !           387:                goto unmap;
        !           388:        }
        !           389:
        !           390:        ia->ia_iosize = SB_NPORT;
        !           391:        return 1;
        !           392:
        !           393:  unmap:
        !           394:        bus_space_unmap(sc->sc_sbdsp.sc_iot, sc->sc_sbdsp.sc_ioh, SBP_NPORT);
        !           395:        return 0;
        !           396: }
        !           397:
        !           398: /*
        !           399:  * Attach hardware to driver, attach hardware driver to audio
        !           400:  * pseudo-device driver .
        !           401:  */
        !           402: void
        !           403: pasattach(parent, self, aux)
        !           404:        struct device *parent, *self;
        !           405:        void *aux;
        !           406: {
        !           407:        struct pas_softc *sc = (struct pas_softc *)self;
        !           408:        struct isa_attach_args *ia = (struct isa_attach_args *)aux;
        !           409:        int iobase = ia->ia_iobase;
        !           410:
        !           411:        sc->sc_sbdsp.sc_isa = parent;
        !           412:        sc->sc_sbdsp.sc_iobase = iobase;
        !           413:        sc->sc_sbdsp.sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
        !           414:            IPL_AUDIO, sbdsp_intr, &sc->sc_sbdsp, sc->sc_sbdsp.sc_dev.dv_xname);
        !           415:
        !           416:        printf(" ProAudio Spectrum %s [rev %d] ", pasnames[sc->model], sc->rev);
        !           417:
        !           418:        sbdsp_attach(&sc->sc_sbdsp);
        !           419:
        !           420:        snprintf(pas_device.name, sizeof pas_device.name, "pas,%s",
        !           421:            pasnames[sc->model]);
        !           422:        snprintf(pas_device.version, sizeof pas_device.version, "%d",
        !           423:            sc->rev);
        !           424:
        !           425:        audio_attach_mi(&pas_hw_if, &sc->sc_sbdsp, &sc->sc_sbdsp.sc_dev);
        !           426: }
        !           427:
        !           428: int
        !           429: pas_getdev(addr, retp)
        !           430:        void *addr;
        !           431:        struct audio_device *retp;
        !           432: {
        !           433:        *retp = pas_device;
        !           434:        return 0;
        !           435: }

CVSweb