[BACK]Return to pas.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / isa

Annotation of src/sys/dev/isa/pas.c, Revision 1.29

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

CVSweb <webmaster@jp.NetBSD.org>