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

Annotation of sys/dev/pci/eso.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: eso.c,v 1.22 2005/08/09 04:10:11 mickey Exp $ */
        !             2: /*     $NetBSD: eso.c,v 1.3 1999/08/02 17:37:43 augustss Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1999 Klaus J. Klein
        !             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. The name of the author may not be used to endorse or promote products
        !            17:  *    derived from this software without specific prior written permission.
        !            18:  *
        !            19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            20:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            21:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            22:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            23:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            24:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            25:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            26:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            27:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            29:  * SUCH DAMAGE.
        !            30:  */
        !            31:
        !            32: /*
        !            33:  * ESS Technology Inc. Solo-1 PCI AudioDrive (ES1938/1946) device driver.
        !            34:  */
        !            35:
        !            36: #ifdef __OpenBSD__
        !            37: #define HIDE
        !            38: #define MATCH_ARG_2_T void *
        !            39: #else
        !            40: #define HIDE static
        !            41: #define MATCH_ARG_2_T struct cfdata *
        !            42: #endif
        !            43:
        !            44: #include <sys/param.h>
        !            45: #include <sys/systm.h>
        !            46: #include <sys/kernel.h>
        !            47: #include <sys/malloc.h>
        !            48: #include <sys/device.h>
        !            49: #include <sys/proc.h>
        !            50:
        !            51: #include <dev/pci/pcidevs.h>
        !            52: #include <dev/pci/pcivar.h>
        !            53:
        !            54: #include <sys/audioio.h>
        !            55: #include <dev/audio_if.h>
        !            56: #include <dev/midi_if.h>
        !            57:
        !            58: #include <dev/mulaw.h>
        !            59: #include <dev/auconv.h>
        !            60:
        !            61: #include <dev/ic/mpuvar.h>
        !            62: #include <dev/ic/i8237reg.h>
        !            63: #include <dev/pci/esoreg.h>
        !            64: #include <dev/pci/esovar.h>
        !            65: #include <dev/audiovar.h>
        !            66:
        !            67: #include <machine/bus.h>
        !            68: #include <machine/intr.h>
        !            69:
        !            70: #if defined(AUDIO_DEBUG) || defined(DEBUG)
        !            71: #define DPRINTF(x) printf x
        !            72: #else
        !            73: #define DPRINTF(x)
        !            74: #endif
        !            75:
        !            76: struct eso_dma {
        !            77:        bus_dmamap_t            ed_map;
        !            78:        caddr_t                 ed_addr;
        !            79:        bus_dma_segment_t       ed_segs[1];
        !            80:        int                     ed_nsegs;
        !            81:        size_t                  ed_size;
        !            82:        struct eso_dma *        ed_next;
        !            83: };
        !            84:
        !            85: #define KVADDR(dma)    ((void *)(dma)->ed_addr)
        !            86: #define DMAADDR(dma)   ((dma)->ed_map->dm_segs[0].ds_addr)
        !            87:
        !            88: /* Autoconfiguration interface */
        !            89: HIDE int eso_match(struct device *, MATCH_ARG_2_T, void *);
        !            90: HIDE void eso_attach(struct device *, struct device *, void *);
        !            91: HIDE void eso_defer(struct device *);
        !            92:
        !            93: struct cfattach eso_ca = {
        !            94:        sizeof (struct eso_softc), eso_match, eso_attach
        !            95: };
        !            96:
        !            97: #ifdef __OpenBSD__
        !            98: struct cfdriver eso_cd = {
        !            99:        NULL, "eso", DV_DULL
        !           100: };
        !           101: #endif
        !           102:
        !           103: /* PCI interface */
        !           104: HIDE int eso_intr(void *);
        !           105:
        !           106: /* MI audio layer interface */
        !           107: HIDE int       eso_open(void *, int);
        !           108: HIDE void      eso_close(void *);
        !           109: HIDE int       eso_query_encoding(void *, struct audio_encoding *);
        !           110: HIDE int       eso_set_params(void *, int, int, struct audio_params *,
        !           111:                    struct audio_params *);
        !           112: HIDE int       eso_round_blocksize(void *, int);
        !           113: HIDE int       eso_halt_output(void *);
        !           114: HIDE int       eso_halt_input(void *);
        !           115: HIDE int       eso_getdev(void *, struct audio_device *);
        !           116: HIDE int       eso_set_port(void *, mixer_ctrl_t *);
        !           117: HIDE int       eso_get_port(void *, mixer_ctrl_t *);
        !           118: HIDE int       eso_query_devinfo(void *, mixer_devinfo_t *);
        !           119: HIDE void *    eso_allocm(void *, int, size_t, int, int);
        !           120: HIDE void      eso_freem(void *, void *, int);
        !           121: HIDE size_t    eso_round_buffersize(void *, int, size_t);
        !           122: HIDE paddr_t   eso_mappage(void *, void *, off_t, int);
        !           123: HIDE int       eso_get_props(void *);
        !           124: HIDE int       eso_trigger_output(void *, void *, void *, int,
        !           125:                    void (*)(void *), void *, struct audio_params *);
        !           126: HIDE int       eso_trigger_input(void *, void *, void *, int,
        !           127:                    void (*)(void *), void *, struct audio_params *);
        !           128: HIDE void       eso_setup(struct eso_softc *, int);
        !           129:
        !           130: HIDE void       eso_powerhook(int, void *);
        !           131:
        !           132:
        !           133: HIDE struct audio_hw_if eso_hw_if = {
        !           134:        eso_open,
        !           135:        eso_close,
        !           136:        NULL,                   /* drain */
        !           137:        eso_query_encoding,
        !           138:        eso_set_params,
        !           139:        eso_round_blocksize,
        !           140:        NULL,                   /* commit_settings */
        !           141:        NULL,                   /* init_output */
        !           142:        NULL,                   /* init_input */
        !           143:        NULL,                   /* start_output */
        !           144:        NULL,                   /* start_input */
        !           145:        eso_halt_output,
        !           146:        eso_halt_input,
        !           147:        NULL,                   /* speaker_ctl */
        !           148:        eso_getdev,
        !           149:        NULL,                   /* setfd */
        !           150:        eso_set_port,
        !           151:        eso_get_port,
        !           152:        eso_query_devinfo,
        !           153:        eso_allocm,
        !           154:        eso_freem,
        !           155:        eso_round_buffersize,
        !           156:        eso_mappage,
        !           157:        eso_get_props,
        !           158:        eso_trigger_output,
        !           159:        eso_trigger_input,
        !           160: };
        !           161:
        !           162: HIDE const char * const eso_rev2model[] = {
        !           163:        "ES1938",
        !           164:        "ES1946",
        !           165:        "ES1946 rev E"
        !           166: };
        !           167:
        !           168:
        !           169: /*
        !           170:  * Utility routines
        !           171:  */
        !           172: /* Register access etc. */
        !           173: HIDE uint8_t   eso_read_ctlreg(struct eso_softc *, uint8_t);
        !           174: HIDE uint8_t   eso_read_mixreg(struct eso_softc *, uint8_t);
        !           175: HIDE uint8_t   eso_read_rdr(struct eso_softc *);
        !           176: HIDE int       eso_reset(struct eso_softc *);
        !           177: HIDE void      eso_set_gain(struct eso_softc *, unsigned int);
        !           178: HIDE int       eso_set_recsrc(struct eso_softc *, unsigned int);
        !           179: HIDE void      eso_write_cmd(struct eso_softc *, uint8_t);
        !           180: HIDE void      eso_write_ctlreg(struct eso_softc *, uint8_t, uint8_t);
        !           181: HIDE void      eso_write_mixreg(struct eso_softc *, uint8_t, uint8_t);
        !           182: /* DMA memory allocation */
        !           183: HIDE int       eso_allocmem(struct eso_softc *, size_t, size_t, size_t,
        !           184:                    int, struct eso_dma *);
        !           185: HIDE void      eso_freemem(struct eso_softc *, struct eso_dma *);
        !           186:
        !           187:
        !           188: HIDE int
        !           189: eso_match(parent, match, aux)
        !           190:        struct device *parent;
        !           191:        MATCH_ARG_2_T match;
        !           192:        void *aux;
        !           193: {
        !           194:        struct pci_attach_args *pa = aux;
        !           195:
        !           196:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ESSTECH &&
        !           197:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ESSTECH_SOLO1)
        !           198:                return (1);
        !           199:
        !           200:        return (0);
        !           201: }
        !           202:
        !           203: HIDE void
        !           204: eso_attach(parent, self, aux)
        !           205:        struct device *parent, *self;
        !           206:        void *aux;
        !           207: {
        !           208:        struct eso_softc *sc = (struct eso_softc *)self;
        !           209:        struct pci_attach_args *pa = aux;
        !           210:        struct audio_attach_args aa;
        !           211:        pci_intr_handle_t ih;
        !           212:        bus_addr_t vcbase;
        !           213:        const char *intrstring;
        !           214:
        !           215:        sc->sc_revision = PCI_REVISION(pa->pa_class);
        !           216:
        !           217:        if (sc->sc_revision <
        !           218:            sizeof (eso_rev2model) / sizeof (eso_rev2model[0]))
        !           219:                printf(": %s", eso_rev2model[sc->sc_revision]);
        !           220:        else
        !           221:                printf(": (unknown rev. 0x%02x)", sc->sc_revision);
        !           222:
        !           223:        /* Map I/O registers. */
        !           224:        if (pci_mapreg_map(pa, ESO_PCI_BAR_IO, PCI_MAPREG_TYPE_IO, 0,
        !           225:            &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0)) {
        !           226:                printf(", can't map I/O space\n");
        !           227:                return;
        !           228:        }
        !           229:        if (pci_mapreg_map(pa, ESO_PCI_BAR_SB, PCI_MAPREG_TYPE_IO, 0,
        !           230:            &sc->sc_sb_iot, &sc->sc_sb_ioh, NULL, NULL, 0)) {
        !           231:                printf(", can't map SB I/O space\n");
        !           232:                return;
        !           233:        }
        !           234:        if (pci_mapreg_map(pa, ESO_PCI_BAR_VC, PCI_MAPREG_TYPE_IO, 0,
        !           235:            &sc->sc_dmac_iot, &sc->sc_dmac_ioh, &vcbase, &sc->sc_vcsize, 0)) {
        !           236:                vcbase = 0;
        !           237:                sc->sc_vcsize = 0x10; /* From the data sheet. */
        !           238:        }
        !           239:
        !           240:        if (pci_mapreg_map(pa, ESO_PCI_BAR_MPU, PCI_MAPREG_TYPE_IO, 0,
        !           241:            &sc->sc_mpu_iot, &sc->sc_mpu_ioh, NULL, NULL, 0)) {
        !           242:                printf(", can't map MPU I/O space\n");
        !           243:                return;
        !           244:        }
        !           245:        if (pci_mapreg_map(pa, ESO_PCI_BAR_GAME, PCI_MAPREG_TYPE_IO, 0,
        !           246:            &sc->sc_game_iot, &sc->sc_game_ioh, NULL, NULL, 0)) {
        !           247:                printf(", can't map Game I/O space\n");
        !           248:                return;
        !           249:        }
        !           250:
        !           251:        sc->sc_dmat = pa->pa_dmat;
        !           252:        sc->sc_dmas = NULL;
        !           253:        sc->sc_dmac_configured = 0;
        !           254:
        !           255:        sc->sc_pa = *pa;
        !           256:
        !           257:        eso_setup(sc, 1);
        !           258:
        !           259:        /* map and establish the interrupt. */
        !           260:        if (pci_intr_map(pa, &ih)) {
        !           261:                printf(", couldn't map interrupt\n");
        !           262:                return;
        !           263:        }
        !           264:        intrstring = pci_intr_string(pa->pa_pc, ih);
        !           265: #ifdef __OpenBSD__
        !           266:        sc->sc_ih  = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, eso_intr, sc,
        !           267:                                        sc->sc_dev.dv_xname);
        !           268: #else
        !           269:        sc->sc_ih  = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, eso_intr, sc);
        !           270: #endif
        !           271:        if (sc->sc_ih == NULL) {
        !           272:                printf(", couldn't establish interrupt");
        !           273:                if (intrstring != NULL)
        !           274:                        printf(" at %s", intrstring);
        !           275:                printf("\n");
        !           276:                return;
        !           277:        }
        !           278:        printf(", %s\n", intrstring);
        !           279:
        !           280:        /*
        !           281:         * Set up the DDMA Control register; a suitable I/O region has been
        !           282:         * supposedly mapped in the VC base address register.
        !           283:         *
        !           284:         * The Solo-1 has an ... interesting silicon bug that causes it to
        !           285:         * not respond to I/O space accesses to the Audio 1 DMA controller
        !           286:         * if the latter's mapping base address is aligned on a 1K boundary.
        !           287:         * As a consequence, it is quite possible for the mapping provided
        !           288:         * in the VC BAR to be useless.  To work around this, we defer this
        !           289:         * part until all autoconfiguration on our parent bus is completed
        !           290:         * and then try to map it ourselves in fulfillment of the constraint.
        !           291:         *
        !           292:         * According to the register map we may write to the low 16 bits
        !           293:         * only, but experimenting has shown we're safe.
        !           294:         * -kjk
        !           295:         */
        !           296:
        !           297:        if (ESO_VALID_DDMAC_BASE(vcbase)) {
        !           298:                pci_conf_write(pa->pa_pc, pa->pa_tag, ESO_PCI_DDMAC,
        !           299:                               vcbase | ESO_PCI_DDMAC_DE);
        !           300:                sc->sc_dmac_configured = 1;
        !           301:
        !           302:                printf("%s: mapping Audio 1 DMA using VC I/O space at 0x%lx\n",
        !           303:                       sc->sc_dev.dv_xname, (unsigned long)vcbase);
        !           304:        } else {
        !           305:                DPRINTF(("%s: VC I/O space at 0x%lx not suitable, deferring\n",
        !           306:                         sc->sc_dev.dv_xname, (unsigned long)vcbase));
        !           307:                config_defer((struct device *)sc, eso_defer);
        !           308:        }
        !           309:
        !           310:        audio_attach_mi(&eso_hw_if, sc, &sc->sc_dev);
        !           311:
        !           312:        aa.type = AUDIODEV_TYPE_OPL;
        !           313:        aa.hwif = NULL;
        !           314:        aa.hdl = NULL;
        !           315:        (void)config_found(&sc->sc_dev, &aa, audioprint);
        !           316:
        !           317:        sc->sc_powerhook = powerhook_establish(&eso_powerhook, sc);
        !           318:
        !           319: #if 0
        !           320:        aa.type = AUDIODEV_TYPE_MPU;
        !           321:        aa.hwif = NULL;
        !           322:        aa.hdl = NULL;
        !           323:        sc->sc_mpudev = config_found(&sc->sc_dev, &aa, audioprint);
        !           324: #endif
        !           325: }
        !           326:
        !           327: HIDE void
        !           328: eso_setup(sc, verbose)
        !           329:        struct eso_softc *sc;
        !           330:        int verbose;
        !           331: {
        !           332:        struct pci_attach_args *pa = &sc->sc_pa;
        !           333:        uint8_t a2mode;
        !           334:        int idx;
        !           335:
        !           336:        /* Reset the device; bail out upon failure. */
        !           337:        if (eso_reset(sc) != 0) {
        !           338:                if (verbose) printf(", can't reset\n");
        !           339:                return;
        !           340:        }
        !           341:
        !           342:        /* Select the DMA/IRQ policy: DDMA, ISA IRQ emulation disabled. */
        !           343:        pci_conf_write(pa->pa_pc, pa->pa_tag, ESO_PCI_S1C,
        !           344:                       pci_conf_read(pa->pa_pc, pa->pa_tag, ESO_PCI_S1C) &
        !           345:                       ~(ESO_PCI_S1C_IRQP_MASK | ESO_PCI_S1C_DMAP_MASK));
        !           346:
        !           347:        /* Enable the relevant DMA interrupts. */
        !           348:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_IRQCTL,
        !           349:                          ESO_IO_IRQCTL_A1IRQ | ESO_IO_IRQCTL_A2IRQ);
        !           350:
        !           351:        /* Set up A1's sample rate generator for new-style parameters. */
        !           352:        a2mode = eso_read_mixreg(sc, ESO_MIXREG_A2MODE);
        !           353:        a2mode |= ESO_MIXREG_A2MODE_NEWA1 | ESO_MIXREG_A2MODE_ASYNC;
        !           354:        eso_write_mixreg(sc, ESO_MIXREG_A2MODE, a2mode);
        !           355:
        !           356:        /* Set mixer regs to something reasonable, needs work. */
        !           357:        for (idx = 0; idx < ESO_NGAINDEVS; idx++) {
        !           358:                int v;
        !           359:
        !           360:                switch (idx) {
        !           361:                case ESO_MIC_PLAY_VOL:
        !           362:                case ESO_LINE_PLAY_VOL:
        !           363:                case ESO_CD_PLAY_VOL:
        !           364:                case ESO_MONO_PLAY_VOL:
        !           365:                case ESO_AUXB_PLAY_VOL:
        !           366:                case ESO_DAC_REC_VOL:
        !           367:                case ESO_LINE_REC_VOL:
        !           368:                case ESO_SYNTH_REC_VOL:
        !           369:                case ESO_CD_REC_VOL:
        !           370:                case ESO_MONO_REC_VOL:
        !           371:                case ESO_AUXB_REC_VOL:
        !           372:                case ESO_SPATIALIZER:
        !           373:                        v = 0;
        !           374:                        break;
        !           375:                case ESO_MASTER_VOL:
        !           376:                        v = ESO_GAIN_TO_6BIT(AUDIO_MAX_GAIN / 2);
        !           377:                        break;
        !           378:                default:
        !           379:                        v = ESO_GAIN_TO_4BIT(AUDIO_MAX_GAIN / 2);
        !           380:                        break;
        !           381:                }
        !           382:                sc->sc_gain[idx][ESO_LEFT] = sc->sc_gain[idx][ESO_RIGHT] = v;
        !           383:                eso_set_gain(sc, idx);
        !           384:        }
        !           385:        eso_set_recsrc(sc, ESO_MIXREG_ERS_MIC);
        !           386: }
        !           387:
        !           388: HIDE void
        !           389: eso_defer(self)
        !           390:        struct device *self;
        !           391: {
        !           392:        struct eso_softc *sc = (struct eso_softc *)self;
        !           393:        struct pci_attach_args *pa = &sc->sc_pa;
        !           394:        bus_addr_t addr, start;
        !           395:
        !           396:        printf("%s: ", sc->sc_dev.dv_xname);
        !           397:
        !           398:        /*
        !           399:         * This is outright ugly, but since we must not make assumptions
        !           400:         * on the underlying allocator's behaviour it's the most straight-
        !           401:         * forward way to implement it.  Note that we skip over the first
        !           402:         * 1K region, which is typically occupied by an attached ISA bus.
        !           403:         */
        !           404:        for (start = 0x0400; start < 0xffff; start += 0x0400) {
        !           405:                if (bus_space_alloc(sc->sc_iot,
        !           406:                    start + sc->sc_vcsize, start + 0x0400 - 1,
        !           407:                    sc->sc_vcsize, sc->sc_vcsize, 0, 0, &addr,
        !           408:                    &sc->sc_dmac_ioh) != 0)
        !           409:                        continue;
        !           410:
        !           411:                pci_conf_write(pa->pa_pc, pa->pa_tag, ESO_PCI_DDMAC,
        !           412:                    addr | ESO_PCI_DDMAC_DE);
        !           413:                sc->sc_dmac_iot = sc->sc_iot;
        !           414:                sc->sc_dmac_configured = 1;
        !           415:                printf("mapping Audio 1 DMA using I/O space at 0x%lx\n",
        !           416:                    (unsigned long)addr);
        !           417:
        !           418:                return;
        !           419:        }
        !           420:
        !           421:        printf("can't map Audio 1 DMA into I/O space\n");
        !           422: }
        !           423:
        !           424: HIDE void
        !           425: eso_write_cmd(sc, cmd)
        !           426:        struct eso_softc *sc;
        !           427:        uint8_t cmd;
        !           428: {
        !           429:        int i;
        !           430:
        !           431:        /* Poll for busy indicator to become clear. */
        !           432:        for (i = 0; i < ESO_WDR_TIMEOUT; i++) {
        !           433:                if ((bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_RSR)
        !           434:                    & ESO_SB_RSR_BUSY) == 0) {
        !           435:                        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh,
        !           436:                            ESO_SB_WDR, cmd);
        !           437:                        return;
        !           438:                } else {
        !           439:                        delay(10);
        !           440:                }
        !           441:        }
        !           442:
        !           443:        printf("%s: WDR timeout\n", sc->sc_dev.dv_xname);
        !           444:        return;
        !           445: }
        !           446:
        !           447: /* Write to a controller register */
        !           448: HIDE void
        !           449: eso_write_ctlreg(sc, reg, val)
        !           450:        struct eso_softc *sc;
        !           451:        uint8_t reg, val;
        !           452: {
        !           453:
        !           454:        /* DPRINTF(("ctlreg 0x%02x = 0x%02x\n", reg, val)); */
        !           455:
        !           456:        eso_write_cmd(sc, reg);
        !           457:        eso_write_cmd(sc, val);
        !           458: }
        !           459:
        !           460: /* Read out the Read Data Register */
        !           461: HIDE uint8_t
        !           462: eso_read_rdr(sc)
        !           463:        struct eso_softc *sc;
        !           464: {
        !           465:        int i;
        !           466:
        !           467:        for (i = 0; i < ESO_RDR_TIMEOUT; i++) {
        !           468:                if (bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh,
        !           469:                    ESO_SB_RBSR) & ESO_SB_RBSR_RDAV) {
        !           470:                        return (bus_space_read_1(sc->sc_sb_iot,
        !           471:                            sc->sc_sb_ioh, ESO_SB_RDR));
        !           472:                } else {
        !           473:                        delay(10);
        !           474:                }
        !           475:        }
        !           476:
        !           477:        printf("%s: RDR timeout\n", sc->sc_dev.dv_xname);
        !           478:        return (-1);
        !           479: }
        !           480:
        !           481:
        !           482: HIDE uint8_t
        !           483: eso_read_ctlreg(sc, reg)
        !           484:        struct eso_softc *sc;
        !           485:        uint8_t reg;
        !           486: {
        !           487:
        !           488:        eso_write_cmd(sc, ESO_CMD_RCR);
        !           489:        eso_write_cmd(sc, reg);
        !           490:        return (eso_read_rdr(sc));
        !           491: }
        !           492:
        !           493: HIDE void
        !           494: eso_write_mixreg(sc, reg, val)
        !           495:        struct eso_softc *sc;
        !           496:        uint8_t reg, val;
        !           497: {
        !           498:        int s;
        !           499:
        !           500:        /* DPRINTF(("mixreg 0x%02x = 0x%02x\n", reg, val)); */
        !           501:
        !           502:        s = splaudio();
        !           503:        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERADDR, reg);
        !           504:        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERDATA, val);
        !           505:        splx(s);
        !           506: }
        !           507:
        !           508: HIDE uint8_t
        !           509: eso_read_mixreg(sc, reg)
        !           510:        struct eso_softc *sc;
        !           511:        uint8_t reg;
        !           512: {
        !           513:        int s;
        !           514:        uint8_t val;
        !           515:
        !           516:        s = splaudio();
        !           517:        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERADDR, reg);
        !           518:        val = bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_MIXERDATA);
        !           519:        splx(s);
        !           520:
        !           521:        return (val);
        !           522: }
        !           523:
        !           524: HIDE int
        !           525: eso_intr(hdl)
        !           526:        void *hdl;
        !           527: {
        !           528:        struct eso_softc *sc = hdl;
        !           529:        uint8_t irqctl;
        !           530:
        !           531:        irqctl = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ESO_IO_IRQCTL);
        !           532:
        !           533:        /* If it wasn't ours, that's all she wrote. */
        !           534:        if ((irqctl & (ESO_IO_IRQCTL_A1IRQ | ESO_IO_IRQCTL_A2IRQ)) == 0)
        !           535:                return (0);
        !           536:
        !           537:        if (irqctl & ESO_IO_IRQCTL_A1IRQ) {
        !           538:                /* Clear interrupt. */
        !           539:                (void)bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh,
        !           540:                    ESO_SB_RBSR);
        !           541:
        !           542:                if (sc->sc_rintr)
        !           543:                        sc->sc_rintr(sc->sc_rarg);
        !           544:                else
        !           545:                        wakeup(&sc->sc_rintr);
        !           546:        }
        !           547:
        !           548:        if (irqctl & ESO_IO_IRQCTL_A2IRQ) {
        !           549:                /*
        !           550:                 * Clear the A2 IRQ latch: the cached value reflects the
        !           551:                 * current DAC settings with the IRQ latch bit not set.
        !           552:                 */
        !           553:                eso_write_mixreg(sc, ESO_MIXREG_A2C2, sc->sc_a2c2);
        !           554:
        !           555:                if (sc->sc_pintr)
        !           556:                        sc->sc_pintr(sc->sc_parg);
        !           557:                else
        !           558:                        wakeup(&sc->sc_pintr);
        !           559:        }
        !           560:
        !           561: #if 0
        !           562:        if ((irqctl & ESO_IO_IRQCTL_MPUIRQ) && sc->sc_mpudev != 0)
        !           563:                mpu_intr(sc->sc_mpudev);
        !           564: #endif
        !           565:
        !           566:        return (1);
        !           567: }
        !           568:
        !           569: /* Perform a software reset, including DMA FIFOs. */
        !           570: HIDE int
        !           571: eso_reset(sc)
        !           572:        struct eso_softc *sc;
        !           573: {
        !           574:        int i;
        !           575:
        !           576:        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_RESET,
        !           577:            ESO_SB_RESET_SW | ESO_SB_RESET_FIFO);
        !           578:        /* `Delay' suggested in the data sheet. */
        !           579:        (void)bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_STATUS);
        !           580:        bus_space_write_1(sc->sc_sb_iot, sc->sc_sb_ioh, ESO_SB_RESET, 0);
        !           581:
        !           582:        /* Wait for reset to take effect. */
        !           583:        for (i = 0; i < ESO_RESET_TIMEOUT; i++) {
        !           584:                /* Poll for data to become available. */
        !           585:                if ((bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh,
        !           586:                    ESO_SB_RBSR) & ESO_SB_RBSR_RDAV) != 0 &&
        !           587:                    bus_space_read_1(sc->sc_sb_iot, sc->sc_sb_ioh,
        !           588:                        ESO_SB_RDR) == ESO_SB_RDR_RESETMAGIC) {
        !           589:
        !           590:                        /* Activate Solo-1 extension commands. */
        !           591:                        eso_write_cmd(sc, ESO_CMD_EXTENB);
        !           592:                        /* Reset mixer registers. */
        !           593:                        eso_write_mixreg(sc, ESO_MIXREG_RESET,
        !           594:                            ESO_MIXREG_RESET_RESET);
        !           595:
        !           596:                        return (0);
        !           597:                } else {
        !           598:                        delay(1000);
        !           599:                }
        !           600:        }
        !           601:
        !           602:        printf("%s: reset timeout\n", sc->sc_dev.dv_xname);
        !           603:        return (-1);
        !           604: }
        !           605:
        !           606:
        !           607: /* ARGSUSED */
        !           608: HIDE int
        !           609: eso_open(hdl, flags)
        !           610:        void *hdl;
        !           611:        int flags;
        !           612: {
        !           613:        struct eso_softc *sc = hdl;
        !           614:
        !           615:        DPRINTF(("%s: open\n", sc->sc_dev.dv_xname));
        !           616:
        !           617:        sc->sc_pintr = NULL;
        !           618:        sc->sc_rintr = NULL;
        !           619:
        !           620:        return (0);
        !           621: }
        !           622:
        !           623: HIDE void
        !           624: eso_close(hdl)
        !           625:        void *hdl;
        !           626: {
        !           627:
        !           628:        DPRINTF(("%s: close\n", ((struct eso_softc *)hdl)->sc_dev.dv_xname));
        !           629: }
        !           630:
        !           631: HIDE int
        !           632: eso_query_encoding(hdl, fp)
        !           633:        void *hdl;
        !           634:        struct audio_encoding *fp;
        !           635: {
        !           636:
        !           637:        switch (fp->index) {
        !           638:        case 0:
        !           639:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
        !           640:                fp->encoding = AUDIO_ENCODING_ULINEAR;
        !           641:                fp->precision = 8;
        !           642:                fp->flags = 0;
        !           643:                break;
        !           644:        case 1:
        !           645:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
        !           646:                fp->encoding = AUDIO_ENCODING_SLINEAR;
        !           647:                fp->precision = 8;
        !           648:                fp->flags = 0;
        !           649:                break;
        !           650:        case 2:
        !           651:                fp->precision = 16;
        !           652:                if (fp->flags & AUOPEN_READ) {
        !           653:                        strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
        !           654:                        fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !           655:                        if (fp->flags & AUOPEN_WRITE)
        !           656:                                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           657:                        else
        !           658:                                fp->flags = 0;
        !           659:                } else {
        !           660:                        strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
        !           661:                        fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !           662:                        fp->flags = 0;
        !           663:                }
        !           664:                break;
        !           665:        case 3:
        !           666:                fp->precision = 16;
        !           667:                if (fp->flags & AUOPEN_READ) {
        !           668:                        strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
        !           669:                        fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !           670:                        if (fp->flags & AUOPEN_WRITE)
        !           671:                                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           672:                        else
        !           673:                                fp->flags = 0;
        !           674:                } else {
        !           675:                        strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
        !           676:                        fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !           677:                        fp->flags = 0;
        !           678:                }
        !           679:                break;
        !           680:        case 4:
        !           681:                fp->precision = 16;
        !           682:                if (fp->flags & AUOPEN_READ) {
        !           683:                        strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
        !           684:                        fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !           685:                } else {
        !           686:                        strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
        !           687:                        fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !           688:                }
        !           689:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           690:                break;
        !           691:        case 5:
        !           692:                fp->precision = 16;
        !           693:                if (fp->flags & AUOPEN_READ) {
        !           694:                        strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
        !           695:                        fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !           696:                } else {
        !           697:                        strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
        !           698:                        fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !           699:                }
        !           700:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           701:                break;
        !           702:        case 6:
        !           703:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
        !           704:                fp->encoding = AUDIO_ENCODING_ULAW;
        !           705:                fp->precision = 8;
        !           706:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           707:                break;
        !           708:        case 7:
        !           709:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
        !           710:                fp->encoding = AUDIO_ENCODING_ALAW;
        !           711:                fp->precision = 8;
        !           712:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           713:                break;
        !           714:        default:
        !           715:                return (EINVAL);
        !           716:        }
        !           717:
        !           718:        return (0);
        !           719: }
        !           720:
        !           721: HIDE int
        !           722: eso_set_params(hdl, setmode, usemode, play, rec)
        !           723:        void *hdl;
        !           724:        int setmode, usemode;
        !           725:        struct audio_params *play, *rec;
        !           726: {
        !           727:        struct eso_softc *sc = hdl;
        !           728:        struct audio_params *p;
        !           729:        int mode, r[2], rd[2], clk;
        !           730:        unsigned int srg, fltdiv;
        !           731:
        !           732:        for (mode = AUMODE_RECORD; mode != -1;
        !           733:             mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
        !           734:                if ((setmode & mode) == 0)
        !           735:                        continue;
        !           736:
        !           737:                p = (mode == AUMODE_PLAY) ? play : rec;
        !           738:
        !           739:                if (p->sample_rate < ESO_MINRATE ||
        !           740:                    p->sample_rate > ESO_MAXRATE ||
        !           741:                    (p->precision != 8 && p->precision != 16) ||
        !           742:                    (p->channels != 1 && p->channels != 2))
        !           743:                        return (EINVAL);
        !           744:
        !           745:                p->factor = 1;
        !           746:                p->sw_code = NULL;
        !           747:                switch (p->encoding) {
        !           748:                case AUDIO_ENCODING_SLINEAR_BE:
        !           749:                case AUDIO_ENCODING_ULINEAR_BE:
        !           750:                        if (mode == AUMODE_PLAY && p->precision == 16)
        !           751:                                p->sw_code = swap_bytes;
        !           752:                        break;
        !           753:                case AUDIO_ENCODING_SLINEAR_LE:
        !           754:                case AUDIO_ENCODING_ULINEAR_LE:
        !           755:                        if (mode == AUMODE_RECORD && p->precision == 16)
        !           756:                                p->sw_code = swap_bytes;
        !           757:                        break;
        !           758:                case AUDIO_ENCODING_ULAW:
        !           759:                        if (mode == AUMODE_PLAY) {
        !           760:                                p->factor = 2;
        !           761:                                p->sw_code = mulaw_to_ulinear16;
        !           762:                        } else {
        !           763:                                p->sw_code = ulinear8_to_mulaw;
        !           764:                        }
        !           765:                        break;
        !           766:                case AUDIO_ENCODING_ALAW:
        !           767:                        if (mode == AUMODE_PLAY) {
        !           768:                                p->factor = 2;
        !           769:                                p->sw_code = alaw_to_ulinear16;
        !           770:                        } else {
        !           771:                                p->sw_code = ulinear8_to_alaw;
        !           772:                        }
        !           773:                        break;
        !           774:                default:
        !           775:                        return (EINVAL);
        !           776:                }
        !           777:
        !           778:                /*
        !           779:                 * We'll compute both possible sample rate dividers and pick
        !           780:                 * the one with the least error.
        !           781:                 */
        !           782: #define ABS(x) ((x) < 0 ? -(x) : (x))
        !           783:                r[0] = ESO_CLK0 /
        !           784:                    (128 - (rd[0] = 128 - ESO_CLK0 / p->sample_rate));
        !           785:                r[1] = ESO_CLK1 /
        !           786:                    (128 - (rd[1] = 128 - ESO_CLK1 / p->sample_rate));
        !           787:
        !           788:                clk = ABS(p->sample_rate - r[0]) > ABS(p->sample_rate - r[1]);
        !           789:                srg = rd[clk] | (clk == 1 ? ESO_CLK1_SELECT : 0x00);
        !           790:
        !           791:                /* Roll-off frequency of 87%, as in the ES1888 driver. */
        !           792:                fltdiv = 256 - 200279L / p->sample_rate;
        !           793:
        !           794:                /* Update to reflect the possibly inexact rate. */
        !           795:                p->sample_rate = r[clk];
        !           796:
        !           797:                if (mode == AUMODE_RECORD) {
        !           798:                        /* Audio 1 */
        !           799:                        DPRINTF(("A1 srg 0x%02x fdiv 0x%02x\n", srg, fltdiv));
        !           800:                        eso_write_ctlreg(sc, ESO_CTLREG_SRG, srg);
        !           801:                        eso_write_ctlreg(sc, ESO_CTLREG_FLTDIV, fltdiv);
        !           802:                } else {
        !           803:                        /* Audio 2 */
        !           804:                        DPRINTF(("A2 srg 0x%02x fdiv 0x%02x\n", srg, fltdiv));
        !           805:                        eso_write_mixreg(sc, ESO_MIXREG_A2SRG, srg);
        !           806:                        eso_write_mixreg(sc, ESO_MIXREG_A2FLTDIV, fltdiv);
        !           807:                }
        !           808: #undef ABS
        !           809:
        !           810:        }
        !           811:
        !           812:        return (0);
        !           813: }
        !           814:
        !           815: HIDE int
        !           816: eso_round_blocksize(hdl, blk)
        !           817:        void *hdl;
        !           818:        int blk;
        !           819: {
        !           820:
        !           821:        return ((blk + 31) & -32); /* keep good alignment; at least 16 req'd */
        !           822: }
        !           823:
        !           824: HIDE int
        !           825: eso_halt_output(hdl)
        !           826:        void *hdl;
        !           827: {
        !           828:        struct eso_softc *sc = hdl;
        !           829:        int error, s;
        !           830:
        !           831:        DPRINTF(("%s: halt_output\n", sc->sc_dev.dv_xname));
        !           832:
        !           833:        /*
        !           834:         * Disable auto-initialize DMA, allowing the FIFO to drain and then
        !           835:         * stop.  The interrupt callback pointer is cleared at this
        !           836:         * point so that an outstanding FIFO interrupt for the remaining data
        !           837:         * will be acknowledged without further processing.
        !           838:         *
        !           839:         * This does not immediately `abort' an operation in progress (c.f.
        !           840:         * audio(9)) but is the method to leave the FIFO behind in a clean
        !           841:         * state with the least hair.  (Besides, that item needs to be
        !           842:         * rephrased for trigger_*()-based DMA environments.)
        !           843:         */
        !           844:        s = splaudio();
        !           845:        eso_write_mixreg(sc, ESO_MIXREG_A2C1,
        !           846:            ESO_MIXREG_A2C1_FIFOENB | ESO_MIXREG_A2C1_DMAENB);
        !           847:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM,
        !           848:            ESO_IO_A2DMAM_DMAENB);
        !           849:
        !           850:        sc->sc_pintr = NULL;
        !           851:        error = tsleep(&sc->sc_pintr, PCATCH | PWAIT, "esoho", hz);
        !           852:        splx(s);
        !           853:
        !           854:        /* Shut down DMA completely. */
        !           855:        eso_write_mixreg(sc, ESO_MIXREG_A2C1, 0);
        !           856:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM, 0);
        !           857:
        !           858:        return (error == EWOULDBLOCK ? 0 : error);
        !           859: }
        !           860:
        !           861: HIDE int
        !           862: eso_halt_input(hdl)
        !           863:        void *hdl;
        !           864: {
        !           865:        struct eso_softc *sc = hdl;
        !           866:        int error, s;
        !           867:
        !           868:        DPRINTF(("%s: halt_input\n", sc->sc_dev.dv_xname));
        !           869:
        !           870:        /* Just like eso_halt_output(), but for Audio 1. */
        !           871:        s = splaudio();
        !           872:        eso_write_ctlreg(sc, ESO_CTLREG_A1C2,
        !           873:            ESO_CTLREG_A1C2_READ | ESO_CTLREG_A1C2_ADC |
        !           874:            ESO_CTLREG_A1C2_DMAENB);
        !           875:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_MODE,
        !           876:            DMA37MD_WRITE | DMA37MD_DEMAND);
        !           877:
        !           878:        sc->sc_rintr = NULL;
        !           879:        error = tsleep(&sc->sc_rintr, PCATCH | PWAIT, "esohi", hz);
        !           880:        splx(s);
        !           881:
        !           882:        /* Shut down DMA completely. */
        !           883:        eso_write_ctlreg(sc, ESO_CTLREG_A1C2,
        !           884:            ESO_CTLREG_A1C2_READ | ESO_CTLREG_A1C2_ADC);
        !           885:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_MASK,
        !           886:            ESO_DMAC_MASK_MASK);
        !           887:
        !           888:        return (error == EWOULDBLOCK ? 0 : error);
        !           889: }
        !           890:
        !           891: /* ARGSUSED */
        !           892: HIDE int
        !           893: eso_getdev(hdl, retp)
        !           894:        void *hdl;
        !           895:        struct audio_device *retp;
        !           896: {
        !           897:        struct eso_softc *sc = hdl;
        !           898:
        !           899:        strlcpy(retp->name, "ESS Solo-1", sizeof retp->name);
        !           900:        snprintf(retp->version, sizeof retp->version, "0x%02x",
        !           901:            sc->sc_revision);
        !           902:        if (sc->sc_revision <=
        !           903:            sizeof (eso_rev2model) / sizeof (eso_rev2model[0]))
        !           904:                strlcpy(retp->config, eso_rev2model[sc->sc_revision],
        !           905:                    sizeof retp->config);
        !           906:        else
        !           907:                strlcpy(retp->config, "unknown", sizeof retp->config);
        !           908:
        !           909:        return (0);
        !           910: }
        !           911:
        !           912: HIDE int
        !           913: eso_set_port(hdl, cp)
        !           914:        void *hdl;
        !           915:        mixer_ctrl_t *cp;
        !           916: {
        !           917:        struct eso_softc *sc = hdl;
        !           918:        unsigned int lgain, rgain;
        !           919:        uint8_t tmp;
        !           920:
        !           921:        switch (cp->dev) {
        !           922:        case ESO_DAC_PLAY_VOL:
        !           923:        case ESO_MIC_PLAY_VOL:
        !           924:        case ESO_LINE_PLAY_VOL:
        !           925:        case ESO_SYNTH_PLAY_VOL:
        !           926:        case ESO_CD_PLAY_VOL:
        !           927:        case ESO_AUXB_PLAY_VOL:
        !           928:        case ESO_RECORD_VOL:
        !           929:        case ESO_DAC_REC_VOL:
        !           930:        case ESO_MIC_REC_VOL:
        !           931:        case ESO_LINE_REC_VOL:
        !           932:        case ESO_SYNTH_REC_VOL:
        !           933:        case ESO_CD_REC_VOL:
        !           934:        case ESO_AUXB_REC_VOL:
        !           935:                if (cp->type != AUDIO_MIXER_VALUE)
        !           936:                        return (EINVAL);
        !           937:
        !           938:                /*
        !           939:                 * Stereo-capable mixer ports: if we get a single-channel
        !           940:                 * gain value passed in, then we duplicate it to both left
        !           941:                 * and right channels.
        !           942:                 */
        !           943:                switch (cp->un.value.num_channels) {
        !           944:                case 1:
        !           945:                        lgain = rgain = ESO_GAIN_TO_4BIT(
        !           946:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !           947:                        break;
        !           948:                case 2:
        !           949:                        lgain = ESO_GAIN_TO_4BIT(
        !           950:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
        !           951:                        rgain = ESO_GAIN_TO_4BIT(
        !           952:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
        !           953:                        break;
        !           954:                default:
        !           955:                        return (EINVAL);
        !           956:                }
        !           957:
        !           958:                sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
        !           959:                sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
        !           960:                eso_set_gain(sc, cp->dev);
        !           961:                break;
        !           962:
        !           963:        case ESO_MASTER_VOL:
        !           964:                if (cp->type != AUDIO_MIXER_VALUE)
        !           965:                        return (EINVAL);
        !           966:
        !           967:                /* Like above, but a precision of 6 bits. */
        !           968:                switch (cp->un.value.num_channels) {
        !           969:                case 1:
        !           970:                        lgain = rgain = ESO_GAIN_TO_6BIT(
        !           971:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !           972:                        break;
        !           973:                case 2:
        !           974:                        lgain = ESO_GAIN_TO_6BIT(
        !           975:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
        !           976:                        rgain = ESO_GAIN_TO_6BIT(
        !           977:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
        !           978:                        break;
        !           979:                default:
        !           980:                        return (EINVAL);
        !           981:                }
        !           982:
        !           983:                sc->sc_gain[cp->dev][ESO_LEFT] = lgain;
        !           984:                sc->sc_gain[cp->dev][ESO_RIGHT] = rgain;
        !           985:                eso_set_gain(sc, cp->dev);
        !           986:                break;
        !           987:
        !           988:        case ESO_SPATIALIZER:
        !           989:                if (cp->type != AUDIO_MIXER_VALUE ||
        !           990:                    cp->un.value.num_channels != 1)
        !           991:                        return (EINVAL);
        !           992:
        !           993:                sc->sc_gain[cp->dev][ESO_LEFT] =
        !           994:                    sc->sc_gain[cp->dev][ESO_RIGHT] =
        !           995:                    ESO_GAIN_TO_6BIT(
        !           996:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !           997:                eso_set_gain(sc, cp->dev);
        !           998:                break;
        !           999:
        !          1000:        case ESO_MONO_PLAY_VOL:
        !          1001:        case ESO_MONO_REC_VOL:
        !          1002:                if (cp->type != AUDIO_MIXER_VALUE ||
        !          1003:                    cp->un.value.num_channels != 1)
        !          1004:                        return (EINVAL);
        !          1005:
        !          1006:                sc->sc_gain[cp->dev][ESO_LEFT] =
        !          1007:                    sc->sc_gain[cp->dev][ESO_RIGHT] =
        !          1008:                    ESO_GAIN_TO_4BIT(
        !          1009:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1010:                eso_set_gain(sc, cp->dev);
        !          1011:                break;
        !          1012:
        !          1013:        case ESO_PCSPEAKER_VOL:
        !          1014:                if (cp->type != AUDIO_MIXER_VALUE ||
        !          1015:                    cp->un.value.num_channels != 1)
        !          1016:                        return (EINVAL);
        !          1017:
        !          1018:                sc->sc_gain[cp->dev][ESO_LEFT] =
        !          1019:                    sc->sc_gain[cp->dev][ESO_RIGHT] =
        !          1020:                    ESO_GAIN_TO_3BIT(
        !          1021:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1022:                eso_set_gain(sc, cp->dev);
        !          1023:                break;
        !          1024:
        !          1025:        case ESO_SPATIALIZER_ENABLE:
        !          1026:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1027:                        return (EINVAL);
        !          1028:
        !          1029:                sc->sc_spatializer = (cp->un.ord != 0);
        !          1030:
        !          1031:                tmp = eso_read_mixreg(sc, ESO_MIXREG_SPAT);
        !          1032:                if (sc->sc_spatializer)
        !          1033:                        tmp |= ESO_MIXREG_SPAT_ENB;
        !          1034:                else
        !          1035:                        tmp &= ~ESO_MIXREG_SPAT_ENB;
        !          1036:                eso_write_mixreg(sc, ESO_MIXREG_SPAT,
        !          1037:                    tmp | ESO_MIXREG_SPAT_RSTREL);
        !          1038:                break;
        !          1039:
        !          1040:        case ESO_MONOOUT_SOURCE:
        !          1041:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1042:                        return (EINVAL);
        !          1043:
        !          1044:                sc->sc_monooutsrc = cp->un.ord;
        !          1045:
        !          1046:                tmp = eso_read_mixreg(sc, ESO_MIXREG_MPM);
        !          1047:                tmp &= ~ESO_MIXREG_MPM_MOMASK;
        !          1048:                tmp |= sc->sc_monooutsrc;
        !          1049:                eso_write_mixreg(sc, ESO_MIXREG_MPM, tmp);
        !          1050:                break;
        !          1051:
        !          1052:        case ESO_RECORD_MONITOR:
        !          1053:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1054:                        return (EINVAL);
        !          1055:
        !          1056:                sc->sc_recmon = (cp->un.ord != 0);
        !          1057:
        !          1058:                tmp = eso_read_ctlreg(sc, ESO_CTLREG_ACTL);
        !          1059:                if (sc->sc_recmon)
        !          1060:                        tmp |= ESO_CTLREG_ACTL_RECMON;
        !          1061:                else
        !          1062:                        tmp &= ~ESO_CTLREG_ACTL_RECMON;
        !          1063:                eso_write_ctlreg(sc, ESO_CTLREG_ACTL, tmp);
        !          1064:                break;
        !          1065:
        !          1066:        case ESO_RECORD_SOURCE:
        !          1067:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1068:                        return (EINVAL);
        !          1069:
        !          1070:                return (eso_set_recsrc(sc, cp->un.ord));
        !          1071:
        !          1072:        case ESO_MIC_PREAMP:
        !          1073:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1074:                        return (EINVAL);
        !          1075:
        !          1076:                sc->sc_preamp = (cp->un.ord != 0);
        !          1077:
        !          1078:                tmp = eso_read_mixreg(sc, ESO_MIXREG_MPM);
        !          1079:                tmp &= ~ESO_MIXREG_MPM_RESV0;
        !          1080:                if (sc->sc_preamp)
        !          1081:                        tmp |= ESO_MIXREG_MPM_PREAMP;
        !          1082:                else
        !          1083:                        tmp &= ~ESO_MIXREG_MPM_PREAMP;
        !          1084:                eso_write_mixreg(sc, ESO_MIXREG_MPM, tmp);
        !          1085:                break;
        !          1086:
        !          1087:        default:
        !          1088:                return (EINVAL);
        !          1089:        }
        !          1090:
        !          1091:        return (0);
        !          1092: }
        !          1093:
        !          1094: HIDE int
        !          1095: eso_get_port(hdl, cp)
        !          1096:        void *hdl;
        !          1097:        mixer_ctrl_t *cp;
        !          1098: {
        !          1099:        struct eso_softc *sc = hdl;
        !          1100:
        !          1101:        switch (cp->dev) {
        !          1102:        case ESO_DAC_PLAY_VOL:
        !          1103:        case ESO_MIC_PLAY_VOL:
        !          1104:        case ESO_LINE_PLAY_VOL:
        !          1105:        case ESO_SYNTH_PLAY_VOL:
        !          1106:        case ESO_CD_PLAY_VOL:
        !          1107:        case ESO_AUXB_PLAY_VOL:
        !          1108:        case ESO_MASTER_VOL:
        !          1109:        case ESO_RECORD_VOL:
        !          1110:        case ESO_DAC_REC_VOL:
        !          1111:        case ESO_MIC_REC_VOL:
        !          1112:        case ESO_LINE_REC_VOL:
        !          1113:        case ESO_SYNTH_REC_VOL:
        !          1114:        case ESO_CD_REC_VOL:
        !          1115:        case ESO_AUXB_REC_VOL:
        !          1116:                /*
        !          1117:                 * Stereo-capable ports: if a single-channel query is made,
        !          1118:                 * just return the left channel's value (since single-channel
        !          1119:                 * settings themselves are applied to both channels).
        !          1120:                 */
        !          1121:                switch (cp->un.value.num_channels) {
        !          1122:                case 1:
        !          1123:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1124:                            sc->sc_gain[cp->dev][ESO_LEFT];
        !          1125:                        break;
        !          1126:                case 2:
        !          1127:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1128:                            sc->sc_gain[cp->dev][ESO_LEFT];
        !          1129:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1130:                            sc->sc_gain[cp->dev][ESO_RIGHT];
        !          1131:                        break;
        !          1132:                default:
        !          1133:                        return (EINVAL);
        !          1134:                }
        !          1135:                break;
        !          1136:
        !          1137:        case ESO_MONO_PLAY_VOL:
        !          1138:        case ESO_PCSPEAKER_VOL:
        !          1139:        case ESO_MONO_REC_VOL:
        !          1140:        case ESO_SPATIALIZER:
        !          1141:                if (cp->un.value.num_channels != 1)
        !          1142:                        return (EINVAL);
        !          1143:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1144:                    sc->sc_gain[cp->dev][ESO_LEFT];
        !          1145:                break;
        !          1146:
        !          1147:        case ESO_RECORD_MONITOR:
        !          1148:                cp->un.ord = sc->sc_recmon;
        !          1149:                break;
        !          1150:
        !          1151:        case ESO_RECORD_SOURCE:
        !          1152:                cp->un.ord = sc->sc_recsrc;
        !          1153:                break;
        !          1154:
        !          1155:        case ESO_MONOOUT_SOURCE:
        !          1156:                cp->un.ord = sc->sc_monooutsrc;
        !          1157:                break;
        !          1158:
        !          1159:        case ESO_SPATIALIZER_ENABLE:
        !          1160:                cp->un.ord = sc->sc_spatializer;
        !          1161:                break;
        !          1162:
        !          1163:        case ESO_MIC_PREAMP:
        !          1164:                cp->un.ord = sc->sc_preamp;
        !          1165:                break;
        !          1166:
        !          1167:        default:
        !          1168:                return (EINVAL);
        !          1169:        }
        !          1170:
        !          1171:
        !          1172:        return (0);
        !          1173:
        !          1174: }
        !          1175:
        !          1176: HIDE int
        !          1177: eso_query_devinfo(hdl, dip)
        !          1178:        void *hdl;
        !          1179:        mixer_devinfo_t *dip;
        !          1180: {
        !          1181:
        !          1182:        switch (dip->index) {
        !          1183:        case ESO_DAC_PLAY_VOL:
        !          1184:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1185:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1186:                strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          1187:                dip->type = AUDIO_MIXER_VALUE;
        !          1188:                dip->un.v.num_channels = 2;
        !          1189:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1190:                    sizeof dip->un.v.units.name);
        !          1191:                break;
        !          1192:        case ESO_MIC_PLAY_VOL:
        !          1193:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1194:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1195:                strlcpy(dip->label.name, AudioNmicrophone,
        !          1196:                    sizeof dip->label.name);
        !          1197:                dip->type = AUDIO_MIXER_VALUE;
        !          1198:                dip->un.v.num_channels = 2;
        !          1199:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1200:                    sizeof dip->un.v.units.name);
        !          1201:                break;
        !          1202:        case ESO_LINE_PLAY_VOL:
        !          1203:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1204:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1205:                strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
        !          1206:                dip->type = AUDIO_MIXER_VALUE;
        !          1207:                dip->un.v.num_channels = 2;
        !          1208:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1209:                    sizeof dip->un.v.units.name);
        !          1210:                break;
        !          1211:        case ESO_SYNTH_PLAY_VOL:
        !          1212:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1213:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1214:                strlcpy(dip->label.name, AudioNfmsynth,
        !          1215:                    sizeof dip->label.name);
        !          1216:                dip->type = AUDIO_MIXER_VALUE;
        !          1217:                dip->un.v.num_channels = 2;
        !          1218:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1219:                    sizeof dip->un.v.units.name);
        !          1220:                break;
        !          1221:        case ESO_MONO_PLAY_VOL:
        !          1222:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1223:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1224:                strlcpy(dip->label.name, "mono_in", sizeof dip->label.name);
        !          1225:                dip->type = AUDIO_MIXER_VALUE;
        !          1226:                dip->un.v.num_channels = 1;
        !          1227:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1228:                    sizeof dip->un.v.units.name);
        !          1229:                break;
        !          1230:        case ESO_CD_PLAY_VOL:
        !          1231:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1232:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1233:                strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          1234:                dip->type = AUDIO_MIXER_VALUE;
        !          1235:                dip->un.v.num_channels = 2;
        !          1236:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1237:                    sizeof dip->un.v.units.name);
        !          1238:                break;
        !          1239:        case ESO_AUXB_PLAY_VOL:
        !          1240:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1241:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1242:                strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
        !          1243:                dip->type = AUDIO_MIXER_VALUE;
        !          1244:                dip->un.v.num_channels = 2;
        !          1245:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1246:                    sizeof dip->un.v.units.name);
        !          1247:                break;
        !          1248:
        !          1249:        case ESO_MIC_PREAMP:
        !          1250:                dip->mixer_class = ESO_MICROPHONE_CLASS;
        !          1251:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1252:                strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
        !          1253:                dip->type = AUDIO_MIXER_ENUM;
        !          1254:                dip->un.e.num_mem = 2;
        !          1255:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1256:                    sizeof dip->un.e.member[0].label.name);
        !          1257:                dip->un.e.member[0].ord = 0;
        !          1258:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1259:                    sizeof dip->un.e.member[1].label.name);
        !          1260:                dip->un.e.member[1].ord = 1;
        !          1261:                break;
        !          1262:        case ESO_MICROPHONE_CLASS:
        !          1263:                dip->mixer_class = ESO_MICROPHONE_CLASS;
        !          1264:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1265:                strlcpy(dip->label.name, AudioNmicrophone,
        !          1266:                    sizeof dip->label.name);
        !          1267:                dip->type = AUDIO_MIXER_CLASS;
        !          1268:                break;
        !          1269:
        !          1270:        case ESO_INPUT_CLASS:
        !          1271:                dip->mixer_class = ESO_INPUT_CLASS;
        !          1272:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1273:                strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
        !          1274:                dip->type = AUDIO_MIXER_CLASS;
        !          1275:                break;
        !          1276:
        !          1277:        case ESO_MASTER_VOL:
        !          1278:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1279:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1280:                strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
        !          1281:                dip->type = AUDIO_MIXER_VALUE;
        !          1282:                dip->un.v.num_channels = 2;
        !          1283:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1284:                    sizeof dip->un.v.units.name);
        !          1285:                break;
        !          1286:        case ESO_PCSPEAKER_VOL:
        !          1287:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1288:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1289:                strlcpy(dip->label.name, "pc_speaker", sizeof dip->label.name);
        !          1290:                dip->type = AUDIO_MIXER_VALUE;
        !          1291:                dip->un.v.num_channels = 1;
        !          1292:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1293:                    sizeof dip->un.v.units.name);
        !          1294:                break;
        !          1295:        case ESO_MONOOUT_SOURCE:
        !          1296:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1297:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1298:                strlcpy(dip->label.name, "mono_out", sizeof dip->label.name);
        !          1299:                dip->type = AUDIO_MIXER_ENUM;
        !          1300:                dip->un.e.num_mem = 3;
        !          1301:                strlcpy(dip->un.e.member[0].label.name, AudioNmute,
        !          1302:                    sizeof dip->un.e.member[0].label.name);
        !          1303:                dip->un.e.member[0].ord = ESO_MIXREG_MPM_MOMUTE;
        !          1304:                strlcpy(dip->un.e.member[1].label.name, AudioNdac,
        !          1305:                    sizeof dip->un.e.member[1].label.name);
        !          1306:                dip->un.e.member[1].ord = ESO_MIXREG_MPM_MOA2R;
        !          1307:                strlcpy(dip->un.e.member[2].label.name, AudioNmixerout,
        !          1308:                    sizeof dip->un.e.member[2].label.name);
        !          1309:                dip->un.e.member[2].ord = ESO_MIXREG_MPM_MOREC;
        !          1310:                break;
        !          1311:        case ESO_SPATIALIZER:
        !          1312:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1313:                dip->prev = AUDIO_MIXER_LAST;
        !          1314:                dip->next = ESO_SPATIALIZER_ENABLE;
        !          1315:                strlcpy(dip->label.name, AudioNspatial,
        !          1316:                    sizeof dip->label.name);
        !          1317:                dip->type = AUDIO_MIXER_VALUE;
        !          1318:                dip->un.v.num_channels = 1;
        !          1319:                strlcpy(dip->un.v.units.name, "level",
        !          1320:                    sizeof dip->un.v.units.name);
        !          1321:                break;
        !          1322:        case ESO_SPATIALIZER_ENABLE:
        !          1323:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1324:                dip->prev = ESO_SPATIALIZER;
        !          1325:                dip->next = AUDIO_MIXER_LAST;
        !          1326:                strlcpy(dip->label.name, "enable", sizeof dip->label.name);
        !          1327:                dip->type = AUDIO_MIXER_ENUM;
        !          1328:                dip->un.e.num_mem = 2;
        !          1329:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1330:                    sizeof dip->un.e.member[0].label.name);
        !          1331:                dip->un.e.member[0].ord = 0;
        !          1332:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1333:                    sizeof dip->un.e.member[1].label.name);
        !          1334:                dip->un.e.member[1].ord = 1;
        !          1335:                break;
        !          1336:
        !          1337:        case ESO_OUTPUT_CLASS:
        !          1338:                dip->mixer_class = ESO_OUTPUT_CLASS;
        !          1339:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1340:                strlcpy(dip->label.name, AudioCoutputs,
        !          1341:                    sizeof dip->label.name);
        !          1342:                dip->type = AUDIO_MIXER_CLASS;
        !          1343:                break;
        !          1344:
        !          1345:        case ESO_RECORD_MONITOR:
        !          1346:                dip->mixer_class = ESO_MONITOR_CLASS;
        !          1347:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1348:                strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
        !          1349:                dip->type = AUDIO_MIXER_ENUM;
        !          1350:                dip->un.e.num_mem = 2;
        !          1351:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1352:                    sizeof dip->un.e.member[0].label.name);
        !          1353:                dip->un.e.member[0].ord = 0;
        !          1354:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1355:                    sizeof dip->un.e.member[1].label.name);
        !          1356:                dip->un.e.member[1].ord = 1;
        !          1357:                break;
        !          1358:        case ESO_MONITOR_CLASS:
        !          1359:                dip->mixer_class = ESO_MONITOR_CLASS;
        !          1360:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1361:                strlcpy(dip->label.name, AudioCmonitor,
        !          1362:                    sizeof dip->label.name);
        !          1363:                dip->type = AUDIO_MIXER_CLASS;
        !          1364:                break;
        !          1365:
        !          1366:        case ESO_RECORD_VOL:
        !          1367:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1368:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1369:                strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
        !          1370:                dip->type = AUDIO_MIXER_VALUE;
        !          1371:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1372:                    sizeof dip->un.v.units.name);
        !          1373:                break;
        !          1374:        case ESO_RECORD_SOURCE:
        !          1375:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1376:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1377:                strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
        !          1378:                dip->type = AUDIO_MIXER_ENUM;
        !          1379:                dip->un.e.num_mem = 4;
        !          1380:                strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
        !          1381:                    sizeof dip->un.e.member[0].label.name);
        !          1382:                dip->un.e.member[0].ord = ESO_MIXREG_ERS_MIC;
        !          1383:                strlcpy(dip->un.e.member[1].label.name, AudioNline,
        !          1384:                    sizeof dip->un.e.member[1].label.name);
        !          1385:                dip->un.e.member[1].ord = ESO_MIXREG_ERS_LINE;
        !          1386:                strlcpy(dip->un.e.member[2].label.name, AudioNcd,
        !          1387:                    sizeof dip->un.e.member[2].label.name);
        !          1388:                dip->un.e.member[2].ord = ESO_MIXREG_ERS_CD;
        !          1389:                strlcpy(dip->un.e.member[3].label.name, AudioNmixerout,
        !          1390:                    sizeof dip->un.e.member[3].label.name);
        !          1391:                dip->un.e.member[3].ord = ESO_MIXREG_ERS_MIXER;
        !          1392:                break;
        !          1393:        case ESO_DAC_REC_VOL:
        !          1394:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1395:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1396:                strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          1397:                dip->type = AUDIO_MIXER_VALUE;
        !          1398:                dip->un.v.num_channels = 2;
        !          1399:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1400:                    sizeof dip->un.v.units.name);
        !          1401:                break;
        !          1402:        case ESO_MIC_REC_VOL:
        !          1403:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1404:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1405:                strlcpy(dip->label.name, AudioNmicrophone,
        !          1406:                    sizeof dip->label.name);
        !          1407:                dip->type = AUDIO_MIXER_VALUE;
        !          1408:                dip->un.v.num_channels = 2;
        !          1409:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1410:                    sizeof dip->un.v.units.name);
        !          1411:                break;
        !          1412:        case ESO_LINE_REC_VOL:
        !          1413:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1414:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1415:                strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
        !          1416:                dip->type = AUDIO_MIXER_VALUE;
        !          1417:                dip->un.v.num_channels = 2;
        !          1418:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1419:                    sizeof dip->un.v.units.name);
        !          1420:                break;
        !          1421:        case ESO_SYNTH_REC_VOL:
        !          1422:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1423:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1424:                strlcpy(dip->label.name, AudioNfmsynth,
        !          1425:                    sizeof dip->label.name);
        !          1426:                dip->type = AUDIO_MIXER_VALUE;
        !          1427:                dip->un.v.num_channels = 2;
        !          1428:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1429:                    sizeof dip->un.v.units.name);
        !          1430:                break;
        !          1431:        case ESO_MONO_REC_VOL:
        !          1432:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1433:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1434:                strlcpy(dip->label.name, "mono_in", sizeof dip->label.name);
        !          1435:                dip->type = AUDIO_MIXER_VALUE;
        !          1436:                dip->un.v.num_channels = 1; /* No lies */
        !          1437:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1438:                    sizeof dip->un.v.units.name);
        !          1439:                break;
        !          1440:        case ESO_CD_REC_VOL:
        !          1441:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1442:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1443:                strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          1444:                dip->type = AUDIO_MIXER_VALUE;
        !          1445:                dip->un.v.num_channels = 2;
        !          1446:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1447:                    sizeof dip->un.v.units.name);
        !          1448:                break;
        !          1449:        case ESO_AUXB_REC_VOL:
        !          1450:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1451:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1452:                strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
        !          1453:                dip->type = AUDIO_MIXER_VALUE;
        !          1454:                dip->un.v.num_channels = 2;
        !          1455:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1456:                    sizeof dip->un.v.units.name);
        !          1457:                break;
        !          1458:        case ESO_RECORD_CLASS:
        !          1459:                dip->mixer_class = ESO_RECORD_CLASS;
        !          1460:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1461:                strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
        !          1462:                dip->type = AUDIO_MIXER_CLASS;
        !          1463:                break;
        !          1464:
        !          1465:        default:
        !          1466:                return (ENXIO);
        !          1467:        }
        !          1468:
        !          1469:        return (0);
        !          1470: }
        !          1471:
        !          1472: HIDE int
        !          1473: eso_allocmem(sc, size, align, boundary, flags, ed)
        !          1474:        struct eso_softc *sc;
        !          1475:        size_t size;
        !          1476:        size_t align;
        !          1477:        size_t boundary;
        !          1478:        int flags;
        !          1479:        struct eso_dma *ed;
        !          1480: {
        !          1481:        int error, wait;
        !          1482:
        !          1483:        wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
        !          1484:        ed->ed_size = size;
        !          1485:
        !          1486:        error = bus_dmamem_alloc(sc->sc_dmat, ed->ed_size, align, boundary,
        !          1487:            ed->ed_segs, sizeof (ed->ed_segs) / sizeof (ed->ed_segs[0]),
        !          1488:            &ed->ed_nsegs, wait);
        !          1489:        if (error)
        !          1490:                goto out;
        !          1491:
        !          1492:        error = bus_dmamem_map(sc->sc_dmat, ed->ed_segs, ed->ed_nsegs,
        !          1493:            ed->ed_size, &ed->ed_addr, wait | BUS_DMA_COHERENT);
        !          1494:        if (error)
        !          1495:                goto free;
        !          1496:
        !          1497:        error = bus_dmamap_create(sc->sc_dmat, ed->ed_size, 1, ed->ed_size, 0,
        !          1498:            wait, &ed->ed_map);
        !          1499:        if (error)
        !          1500:                goto unmap;
        !          1501:
        !          1502:        error = bus_dmamap_load(sc->sc_dmat, ed->ed_map, ed->ed_addr,
        !          1503:            ed->ed_size, NULL, wait);
        !          1504:        if (error)
        !          1505:                goto destroy;
        !          1506:
        !          1507:        return (0);
        !          1508:
        !          1509:  destroy:
        !          1510:        bus_dmamap_destroy(sc->sc_dmat, ed->ed_map);
        !          1511:  unmap:
        !          1512:        bus_dmamem_unmap(sc->sc_dmat, ed->ed_addr, ed->ed_size);
        !          1513:  free:
        !          1514:        bus_dmamem_free(sc->sc_dmat, ed->ed_segs, ed->ed_nsegs);
        !          1515:  out:
        !          1516:        return (error);
        !          1517: }
        !          1518:
        !          1519: HIDE void
        !          1520: eso_freemem(sc, ed)
        !          1521:        struct eso_softc *sc;
        !          1522:        struct eso_dma *ed;
        !          1523: {
        !          1524:
        !          1525:        bus_dmamap_unload(sc->sc_dmat, ed->ed_map);
        !          1526:        bus_dmamap_destroy(sc->sc_dmat, ed->ed_map);
        !          1527:        bus_dmamem_unmap(sc->sc_dmat, ed->ed_addr, ed->ed_size);
        !          1528:        bus_dmamem_free(sc->sc_dmat, ed->ed_segs, ed->ed_nsegs);
        !          1529: }
        !          1530:
        !          1531: HIDE void *
        !          1532: eso_allocm(hdl, direction, size, type, flags)
        !          1533:        void *hdl;
        !          1534:        int direction;
        !          1535:        size_t size;
        !          1536:        int type, flags;
        !          1537: {
        !          1538:        struct eso_softc *sc = hdl;
        !          1539:        struct eso_dma *ed;
        !          1540:        size_t boundary;
        !          1541:        int error;
        !          1542:
        !          1543:        if ((ed = malloc(size, type, flags)) == NULL)
        !          1544:                return (NULL);
        !          1545:
        !          1546:        /*
        !          1547:         * Apparently the Audio 1 DMA controller's current address
        !          1548:         * register can't roll over a 64K address boundary, so we have to
        !          1549:         * take care of that ourselves.  The second channel DMA controller
        !          1550:         * doesn't have that restriction, however.
        !          1551:         */
        !          1552:        if (direction == AUMODE_RECORD)
        !          1553:                boundary = 0x10000;
        !          1554:        else
        !          1555:                boundary = 0;
        !          1556:
        !          1557:
        !          1558:        error = eso_allocmem(sc, size, 32, boundary, flags, ed);
        !          1559:        if (error) {
        !          1560:                free(ed, type);
        !          1561:                return (NULL);
        !          1562:        }
        !          1563:        ed->ed_next = sc->sc_dmas;
        !          1564:        sc->sc_dmas = ed;
        !          1565:
        !          1566:        return (KVADDR(ed));
        !          1567: }
        !          1568:
        !          1569: HIDE void
        !          1570: eso_freem(hdl, addr, type)
        !          1571:        void *hdl;
        !          1572:        void *addr;
        !          1573:        int type;
        !          1574: {
        !          1575:        struct eso_softc *sc = hdl;
        !          1576:        struct eso_dma *p, **pp;
        !          1577:
        !          1578:        for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->ed_next) {
        !          1579:                if (KVADDR(p) == addr) {
        !          1580:                        eso_freemem(sc, p);
        !          1581:                        *pp = p->ed_next;
        !          1582:                        free(p, type);
        !          1583:                        return;
        !          1584:                }
        !          1585:        }
        !          1586: }
        !          1587:
        !          1588: HIDE size_t
        !          1589: eso_round_buffersize(hdl, direction, bufsize)
        !          1590:        void *hdl;
        !          1591:        int direction;
        !          1592:        size_t bufsize;
        !          1593: {
        !          1594:
        !          1595:        /* 64K restriction: ISA at eleven? */
        !          1596:        if (bufsize > 65536)
        !          1597:                bufsize = 65536;
        !          1598:
        !          1599:        return (bufsize);
        !          1600: }
        !          1601:
        !          1602: HIDE paddr_t
        !          1603: eso_mappage(hdl, addr, offs, prot)
        !          1604:        void *hdl;
        !          1605:        void *addr;
        !          1606:        off_t offs;
        !          1607:        int prot;
        !          1608: {
        !          1609:        struct eso_softc *sc = hdl;
        !          1610:        struct eso_dma *ed;
        !          1611:
        !          1612:        if (offs < 0)
        !          1613:                return (-1);
        !          1614:        for (ed = sc->sc_dmas; ed != NULL && KVADDR(ed) == addr;
        !          1615:             ed = ed->ed_next)
        !          1616:                ;
        !          1617:        if (ed == NULL)
        !          1618:                return (-1);
        !          1619:
        !          1620:        return (bus_dmamem_mmap(sc->sc_dmat, ed->ed_segs, ed->ed_nsegs,
        !          1621:            offs, prot, BUS_DMA_WAITOK));
        !          1622: }
        !          1623:
        !          1624: /* ARGSUSED */
        !          1625: HIDE int
        !          1626: eso_get_props(hdl)
        !          1627:        void *hdl;
        !          1628: {
        !          1629:
        !          1630:        return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
        !          1631:            AUDIO_PROP_FULLDUPLEX);
        !          1632: }
        !          1633:
        !          1634: HIDE int
        !          1635: eso_trigger_output(hdl, start, end, blksize, intr, arg, param)
        !          1636:        void *hdl;
        !          1637:        void *start, *end;
        !          1638:        int blksize;
        !          1639:        void (*intr)(void *);
        !          1640:        void *arg;
        !          1641:        struct audio_params *param;
        !          1642: {
        !          1643:        struct eso_softc *sc = hdl;
        !          1644:        struct eso_dma *ed;
        !          1645:        uint8_t a2c1;
        !          1646:
        !          1647:        DPRINTF((
        !          1648:            "%s: trigger_output: start %p, end %p, blksize %d, intr %p(%p)\n",
        !          1649:            sc->sc_dev.dv_xname, start, end, blksize, intr, arg));
        !          1650:        DPRINTF(("%s: param: rate %lu, encoding %u, precision %u, channels %u, sw_code %p, factor %d\n",
        !          1651:            sc->sc_dev.dv_xname, param->sample_rate, param->encoding,
        !          1652:            param->precision, param->channels, param->sw_code, param->factor));
        !          1653:
        !          1654:        /* Find DMA buffer. */
        !          1655:        for (ed = sc->sc_dmas; ed != NULL && KVADDR(ed) != start;
        !          1656:             ed = ed->ed_next)
        !          1657:                ;
        !          1658:        if (ed == NULL) {
        !          1659:                printf("%s: trigger_output: bad addr %p\n",
        !          1660:                    sc->sc_dev.dv_xname, start);
        !          1661:                return (EINVAL);
        !          1662:        }
        !          1663:
        !          1664:        sc->sc_pintr = intr;
        !          1665:        sc->sc_parg = arg;
        !          1666:
        !          1667:        /* DMA transfer count (in `words'!) reload using 2's complement. */
        !          1668:        blksize = -(blksize >> 1);
        !          1669:        eso_write_mixreg(sc, ESO_MIXREG_A2TCRLO, blksize & 0xff);
        !          1670:        eso_write_mixreg(sc, ESO_MIXREG_A2TCRHI, blksize >> 8);
        !          1671:
        !          1672:        /* Update DAC to reflect DMA count and audio parameters. */
        !          1673:        /* Note: we cache A2C2 in order to avoid r/m/w at interrupt time. */
        !          1674:        if (param->precision * param->factor == 16)
        !          1675:                sc->sc_a2c2 |= ESO_MIXREG_A2C2_16BIT;
        !          1676:        else
        !          1677:                sc->sc_a2c2 &= ~ESO_MIXREG_A2C2_16BIT;
        !          1678:        if (param->channels == 2)
        !          1679:                sc->sc_a2c2 |= ESO_MIXREG_A2C2_STEREO;
        !          1680:        else
        !          1681:                sc->sc_a2c2 &= ~ESO_MIXREG_A2C2_STEREO;
        !          1682:        if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
        !          1683:            param->encoding == AUDIO_ENCODING_SLINEAR_LE)
        !          1684:                sc->sc_a2c2 |= ESO_MIXREG_A2C2_SIGNED;
        !          1685:        else
        !          1686:                sc->sc_a2c2 &= ~ESO_MIXREG_A2C2_SIGNED;
        !          1687:        /* Unmask IRQ. */
        !          1688:        sc->sc_a2c2 |= ESO_MIXREG_A2C2_IRQM;
        !          1689:        eso_write_mixreg(sc, ESO_MIXREG_A2C2, sc->sc_a2c2);
        !          1690:
        !          1691:        /* Set up DMA controller. */
        !          1692:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAA, DMAADDR(ed));
        !          1693:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAC,
        !          1694:            (uint8_t *)end - (uint8_t *)start);
        !          1695:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM,
        !          1696:            ESO_IO_A2DMAM_DMAENB | ESO_IO_A2DMAM_AUTO);
        !          1697:
        !          1698:        /* Start DMA. */
        !          1699:        a2c1 = eso_read_mixreg(sc, ESO_MIXREG_A2C1);
        !          1700:        a2c1 &= ~ESO_MIXREG_A2C1_RESV0; /* Paranoia? XXX bit 5 */
        !          1701:        a2c1 |= ESO_MIXREG_A2C1_FIFOENB | ESO_MIXREG_A2C1_DMAENB |
        !          1702:            ESO_MIXREG_A2C1_AUTO;
        !          1703:        eso_write_mixreg(sc, ESO_MIXREG_A2C1, a2c1);
        !          1704:
        !          1705:        return (0);
        !          1706: }
        !          1707:
        !          1708: HIDE int
        !          1709: eso_trigger_input(hdl, start, end, blksize, intr, arg, param)
        !          1710:        void *hdl;
        !          1711:        void *start, *end;
        !          1712:        int blksize;
        !          1713:        void (*intr)(void *);
        !          1714:        void *arg;
        !          1715:        struct audio_params *param;
        !          1716: {
        !          1717:        struct eso_softc *sc = hdl;
        !          1718:        struct eso_dma *ed;
        !          1719:        uint8_t actl, a1c1;
        !          1720:
        !          1721:        DPRINTF((
        !          1722:            "%s: trigger_input: start %p, end %p, blksize %d, intr %p(%p)\n",
        !          1723:            sc->sc_dev.dv_xname, start, end, blksize, intr, arg));
        !          1724:        DPRINTF(("%s: param: rate %lu, encoding %u, precision %u, channels %u, sw_code %p, factor %d\n",
        !          1725:            sc->sc_dev.dv_xname, param->sample_rate, param->encoding,
        !          1726:            param->precision, param->channels, param->sw_code, param->factor));
        !          1727:
        !          1728:        /*
        !          1729:         * If we failed to configure the Audio 1 DMA controller, bail here
        !          1730:         * while retaining availability of the DAC direction (in Audio 2).
        !          1731:         */
        !          1732:        if (!sc->sc_dmac_configured)
        !          1733:                return (EIO);
        !          1734:
        !          1735:        /* Find DMA buffer. */
        !          1736:        for (ed = sc->sc_dmas; ed != NULL && KVADDR(ed) != start;
        !          1737:             ed = ed->ed_next)
        !          1738:                ;
        !          1739:        if (ed == NULL) {
        !          1740:                printf("%s: trigger_output: bad addr %p\n",
        !          1741:                    sc->sc_dev.dv_xname, start);
        !          1742:                return (EINVAL);
        !          1743:        }
        !          1744:
        !          1745:        sc->sc_rintr = intr;
        !          1746:        sc->sc_rarg = arg;
        !          1747:
        !          1748:        /* Set up ADC DMA converter parameters. */
        !          1749:        actl = eso_read_ctlreg(sc, ESO_CTLREG_ACTL);
        !          1750:        if (param->channels == 2) {
        !          1751:                actl &= ~ESO_CTLREG_ACTL_MONO;
        !          1752:                actl |= ESO_CTLREG_ACTL_STEREO;
        !          1753:        } else {
        !          1754:                actl &= ~ESO_CTLREG_ACTL_STEREO;
        !          1755:                actl |= ESO_CTLREG_ACTL_MONO;
        !          1756:        }
        !          1757:        eso_write_ctlreg(sc, ESO_CTLREG_ACTL, actl);
        !          1758:
        !          1759:        /* Set up Transfer Type: maybe move to attach time? */
        !          1760:        eso_write_ctlreg(sc, ESO_CTLREG_A1TT, ESO_CTLREG_A1TT_DEMAND4);
        !          1761:
        !          1762:        /* DMA transfer count reload using 2's complement. */
        !          1763:        blksize = -blksize;
        !          1764:        eso_write_ctlreg(sc, ESO_CTLREG_A1TCRLO, blksize & 0xff);
        !          1765:        eso_write_ctlreg(sc, ESO_CTLREG_A1TCRHI, blksize >> 8);
        !          1766:
        !          1767:        /* Set up and enable Audio 1 DMA FIFO. */
        !          1768:        a1c1 = ESO_CTLREG_A1C1_RESV1 | ESO_CTLREG_A1C1_FIFOENB;
        !          1769:        if (param->precision * param->factor == 16)
        !          1770:                a1c1 |= ESO_CTLREG_A1C1_16BIT;
        !          1771:        if (param->channels == 2)
        !          1772:                a1c1 |= ESO_CTLREG_A1C1_STEREO;
        !          1773:        else
        !          1774:                a1c1 |= ESO_CTLREG_A1C1_MONO;
        !          1775:        if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
        !          1776:            param->encoding == AUDIO_ENCODING_SLINEAR_LE)
        !          1777:                a1c1 |= ESO_CTLREG_A1C1_SIGNED;
        !          1778:        eso_write_ctlreg(sc, ESO_CTLREG_A1C1, a1c1);
        !          1779:
        !          1780:        /* Set up ADC IRQ/DRQ parameters. */
        !          1781:        eso_write_ctlreg(sc, ESO_CTLREG_LAIC,
        !          1782:            ESO_CTLREG_LAIC_PINENB | ESO_CTLREG_LAIC_EXTENB);
        !          1783:        eso_write_ctlreg(sc, ESO_CTLREG_DRQCTL,
        !          1784:            ESO_CTLREG_DRQCTL_ENB1 | ESO_CTLREG_DRQCTL_EXTENB);
        !          1785:
        !          1786:        /* Set up and enable DMA controller. */
        !          1787:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_CLEAR, 0);
        !          1788:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_MASK,
        !          1789:            ESO_DMAC_MASK_MASK);
        !          1790:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_MODE,
        !          1791:            DMA37MD_WRITE | DMA37MD_LOOP | DMA37MD_DEMAND);
        !          1792:        bus_space_write_4(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_DMAA,
        !          1793:            DMAADDR(ed));
        !          1794:        bus_space_write_2(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_DMAC,
        !          1795:            (uint8_t *)end - (uint8_t *)start - 1);
        !          1796:        bus_space_write_1(sc->sc_dmac_iot, sc->sc_dmac_ioh, ESO_DMAC_MASK, 0);
        !          1797:
        !          1798:        /* Start DMA. */
        !          1799:        eso_write_ctlreg(sc, ESO_CTLREG_A1C2,
        !          1800:            ESO_CTLREG_A1C2_DMAENB | ESO_CTLREG_A1C2_READ |
        !          1801:            ESO_CTLREG_A1C2_AUTO | ESO_CTLREG_A1C2_ADC);
        !          1802:
        !          1803:        return (0);
        !          1804: }
        !          1805:
        !          1806: HIDE int
        !          1807: eso_set_recsrc(sc, recsrc)
        !          1808:        struct eso_softc *sc;
        !          1809:        unsigned int recsrc;
        !          1810: {
        !          1811:
        !          1812:        eso_write_mixreg(sc, ESO_MIXREG_ERS, recsrc);
        !          1813:        sc->sc_recsrc = recsrc;
        !          1814:        return (0);
        !          1815: }
        !          1816:
        !          1817: HIDE void
        !          1818: eso_set_gain(sc, port)
        !          1819:        struct eso_softc *sc;
        !          1820:        unsigned int port;
        !          1821: {
        !          1822:        uint8_t mixreg, tmp;
        !          1823:
        !          1824:        switch (port) {
        !          1825:        case ESO_DAC_PLAY_VOL:
        !          1826:                mixreg = ESO_MIXREG_PVR_A2;
        !          1827:                break;
        !          1828:        case ESO_MIC_PLAY_VOL:
        !          1829:                mixreg = ESO_MIXREG_PVR_MIC;
        !          1830:                break;
        !          1831:        case ESO_LINE_PLAY_VOL:
        !          1832:                mixreg = ESO_MIXREG_PVR_LINE;
        !          1833:                break;
        !          1834:        case ESO_SYNTH_PLAY_VOL:
        !          1835:                mixreg = ESO_MIXREG_PVR_SYNTH;
        !          1836:                break;
        !          1837:        case ESO_CD_PLAY_VOL:
        !          1838:                mixreg = ESO_MIXREG_PVR_CD;
        !          1839:                break;
        !          1840:        case ESO_AUXB_PLAY_VOL:
        !          1841:                mixreg = ESO_MIXREG_PVR_AUXB;
        !          1842:                break;
        !          1843:
        !          1844:        case ESO_DAC_REC_VOL:
        !          1845:                mixreg = ESO_MIXREG_RVR_A2;
        !          1846:                break;
        !          1847:        case ESO_MIC_REC_VOL:
        !          1848:                mixreg = ESO_MIXREG_RVR_MIC;
        !          1849:                break;
        !          1850:        case ESO_LINE_REC_VOL:
        !          1851:                mixreg = ESO_MIXREG_RVR_LINE;
        !          1852:                break;
        !          1853:        case ESO_SYNTH_REC_VOL:
        !          1854:                mixreg = ESO_MIXREG_RVR_SYNTH;
        !          1855:                break;
        !          1856:        case ESO_CD_REC_VOL:
        !          1857:                mixreg = ESO_MIXREG_RVR_CD;
        !          1858:                break;
        !          1859:        case ESO_AUXB_REC_VOL:
        !          1860:                mixreg = ESO_MIXREG_RVR_AUXB;
        !          1861:                break;
        !          1862:        case ESO_MONO_PLAY_VOL:
        !          1863:                mixreg = ESO_MIXREG_PVR_MONO;
        !          1864:                break;
        !          1865:        case ESO_MONO_REC_VOL:
        !          1866:                mixreg = ESO_MIXREG_RVR_MONO;
        !          1867:                break;
        !          1868:
        !          1869:        case ESO_PCSPEAKER_VOL:
        !          1870:                /* Special case - only 3-bit, mono, and reserved bits. */
        !          1871:                tmp = eso_read_mixreg(sc, ESO_MIXREG_PCSVR);
        !          1872:                tmp &= ESO_MIXREG_PCSVR_RESV;
        !          1873:                /* Map bits 7:5 -> 2:0. */
        !          1874:                tmp |= (sc->sc_gain[port][ESO_LEFT] >> 5);
        !          1875:                eso_write_mixreg(sc, ESO_MIXREG_PCSVR, tmp);
        !          1876:                return;
        !          1877:
        !          1878:        case ESO_MASTER_VOL:
        !          1879:                /* Special case - separate regs, and 6-bit precision. */
        !          1880:                /* Map bits 7:2 -> 5:0. */
        !          1881:                eso_write_mixreg(sc, ESO_MIXREG_LMVM,
        !          1882:                    sc->sc_gain[port][ESO_LEFT] >> 2);
        !          1883:                eso_write_mixreg(sc, ESO_MIXREG_RMVM,
        !          1884:                    sc->sc_gain[port][ESO_RIGHT] >> 2);
        !          1885:                return;
        !          1886:
        !          1887:        case ESO_SPATIALIZER:
        !          1888:                /* Special case - only `mono', and higher precision. */
        !          1889:                eso_write_mixreg(sc, ESO_MIXREG_SPATLVL,
        !          1890:                    sc->sc_gain[port][ESO_LEFT]);
        !          1891:                return;
        !          1892:
        !          1893:        case ESO_RECORD_VOL:
        !          1894:                /* Very Special case, controller register. */
        !          1895:                eso_write_ctlreg(sc, ESO_CTLREG_RECLVL,ESO_4BIT_GAIN_TO_STEREO(
        !          1896:                   sc->sc_gain[port][ESO_LEFT], sc->sc_gain[port][ESO_RIGHT]));
        !          1897:                return;
        !          1898:
        !          1899:        default:
        !          1900: #ifdef DIAGNOSTIC
        !          1901:                panic("eso_set_gain: bad port %u", port);
        !          1902:                /* NOTREACHED */
        !          1903: #else
        !          1904:                return;
        !          1905: #endif
        !          1906:                }
        !          1907:
        !          1908:        eso_write_mixreg(sc, mixreg, ESO_4BIT_GAIN_TO_STEREO(
        !          1909:            sc->sc_gain[port][ESO_LEFT], sc->sc_gain[port][ESO_RIGHT]));
        !          1910: }
        !          1911:
        !          1912:
        !          1913: HIDE void
        !          1914: eso_powerhook(why, self)
        !          1915:        int why;
        !          1916:        void *self;
        !          1917: {
        !          1918:        struct eso_softc *sc = (struct eso_softc *)self;
        !          1919:
        !          1920:        if (why != PWR_RESUME) {
        !          1921:                eso_halt_output(sc);
        !          1922:                eso_halt_input(sc);
        !          1923:
        !          1924:                bus_space_write_1(sc->sc_iot, sc->sc_ioh, ESO_IO_A2DMAM, 0);
        !          1925:                bus_space_write_1(sc->sc_dmac_iot,
        !          1926:                                  sc->sc_dmac_ioh, ESO_DMAC_CLEAR, 0);
        !          1927:                bus_space_write_1(sc->sc_sb_iot,
        !          1928:                                  sc->sc_sb_ioh, ESO_SB_STATUSFLAGS, 3);
        !          1929:
        !          1930:                /* shut down dma */
        !          1931:                pci_conf_write(sc->sc_pa.pa_pc,
        !          1932:                               sc->sc_pa.pa_tag, ESO_PCI_DDMAC, 0);
        !          1933:        } else
        !          1934:                eso_setup(sc, 0);
        !          1935: }

CVSweb