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

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

1.1     ! nbrk        1: /*     $OpenBSD: ess.c,v 1.11 2006/02/22 19:43:42 miod Exp $   */
        !             2: /*     $NetBSD: ess.c,v 1.44.4.1 1999/06/21 01:18:00 thorpej Exp $     */
        !             3:
        !             4: /*
        !             5:  * Copyright 1997
        !             6:  * Digital Equipment Corporation. All rights reserved.
        !             7:  *
        !             8:  * This software is furnished under license and may be used and
        !             9:  * copied only in accordance with the following terms and conditions.
        !            10:  * Subject to these conditions, you may download, copy, install,
        !            11:  * use, modify and distribute this software in source and/or binary
        !            12:  * form. No title or ownership is transferred hereby.
        !            13:  *
        !            14:  * 1) Any source code used, modified or distributed must reproduce
        !            15:  *    and retain this copyright notice and list of conditions as
        !            16:  *    they appear in the source file.
        !            17:  *
        !            18:  * 2) No right is granted to use any trade name, trademark, or logo of
        !            19:  *    Digital Equipment Corporation. Neither the "Digital Equipment
        !            20:  *    Corporation" name nor any trademark or logo of Digital Equipment
        !            21:  *    Corporation may be used to endorse or promote products derived
        !            22:  *    from this software without the prior written permission of
        !            23:  *    Digital Equipment Corporation.
        !            24:  *
        !            25:  * 3) This software is provided "AS-IS" and any express or implied
        !            26:  *    warranties, including but not limited to, any implied warranties
        !            27:  *    of merchantability, fitness for a particular purpose, or
        !            28:  *    non-infringement are disclaimed. In no event shall DIGITAL be
        !            29:  *    liable for any damages whatsoever, and in particular, DIGITAL
        !            30:  *    shall not be liable for special, indirect, consequential, or
        !            31:  *    incidental damages or damages for lost profits, loss of
        !            32:  *    revenue or loss of use, whether such damages arise in contract,
        !            33:  *    negligence, tort, under statute, in equity, at law or otherwise,
        !            34:  *    even if advised of the possibility of such damage.
        !            35:  */
        !            36:
        !            37: /*
        !            38: **++
        !            39: **
        !            40: **  ess.c
        !            41: **
        !            42: **  FACILITY:
        !            43: **
        !            44: **     DIGITAL Network Appliance Reference Design (DNARD)
        !            45: **
        !            46: **  MODULE DESCRIPTION:
        !            47: **
        !            48: **     This module contains the device driver for the ESS
        !            49: **     Technologies 1888/1887/888 sound chip. The code in sbdsp.c was
        !            50: **     used as a reference point when implementing this driver.
        !            51: **
        !            52: **  AUTHORS:
        !            53: **
        !            54: **     Blair Fidler    Software Engineering Australia
        !            55: **                     Gold Coast, Australia.
        !            56: **
        !            57: **  CREATION DATE:
        !            58: **
        !            59: **     March 10, 1997.
        !            60: **
        !            61: **  MODIFICATION HISTORY:
        !            62: **
        !            63: **     Heavily modified by Lennart Augustsson and Charles M. Hannum for
        !            64: **     bus_dma, changes to audio interface, and many bug fixes.
        !            65: **     ESS1788 support by Nathan J. Williams and Charles M. Hannum.
        !            66: **--
        !            67: */
        !            68:
        !            69: #include <sys/param.h>
        !            70: #include <sys/systm.h>
        !            71: #include <sys/errno.h>
        !            72: #include <sys/ioctl.h>
        !            73: #include <sys/syslog.h>
        !            74: #include <sys/device.h>
        !            75: #include <sys/proc.h>
        !            76: #include <sys/kernel.h>
        !            77: #include <sys/timeout.h>
        !            78:
        !            79: #include <machine/cpu.h>
        !            80: #include <machine/intr.h>
        !            81: #include <machine/bus.h>
        !            82:
        !            83: #include <sys/audioio.h>
        !            84: #include <dev/audio_if.h>
        !            85: #include <dev/auconv.h>
        !            86: #include <dev/mulaw.h>
        !            87:
        !            88: #include <dev/isa/isavar.h>
        !            89: #include <dev/isa/isadmavar.h>
        !            90:
        !            91: #include <dev/isa/essvar.h>
        !            92: #include <dev/isa/essreg.h>
        !            93:
        !            94: #ifdef AUDIO_DEBUG
        !            95: #define DPRINTF(x)     if (essdebug) printf x
        !            96: #define DPRINTFN(n,x)  if (essdebug>(n)) printf x
        !            97: int    essdebug = 0;
        !            98: #else
        !            99: #define DPRINTF(x)
        !           100: #define DPRINTFN(n,x)
        !           101: #endif
        !           102:
        !           103: #if 0
        !           104: unsigned uuu;
        !           105: #define EREAD1(t, h, a) (uuu=bus_space_read_1(t, h, a),printf("EREAD  %02x=%02x\n", ((int)h&0xfff)+a, uuu),uuu)
        !           106: #define EWRITE1(t, h, a, d) (printf("EWRITE %02x=%02x\n", ((int)h & 0xfff)+a, d), bus_space_write_1(t, h, a, d))
        !           107: #else
        !           108: #define EREAD1(t, h, a) bus_space_read_1(t, h, a)
        !           109: #define EWRITE1(t, h, a, d) bus_space_write_1(t, h, a, d)
        !           110: #endif
        !           111:
        !           112: struct cfdriver ess_cd = {
        !           113:        NULL, "ess", DV_DULL
        !           114: };
        !           115:
        !           116: int    ess_setup_sc(struct ess_softc *, int);
        !           117:
        !           118: int    ess_open(void *, int);
        !           119: void   ess_1788_close(void *);
        !           120: void   ess_1888_close(void *);
        !           121: int    ess_getdev(void *, struct audio_device *);
        !           122: int    ess_drain(void *);
        !           123:
        !           124: int    ess_query_encoding(void *, struct audio_encoding *);
        !           125:
        !           126: int    ess_set_params(void *, int, int, struct audio_params *,
        !           127:            struct audio_params *);
        !           128:
        !           129: int    ess_round_blocksize(void *, int);
        !           130:
        !           131: int    ess_audio1_trigger_output(void *, void *, void *, int,
        !           132:            void (*)(void *), void *, struct audio_params *);
        !           133: int    ess_audio2_trigger_output(void *, void *, void *, int,
        !           134:            void (*)(void *), void *, struct audio_params *);
        !           135: int    ess_audio1_trigger_input(void *, void *, void *, int,
        !           136:            void (*)(void *), void *, struct audio_params *);
        !           137: int    ess_audio1_halt(void *);
        !           138: int    ess_audio2_halt(void *);
        !           139: int    ess_audio1_intr(void *);
        !           140: int    ess_audio2_intr(void *);
        !           141: void   ess_audio1_poll(void *);
        !           142: void   ess_audio2_poll(void *);
        !           143:
        !           144: int    ess_speaker_ctl(void *, int);
        !           145:
        !           146: int    ess_getdev(void *, struct audio_device *);
        !           147:
        !           148: int    ess_set_port(void *, mixer_ctrl_t *);
        !           149: int    ess_get_port(void *, mixer_ctrl_t *);
        !           150:
        !           151: void   *ess_malloc(void *, int, size_t, int, int);
        !           152: void   ess_free(void *, void *, int);
        !           153: size_t ess_round_buffersize(void *, int, size_t);
        !           154: paddr_t        ess_mappage(void *, void *, off_t, int);
        !           155:
        !           156:
        !           157: int    ess_query_devinfo(void *, mixer_devinfo_t *);
        !           158: int    ess_1788_get_props(void *);
        !           159: int    ess_1888_get_props(void *);
        !           160:
        !           161: void   ess_speaker_on(struct ess_softc *);
        !           162: void   ess_speaker_off(struct ess_softc *);
        !           163:
        !           164: int    ess_config_addr(struct ess_softc *);
        !           165: void   ess_config_irq(struct ess_softc *);
        !           166: void   ess_config_drq(struct ess_softc *);
        !           167: void   ess_setup(struct ess_softc *);
        !           168: int    ess_identify(struct ess_softc *);
        !           169:
        !           170: int    ess_reset(struct ess_softc *);
        !           171: void   ess_set_gain(struct ess_softc *, int, int);
        !           172: int    ess_set_in_port(struct ess_softc *, int);
        !           173: int    ess_set_in_ports(struct ess_softc *, int);
        !           174: u_int  ess_srtotc(u_int);
        !           175: u_int  ess_srtofc(u_int);
        !           176: u_char ess_get_dsp_status(struct ess_softc *);
        !           177: u_char ess_dsp_read_ready(struct ess_softc *);
        !           178: u_char ess_dsp_write_ready(struct ess_softc *);
        !           179: int    ess_rdsp(struct ess_softc *);
        !           180: int    ess_wdsp(struct ess_softc *, u_char);
        !           181: u_char ess_read_x_reg(struct ess_softc *, u_char);
        !           182: int    ess_write_x_reg(struct ess_softc *, u_char, u_char);
        !           183: void   ess_clear_xreg_bits(struct ess_softc *, u_char, u_char);
        !           184: void   ess_set_xreg_bits(struct ess_softc *, u_char, u_char);
        !           185: u_char ess_read_mix_reg(struct ess_softc *, u_char);
        !           186: void   ess_write_mix_reg(struct ess_softc *, u_char, u_char);
        !           187: void   ess_clear_mreg_bits(struct ess_softc *, u_char, u_char);
        !           188: void   ess_set_mreg_bits(struct ess_softc *, u_char, u_char);
        !           189: void   ess_read_multi_mix_reg(struct ess_softc *, u_char, u_int8_t *, bus_size_t);
        !           190:
        !           191: static char *essmodel[] = {
        !           192:        "unsupported",
        !           193:        "1888",
        !           194:        "1887",
        !           195:        "888",
        !           196:        "1788",
        !           197:        "1869",
        !           198:        "1879",
        !           199:        "1868",
        !           200:        "1878",
        !           201: };
        !           202:
        !           203: struct audio_device ess_device = {
        !           204:        "ESS Technology",
        !           205:        "x",
        !           206:        "ess"
        !           207: };
        !           208:
        !           209: /*
        !           210:  * Define our interface to the higher level audio driver.
        !           211:  */
        !           212:
        !           213: struct audio_hw_if ess_1788_hw_if = {
        !           214:        ess_open,
        !           215:        ess_1788_close,
        !           216:        ess_drain,
        !           217:        ess_query_encoding,
        !           218:        ess_set_params,
        !           219:        ess_round_blocksize,
        !           220:        NULL,
        !           221:        NULL,
        !           222:        NULL,
        !           223:        NULL,
        !           224:        NULL,
        !           225:        ess_audio1_halt,
        !           226:        ess_audio1_halt,
        !           227:        ess_speaker_ctl,
        !           228:        ess_getdev,
        !           229:        NULL,
        !           230:        ess_set_port,
        !           231:        ess_get_port,
        !           232:        ess_query_devinfo,
        !           233:        ess_malloc,
        !           234:        ess_free,
        !           235:        ess_round_buffersize,
        !           236:        ess_mappage,
        !           237:        ess_1788_get_props,
        !           238:        ess_audio1_trigger_output,
        !           239:        ess_audio1_trigger_input,
        !           240: };
        !           241:
        !           242: struct audio_hw_if ess_1888_hw_if = {
        !           243:        ess_open,
        !           244:        ess_1888_close,
        !           245:        ess_drain,
        !           246:        ess_query_encoding,
        !           247:        ess_set_params,
        !           248:        ess_round_blocksize,
        !           249:        NULL,
        !           250:        NULL,
        !           251:        NULL,
        !           252:        NULL,
        !           253:        NULL,
        !           254:        ess_audio2_halt,
        !           255:        ess_audio1_halt,
        !           256:        ess_speaker_ctl,
        !           257:        ess_getdev,
        !           258:        NULL,
        !           259:        ess_set_port,
        !           260:        ess_get_port,
        !           261:        ess_query_devinfo,
        !           262:        ess_malloc,
        !           263:        ess_free,
        !           264:        ess_round_buffersize,
        !           265:        ess_mappage,
        !           266:        ess_1888_get_props,
        !           267:        ess_audio2_trigger_output,
        !           268:        ess_audio1_trigger_input,
        !           269: };
        !           270:
        !           271: #ifdef AUDIO_DEBUG
        !           272: void ess_printsc(struct ess_softc *);
        !           273: void ess_dump_mixer(struct ess_softc *);
        !           274:
        !           275: void
        !           276: ess_printsc(sc)
        !           277:        struct ess_softc *sc;
        !           278: {
        !           279:        int i;
        !           280:
        !           281:        printf("open %d iobase 0x%x outport %u inport %u speaker %s\n",
        !           282:               (int)sc->sc_open, sc->sc_iobase, sc->out_port,
        !           283:               sc->in_port, sc->spkr_state ? "on" : "off");
        !           284:
        !           285:        printf("audio1: dmachan %d irq %d nintr %lu intr %p arg %p\n",
        !           286:               sc->sc_audio1.drq, sc->sc_audio1.irq, sc->sc_audio1.nintr,
        !           287:               sc->sc_audio1.intr, sc->sc_audio1.arg);
        !           288:
        !           289:        if (!ESS_USE_AUDIO1(sc->sc_model)) {
        !           290:                printf("audio2: dmachan %d irq %d nintr %lu intr %p arg %p\n",
        !           291:                       sc->sc_audio2.drq, sc->sc_audio2.irq, sc->sc_audio2.nintr,
        !           292:                       sc->sc_audio2.intr, sc->sc_audio2.arg);
        !           293:        }
        !           294:
        !           295:        printf("gain:");
        !           296:        for (i = 0; i < sc->ndevs; i++)
        !           297:                printf(" %u,%u", sc->gain[i][ESS_LEFT], sc->gain[i][ESS_RIGHT]);
        !           298:        printf("\n");
        !           299: }
        !           300:
        !           301: void
        !           302: ess_dump_mixer(sc)
        !           303:        struct ess_softc *sc;
        !           304: {
        !           305:        printf("ESS_DAC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           306:               0x7C, ess_read_mix_reg(sc, 0x7C));
        !           307:        printf("ESS_MIC_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           308:               0x1A, ess_read_mix_reg(sc, 0x1A));
        !           309:        printf("ESS_LINE_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           310:               0x3E, ess_read_mix_reg(sc, 0x3E));
        !           311:        printf("ESS_SYNTH_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           312:               0x36, ess_read_mix_reg(sc, 0x36));
        !           313:        printf("ESS_CD_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           314:               0x38, ess_read_mix_reg(sc, 0x38));
        !           315:        printf("ESS_AUXB_PLAY_VOL: mix reg 0x%02x=0x%02x\n",
        !           316:               0x3A, ess_read_mix_reg(sc, 0x3A));
        !           317:        printf("ESS_MASTER_VOL: mix reg 0x%02x=0x%02x\n",
        !           318:               0x32, ess_read_mix_reg(sc, 0x32));
        !           319:        printf("ESS_PCSPEAKER_VOL: mix reg 0x%02x=0x%02x\n",
        !           320:               0x3C, ess_read_mix_reg(sc, 0x3C));
        !           321:        printf("ESS_DAC_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           322:               0x69, ess_read_mix_reg(sc, 0x69));
        !           323:        printf("ESS_MIC_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           324:               0x68, ess_read_mix_reg(sc, 0x68));
        !           325:        printf("ESS_LINE_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           326:               0x6E, ess_read_mix_reg(sc, 0x6E));
        !           327:        printf("ESS_SYNTH_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           328:               0x6B, ess_read_mix_reg(sc, 0x6B));
        !           329:        printf("ESS_CD_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           330:               0x6A, ess_read_mix_reg(sc, 0x6A));
        !           331:        printf("ESS_AUXB_REC_VOL: mix reg 0x%02x=0x%02x\n",
        !           332:               0x6C, ess_read_mix_reg(sc, 0x6C));
        !           333:        printf("ESS_RECORD_VOL: x reg 0x%02x=0x%02x\n",
        !           334:               0xB4, ess_read_x_reg(sc, 0xB4));
        !           335:        printf("Audio 1 play vol (unused): mix reg 0x%02x=0x%02x\n",
        !           336:               0x14, ess_read_mix_reg(sc, 0x14));
        !           337:
        !           338:        printf("ESS_MIC_PREAMP: x reg 0x%02x=0x%02x\n",
        !           339:               ESS_XCMD_PREAMP_CTRL, ess_read_x_reg(sc, ESS_XCMD_PREAMP_CTRL));
        !           340:        printf("ESS_RECORD_MONITOR: x reg 0x%02x=0x%02x\n",
        !           341:               ESS_XCMD_AUDIO_CTRL, ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL));
        !           342:        printf("Record source: mix reg 0x%02x=0x%02x, 0x%02x=0x%02x\n",
        !           343:               ESS_MREG_ADC_SOURCE, ess_read_mix_reg(sc, ESS_MREG_ADC_SOURCE),
        !           344:               ESS_MREG_AUDIO2_CTRL2, ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2));
        !           345: }
        !           346:
        !           347: #endif
        !           348:
        !           349: /*
        !           350:  * Configure the ESS chip for the desired audio base address.
        !           351:  */
        !           352: int
        !           353: ess_config_addr(sc)
        !           354:        struct ess_softc *sc;
        !           355: {
        !           356:        int iobase = sc->sc_iobase;
        !           357:        bus_space_tag_t iot = sc->sc_iot;
        !           358:
        !           359:        /*
        !           360:         * Configure using the System Control Register method.  This
        !           361:         * method is used when the AMODE line is tied high, which is
        !           362:         * the case for the Shark, but not for the evaluation board.
        !           363:         */
        !           364:
        !           365:        bus_space_handle_t scr_access_ioh;
        !           366:        bus_space_handle_t scr_ioh;
        !           367:        u_short scr_value;
        !           368:
        !           369:        /*
        !           370:         * Set the SCR bit to enable audio.
        !           371:         */
        !           372:        scr_value = ESS_SCR_AUDIO_ENABLE;
        !           373:
        !           374:        /*
        !           375:         * Set the SCR bits necessary to select the specified audio
        !           376:         * base address.
        !           377:         */
        !           378:        switch(iobase) {
        !           379:        case 0x220:
        !           380:                scr_value |= ESS_SCR_AUDIO_220;
        !           381:                break;
        !           382:        case 0x230:
        !           383:                scr_value |= ESS_SCR_AUDIO_230;
        !           384:                break;
        !           385:        case 0x240:
        !           386:                scr_value |= ESS_SCR_AUDIO_240;
        !           387:                break;
        !           388:        case 0x250:
        !           389:                scr_value |= ESS_SCR_AUDIO_250;
        !           390:                break;
        !           391:        default:
        !           392:                printf("ess: configured iobase 0x%x invalid\n", iobase);
        !           393:                return (1);
        !           394:                break;
        !           395:        }
        !           396:
        !           397:        /*
        !           398:         * Get a mapping for the System Control Register (SCR) access
        !           399:         * registers and the SCR data registers.
        !           400:         */
        !           401:        if (bus_space_map(iot, ESS_SCR_ACCESS_BASE, ESS_SCR_ACCESS_PORTS,
        !           402:                          0, &scr_access_ioh)) {
        !           403:                printf("ess: can't map SCR access registers\n");
        !           404:                return (1);
        !           405:        }
        !           406:        if (bus_space_map(iot, ESS_SCR_BASE, ESS_SCR_PORTS,
        !           407:                          0, &scr_ioh)) {
        !           408:                printf("ess: can't map SCR registers\n");
        !           409:                bus_space_unmap(iot, scr_access_ioh, ESS_SCR_ACCESS_PORTS);
        !           410:                return (1);
        !           411:        }
        !           412:
        !           413:        /* Unlock the SCR. */
        !           414:        EWRITE1(iot, scr_access_ioh, ESS_SCR_UNLOCK, 0);
        !           415:
        !           416:        /* Write the base address information into SCR[0]. */
        !           417:        EWRITE1(iot, scr_ioh, ESS_SCR_INDEX, 0);
        !           418:        EWRITE1(iot, scr_ioh, ESS_SCR_DATA, scr_value);
        !           419:
        !           420:        /* Lock the SCR. */
        !           421:        EWRITE1(iot, scr_access_ioh, ESS_SCR_LOCK, 0);
        !           422:
        !           423:        /* Unmap the SCR access ports and the SCR data ports. */
        !           424:        bus_space_unmap(iot, scr_access_ioh, ESS_SCR_ACCESS_PORTS);
        !           425:        bus_space_unmap(iot, scr_ioh, ESS_SCR_PORTS);
        !           426:
        !           427:        return 0;
        !           428: }
        !           429:
        !           430:
        !           431: /*
        !           432:  * Configure the ESS chip for the desired IRQ and DMA channels.
        !           433:  * ESS  ISA
        !           434:  * --------
        !           435:  * IRQA irq9
        !           436:  * IRQB irq5
        !           437:  * IRQC irq7
        !           438:  * IRQD irq10
        !           439:  * IRQE irq15
        !           440:  *
        !           441:  * DRQA drq0
        !           442:  * DRQB drq1
        !           443:  * DRQC drq3
        !           444:  * DRQD drq5
        !           445:  */
        !           446: void
        !           447: ess_config_irq(sc)
        !           448:        struct ess_softc *sc;
        !           449: {
        !           450:        int v;
        !           451:
        !           452:        DPRINTFN(2,("ess_config_irq\n"));
        !           453:
        !           454:        if (sc->sc_model == ESS_1887 &&
        !           455:            sc->sc_audio1.irq == sc->sc_audio2.irq &&
        !           456:            sc->sc_audio1.irq != -1) {
        !           457:                /* Use new method, both interrupts are the same. */
        !           458:                v = ESS_IS_SELECT_IRQ;  /* enable intrs */
        !           459:                switch (sc->sc_audio1.irq) {
        !           460:                case 5:
        !           461:                        v |= ESS_IS_INTRB;
        !           462:                        break;
        !           463:                case 7:
        !           464:                        v |= ESS_IS_INTRC;
        !           465:                        break;
        !           466:                case 9:
        !           467:                        v |= ESS_IS_INTRA;
        !           468:                        break;
        !           469:                case 10:
        !           470:                        v |= ESS_IS_INTRD;
        !           471:                        break;
        !           472:                case 15:
        !           473:                        v |= ESS_IS_INTRE;
        !           474:                        break;
        !           475: #ifdef DIAGNOSTIC
        !           476:                default:
        !           477:                        printf("ess_config_irq: configured irq %d not supported for Audio 1\n",
        !           478:                               sc->sc_audio1.irq);
        !           479:                        return;
        !           480: #endif
        !           481:                }
        !           482:                /* Set the IRQ */
        !           483:                ess_write_mix_reg(sc, ESS_MREG_INTR_ST, v);
        !           484:                return;
        !           485:        }
        !           486:
        !           487:        if (sc->sc_model == ESS_1887) {
        !           488:                /* Tell the 1887 to use the old interrupt method. */
        !           489:                ess_write_mix_reg(sc, ESS_MREG_INTR_ST, ESS_IS_ES1888);
        !           490:        }
        !           491:
        !           492:        if (sc->sc_audio1.polled) {
        !           493:                /* Turn off Audio1 interrupts. */
        !           494:                v = 0;
        !           495:        } else {
        !           496:                /* Configure Audio 1 for the appropriate IRQ line. */
        !           497:                v = ESS_IRQ_CTRL_MASK | ESS_IRQ_CTRL_EXT; /* All intrs on */
        !           498:                switch (sc->sc_audio1.irq) {
        !           499:                case 5:
        !           500:                        v |= ESS_IRQ_CTRL_INTRB;
        !           501:                        break;
        !           502:                case 7:
        !           503:                        v |= ESS_IRQ_CTRL_INTRC;
        !           504:                        break;
        !           505:                case 9:
        !           506:                        v |= ESS_IRQ_CTRL_INTRA;
        !           507:                        break;
        !           508:                case 10:
        !           509:                        v |= ESS_IRQ_CTRL_INTRD;
        !           510:                        break;
        !           511: #ifdef DIAGNOSTIC
        !           512:                default:
        !           513:                        printf("ess: configured irq %d not supported for Audio 1\n",
        !           514:                               sc->sc_audio1.irq);
        !           515:                        return;
        !           516: #endif
        !           517:                }
        !           518:        }
        !           519:        ess_write_x_reg(sc, ESS_XCMD_IRQ_CTRL, v);
        !           520:
        !           521:        if (ESS_USE_AUDIO1(sc->sc_model))
        !           522:                return;
        !           523:
        !           524:        if (sc->sc_audio2.polled) {
        !           525:                /* Turn off Audio2 interrupts. */
        !           526:                ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
        !           527:                                    ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
        !           528:        } else {
        !           529:                /* Audio2 is hardwired to INTRE in this mode. */
        !           530:                ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
        !           531:                                  ESS_AUDIO2_CTRL2_IRQ2_ENABLE);
        !           532:        }
        !           533: }
        !           534:
        !           535:
        !           536: void
        !           537: ess_config_drq(sc)
        !           538:        struct ess_softc *sc;
        !           539: {
        !           540:        int v;
        !           541:
        !           542:        DPRINTFN(2,("ess_config_drq\n"));
        !           543:
        !           544:        /* Configure Audio 1 (record) for DMA on the appropriate channel. */
        !           545:        v = ESS_DRQ_CTRL_PU | ESS_DRQ_CTRL_EXT;
        !           546:        switch (sc->sc_audio1.drq) {
        !           547:        case 0:
        !           548:                v |= ESS_DRQ_CTRL_DRQA;
        !           549:                break;
        !           550:        case 1:
        !           551:                v |= ESS_DRQ_CTRL_DRQB;
        !           552:                break;
        !           553:        case 3:
        !           554:                v |= ESS_DRQ_CTRL_DRQC;
        !           555:                break;
        !           556: #ifdef DIAGNOSTIC
        !           557:        default:
        !           558:                printf("ess_config_drq: configured dma chan %d not supported for Audio 1\n",
        !           559:                       sc->sc_audio1.drq);
        !           560:                return;
        !           561: #endif
        !           562:        }
        !           563:        /* Set DRQ1 */
        !           564:        ess_write_x_reg(sc, ESS_XCMD_DRQ_CTRL, v);
        !           565:
        !           566:        if (ESS_USE_AUDIO1(sc->sc_model))
        !           567:                return;
        !           568:
        !           569:        /* Configure DRQ2 */
        !           570:        v = ESS_AUDIO2_CTRL3_DRQ_PD;
        !           571:        switch (sc->sc_audio2.drq) {
        !           572:        case 0:
        !           573:                v |= ESS_AUDIO2_CTRL3_DRQA;
        !           574:                break;
        !           575:        case 1:
        !           576:                v |= ESS_AUDIO2_CTRL3_DRQB;
        !           577:                break;
        !           578:        case 3:
        !           579:                v |= ESS_AUDIO2_CTRL3_DRQC;
        !           580:                break;
        !           581:        case 5:
        !           582:                v |= ESS_AUDIO2_CTRL3_DRQD;
        !           583:                break;
        !           584: #ifdef DIAGNOSTIC
        !           585:        default:
        !           586:                printf("ess_config_drq: configured dma chan %d not supported for Audio 2\n",
        !           587:                       sc->sc_audio2.drq);
        !           588:                return;
        !           589: #endif
        !           590:        }
        !           591:        ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL3, v);
        !           592:        /* Enable DMA 2 */
        !           593:        ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2,
        !           594:                          ESS_AUDIO2_CTRL2_DMA_ENABLE);
        !           595: }
        !           596:
        !           597: /*
        !           598:  * Set up registers after a reset.
        !           599:  */
        !           600: void
        !           601: ess_setup(sc)
        !           602:        struct ess_softc *sc;
        !           603: {
        !           604:
        !           605:        ess_config_irq(sc);
        !           606:        ess_config_drq(sc);
        !           607:
        !           608:        DPRINTFN(2,("ess_setup: done\n"));
        !           609: }
        !           610:
        !           611: /*
        !           612:  * Determine the model of ESS chip we are talking to.  Currently we
        !           613:  * only support ES1888, ES1887 and ES888.  The method of determining
        !           614:  * the chip is based on the information on page 27 of the ES1887 data
        !           615:  * sheet.
        !           616:  *
        !           617:  * This routine sets the values of sc->sc_model and sc->sc_version.
        !           618:  */
        !           619: int
        !           620: ess_identify(sc)
        !           621:        struct ess_softc *sc;
        !           622: {
        !           623:        u_char reg1;
        !           624:        u_char reg2;
        !           625:        u_char reg3;
        !           626:        u_int8_t ident[4];
        !           627:
        !           628:        sc->sc_model = ESS_UNSUPPORTED;
        !           629:        sc->sc_version = 0;
        !           630:
        !           631:        memset(ident, 0, sizeof(ident));
        !           632:
        !           633:        /*
        !           634:         * 1. Check legacy ID bytes.  These should be 0x68 0x8n, where
        !           635:         *    n >= 8 for an ES1887 or an ES888.  Other values indicate
        !           636:         *    earlier (unsupported) chips.
        !           637:         */
        !           638:        ess_wdsp(sc, ESS_ACMD_LEGACY_ID);
        !           639:
        !           640:        if ((reg1 = ess_rdsp(sc)) != 0x68) {
        !           641:                printf("ess: First ID byte wrong (0x%02x)\n", reg1);
        !           642:                return 1;
        !           643:        }
        !           644:
        !           645:        reg2 = ess_rdsp(sc);
        !           646:        if (((reg2 & 0xf0) != 0x80) ||
        !           647:            ((reg2 & 0x0f) < 8)) {
        !           648:                printf("ess: Second ID byte wrong (0x%02x)\n", reg2);
        !           649:                return 1;
        !           650:        }
        !           651:
        !           652:        /*
        !           653:         * Store the ID bytes as the version.
        !           654:         */
        !           655:        sc->sc_version = (reg1 << 8) + reg2;
        !           656:
        !           657:
        !           658:        /*
        !           659:         * 2. Verify we can change bit 2 in mixer register 0x64.  This
        !           660:         *    should be possible on all supported chips.
        !           661:         */
        !           662:        reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
        !           663:        reg2 = reg1 ^ 0x04;  /* toggle bit 2 */
        !           664:
        !           665:        ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
        !           666:
        !           667:        if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) != reg2) {
        !           668:                printf("ess: Hardware error (unable to toggle bit 2 of mixer register 0x64)\n");
        !           669:                return 1;
        !           670:        }
        !           671:
        !           672:        /*
        !           673:         * Restore the original value of mixer register 0x64.
        !           674:         */
        !           675:        ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
        !           676:
        !           677:
        !           678:        /*
        !           679:         * 3. Verify we can change the value of mixer register
        !           680:         *    ESS_MREG_SAMPLE_RATE.
        !           681:         *    This is possible on the 1888/1887/888, but not on the 1788.
        !           682:         *    It is not necessary to restore the value of this mixer register.
        !           683:         */
        !           684:        reg1 = ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE);
        !           685:        reg2 = reg1 ^ 0xff;  /* toggle all bits */
        !           686:
        !           687:        ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, reg2);
        !           688:
        !           689:        if (ess_read_mix_reg(sc, ESS_MREG_SAMPLE_RATE) != reg2) {
        !           690:                /* If we got this far before failing, it's a 1788. */
        !           691:                sc->sc_model = ESS_1788;
        !           692:
        !           693:                /*
        !           694:                 * Identify ESS model for ES18[67]8.
        !           695:                 */
        !           696:                ess_read_multi_mix_reg(sc, 0x40, ident, sizeof(ident));
        !           697:                if(ident[0] == 0x18) {
        !           698:                        switch(ident[1]) {
        !           699:                        case 0x68:
        !           700:                                sc->sc_model = ESS_1868;
        !           701:                                break;
        !           702:                        case 0x78:
        !           703:                                sc->sc_model = ESS_1878;
        !           704:                                break;
        !           705:                        }
        !           706:                }
        !           707:        } else {
        !           708:                /*
        !           709:                 * 4. Determine if we can change bit 5 in mixer register 0x64.
        !           710:                 *    This determines whether we have an ES1887:
        !           711:                 *
        !           712:                 *    - can change indicates ES1887
        !           713:                 *    - can't change indicates ES1888 or ES888
        !           714:                 */
        !           715:                reg1 = ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL);
        !           716:                reg2 = reg1 ^ 0x20;  /* toggle bit 5 */
        !           717:
        !           718:                ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg2);
        !           719:
        !           720:                if (ess_read_mix_reg(sc, ESS_MREG_VOLUME_CTRL) == reg2) {
        !           721:                        sc->sc_model = ESS_1887;
        !           722:
        !           723:                        /*
        !           724:                         * Restore the original value of mixer register 0x64.
        !           725:                         */
        !           726:                        ess_write_mix_reg(sc, ESS_MREG_VOLUME_CTRL, reg1);
        !           727:
        !           728:                        /*
        !           729:                         * Identify ESS model for ES18[67]9.
        !           730:                         */
        !           731:                        ess_read_multi_mix_reg(sc, 0x40, ident, sizeof(ident));
        !           732:                        if(ident[0] == 0x18) {
        !           733:                                switch(ident[1]) {
        !           734:                                case 0x69:
        !           735:                                        sc->sc_model = ESS_1869;
        !           736:                                        break;
        !           737:                                case 0x79:
        !           738:                                        sc->sc_model = ESS_1879;
        !           739:                                        break;
        !           740:                                }
        !           741:                        }
        !           742:                } else {
        !           743:                        /*
        !           744:                         * 5. Determine if we can change the value of mixer
        !           745:                         *    register 0x69 independently of mixer register
        !           746:                         *    0x68. This determines which chip we have:
        !           747:                         *
        !           748:                         *    - can modify idependently indicates ES888
        !           749:                         *    - register 0x69 is an alias of 0x68 indicates ES1888
        !           750:                         */
        !           751:                        reg1 = ess_read_mix_reg(sc, 0x68);
        !           752:                        reg2 = ess_read_mix_reg(sc, 0x69);
        !           753:                        reg3 = reg2 ^ 0xff;  /* toggle all bits */
        !           754:
        !           755:                        /*
        !           756:                         * Write different values to each register.
        !           757:                         */
        !           758:                        ess_write_mix_reg(sc, 0x68, reg2);
        !           759:                        ess_write_mix_reg(sc, 0x69, reg3);
        !           760:
        !           761:                        if (ess_read_mix_reg(sc, 0x68) == reg2 &&
        !           762:                            ess_read_mix_reg(sc, 0x69) == reg3)
        !           763:                                sc->sc_model = ESS_888;
        !           764:                        else
        !           765:                                sc->sc_model = ESS_1888;
        !           766:
        !           767:                        /*
        !           768:                         * Restore the original value of the registers.
        !           769:                         */
        !           770:                        ess_write_mix_reg(sc, 0x68, reg1);
        !           771:                        ess_write_mix_reg(sc, 0x69, reg2);
        !           772:                }
        !           773:        }
        !           774:
        !           775:        return 0;
        !           776: }
        !           777:
        !           778:
        !           779: int
        !           780: ess_setup_sc(sc, doinit)
        !           781:        struct ess_softc *sc;
        !           782:        int doinit;
        !           783: {
        !           784:        /* Reset the chip. */
        !           785:        if (ess_reset(sc) != 0) {
        !           786:                DPRINTF(("ess_setup_sc: couldn't reset chip\n"));
        !           787:                return (1);
        !           788:        }
        !           789:
        !           790:        /* Identify the ESS chip, and check that it is supported. */
        !           791:        if (ess_identify(sc)) {
        !           792:                DPRINTF(("ess_setup_sc: couldn't identify\n"));
        !           793:                return (1);
        !           794:        }
        !           795:
        !           796:        return (0);
        !           797: }
        !           798:
        !           799: /*
        !           800:  * Probe for the ESS hardware.
        !           801:  */
        !           802: int
        !           803: essmatch(sc)
        !           804:        struct ess_softc *sc;
        !           805: {
        !           806:        if (!ESS_BASE_VALID(sc->sc_iobase)) {
        !           807:                printf("ess: configured iobase 0x%x invalid\n", sc->sc_iobase);
        !           808:                return (0);
        !           809:        }
        !           810:
        !           811:        /* Configure the ESS chip for the desired audio base address. */
        !           812:        if (ess_config_addr(sc))
        !           813:                return (0);
        !           814:
        !           815:        if (ess_setup_sc(sc, 1))
        !           816:                return (0);
        !           817:
        !           818:        if (sc->sc_model == ESS_UNSUPPORTED) {
        !           819:                DPRINTF(("ess: Unsupported model\n"));
        !           820:                return (0);
        !           821:        }
        !           822:
        !           823:        /* Check that requested DMA channels are valid and different. */
        !           824:        if (!ESS_DRQ1_VALID(sc->sc_audio1.drq)) {
        !           825:                printf("ess: record drq %d invalid\n", sc->sc_audio1.drq);
        !           826:                return (0);
        !           827:        }
        !           828:        if (!isa_drq_isfree(sc->sc_isa, sc->sc_audio1.drq))
        !           829:                return (0);
        !           830:        if (!ESS_USE_AUDIO1(sc->sc_model)) {
        !           831:                if (!ESS_DRQ2_VALID(sc->sc_audio2.drq)) {
        !           832:                        printf("ess: play drq %d invalid\n", sc->sc_audio2.drq);
        !           833:                        return (0);
        !           834:                }
        !           835:                if (sc->sc_audio1.drq == sc->sc_audio2.drq) {
        !           836:                        printf("ess: play and record drq both %d\n",
        !           837:                               sc->sc_audio1.drq);
        !           838:                        return (0);
        !           839:                }
        !           840:                if (!isa_drq_isfree(sc->sc_isa, sc->sc_audio2.drq))
        !           841:                        return (0);
        !           842:        }
        !           843:
        !           844:        /*
        !           845:         * The 1887 has an additional IRQ mode where both channels are mapped
        !           846:         * to the same IRQ.
        !           847:         */
        !           848:        if (sc->sc_model == ESS_1887 &&
        !           849:            sc->sc_audio1.irq == sc->sc_audio2.irq &&
        !           850:            sc->sc_audio1.irq != -1 &&
        !           851:            ESS_IRQ12_VALID(sc->sc_audio1.irq))
        !           852:                goto irq_not1888;
        !           853:
        !           854:        /* Check that requested IRQ lines are valid and different. */
        !           855:        if (sc->sc_audio1.irq != -1 &&
        !           856:            !ESS_IRQ1_VALID(sc->sc_audio1.irq)) {
        !           857:                printf("ess: record irq %d invalid\n", sc->sc_audio1.irq);
        !           858:                return (0);
        !           859:        }
        !           860:        if (!ESS_USE_AUDIO1(sc->sc_model)) {
        !           861:                if (sc->sc_audio2.irq != -1 &&
        !           862:                    !ESS_IRQ2_VALID(sc->sc_audio2.irq)) {
        !           863:                        printf("ess: play irq %d invalid\n", sc->sc_audio2.irq);
        !           864:                        return (0);
        !           865:                }
        !           866:                if (sc->sc_audio1.irq == sc->sc_audio2.irq &&
        !           867:                    sc->sc_audio1.irq != -1) {
        !           868:                        printf("ess: play and record irq both %d\n",
        !           869:                               sc->sc_audio1.irq);
        !           870:                        return (0);
        !           871:                }
        !           872:        }
        !           873:
        !           874: irq_not1888:
        !           875:        /* XXX should we check IRQs as well? */
        !           876:
        !           877:        return (1);
        !           878: }
        !           879:
        !           880:
        !           881: /*
        !           882:  * Attach hardware to driver, attach hardware driver to audio
        !           883:  * pseudo-device driver.
        !           884:  */
        !           885: void
        !           886: essattach(sc)
        !           887:        struct ess_softc *sc;
        !           888: {
        !           889:        struct audio_attach_args arg;
        !           890:        struct audio_params pparams, rparams;
        !           891:        int i;
        !           892:        u_int v;
        !           893:
        !           894:        if (ess_setup_sc(sc, 0)) {
        !           895:                printf(": setup failed\n");
        !           896:                return;
        !           897:        }
        !           898:
        !           899:        printf(": ESS Technology ES%s [version 0x%04x]\n",
        !           900:               essmodel[sc->sc_model], sc->sc_version);
        !           901:
        !           902:        sc->sc_audio1.polled = sc->sc_audio1.irq == -1;
        !           903:        if (!sc->sc_audio1.polled) {
        !           904:                sc->sc_audio1.ih = isa_intr_establish(sc->sc_ic,
        !           905:                    sc->sc_audio1.irq, sc->sc_audio1.ist, IPL_AUDIO,
        !           906:                    ess_audio1_intr, sc, sc->sc_dev.dv_xname);
        !           907:                printf("%s: audio1 interrupting at irq %d\n",
        !           908:                    sc->sc_dev.dv_xname, sc->sc_audio1.irq);
        !           909:        } else
        !           910:                printf("%s: audio1 polled\n", sc->sc_dev.dv_xname);
        !           911:        if (isa_dmamap_create(sc->sc_isa, sc->sc_audio1.drq,
        !           912:            MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
        !           913:                printf("%s: can't create map for drq %d\n",
        !           914:                       sc->sc_dev.dv_xname, sc->sc_audio1.drq);
        !           915:                return;
        !           916:        }
        !           917:
        !           918:        if (!ESS_USE_AUDIO1(sc->sc_model)) {
        !           919:                sc->sc_audio2.polled = sc->sc_audio2.irq == -1;
        !           920:                if (!sc->sc_audio2.polled) {
        !           921:                        sc->sc_audio2.ih = isa_intr_establish(sc->sc_ic,
        !           922:                            sc->sc_audio2.irq, sc->sc_audio2.ist, IPL_AUDIO,
        !           923:                            ess_audio2_intr, sc, sc->sc_dev.dv_xname);
        !           924:                        printf("%s: audio2 interrupting at irq %d\n",
        !           925:                            sc->sc_dev.dv_xname, sc->sc_audio2.irq);
        !           926:                } else
        !           927:                        printf("%s: audio2 polled\n", sc->sc_dev.dv_xname);
        !           928:                if (isa_dmamap_create(sc->sc_isa, sc->sc_audio2.drq,
        !           929:                    MAX_ISADMA, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
        !           930:                        printf("%s: can't create map for drq %d\n",
        !           931:                               sc->sc_dev.dv_xname, sc->sc_audio2.drq);
        !           932:                        return;
        !           933:                }
        !           934:        }
        !           935:
        !           936:        timeout_set(&sc->sc_tmo1, ess_audio1_poll, sc);
        !           937:        timeout_set(&sc->sc_tmo2, ess_audio2_poll, sc);
        !           938:
        !           939:        /*
        !           940:         * Set record and play parameters to default values defined in
        !           941:         * generic audio driver.
        !           942:         */
        !           943:        pparams = audio_default;
        !           944:        rparams = audio_default;
        !           945:        ess_set_params(sc, AUMODE_RECORD|AUMODE_PLAY, 0, &pparams, &rparams);
        !           946:
        !           947:        /* Do a hardware reset on the mixer. */
        !           948:        ess_write_mix_reg(sc, ESS_MIX_RESET, ESS_MIX_RESET);
        !           949:
        !           950:        /*
        !           951:         * Set volume of Audio 1 to zero and disable Audio 1 DAC input
        !           952:         * to playback mixer, since playback is always through Audio 2.
        !           953:         */
        !           954:        if (!ESS_USE_AUDIO1(sc->sc_model))
        !           955:                ess_write_mix_reg(sc, ESS_MREG_VOLUME_VOICE, 0);
        !           956:        ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
        !           957:
        !           958:        if (ESS_USE_AUDIO1(sc->sc_model)) {
        !           959:                ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIC);
        !           960:                sc->in_port = ESS_SOURCE_MIC;
        !           961:                sc->ndevs = ESS_1788_NDEVS;
        !           962:        } else {
        !           963:                /*
        !           964:                 * Set hardware record source to use output of the record
        !           965:                 * mixer. We do the selection of record source in software by
        !           966:                 * setting the gain of the unused sources to zero. (See
        !           967:                 * ess_set_in_ports.)
        !           968:                 */
        !           969:                ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ESS_SOURCE_MIXER);
        !           970:                sc->in_mask = 1 << ESS_MIC_REC_VOL;
        !           971:                sc->ndevs = ESS_1888_NDEVS;
        !           972:                ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x10);
        !           973:                ess_set_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL2, 0x08);
        !           974:        }
        !           975:
        !           976:        /*
        !           977:         * Set gain on each mixer device to a sensible value.
        !           978:         * Devices not normally used are turned off, and other devices
        !           979:         * are set to 50% volume.
        !           980:         */
        !           981:        for (i = 0; i < sc->ndevs; i++) {
        !           982:                switch (i) {
        !           983:                case ESS_MIC_PLAY_VOL:
        !           984:                case ESS_LINE_PLAY_VOL:
        !           985:                case ESS_CD_PLAY_VOL:
        !           986:                case ESS_AUXB_PLAY_VOL:
        !           987:                case ESS_DAC_REC_VOL:
        !           988:                case ESS_LINE_REC_VOL:
        !           989:                case ESS_SYNTH_REC_VOL:
        !           990:                case ESS_CD_REC_VOL:
        !           991:                case ESS_AUXB_REC_VOL:
        !           992:                        v = 0;
        !           993:                        break;
        !           994:                default:
        !           995:                        v = ESS_4BIT_GAIN(AUDIO_MAX_GAIN / 2);
        !           996:                        break;
        !           997:                }
        !           998:                sc->gain[i][ESS_LEFT] = sc->gain[i][ESS_RIGHT] = v;
        !           999:                ess_set_gain(sc, i, 1);
        !          1000:        }
        !          1001:
        !          1002:        ess_setup(sc);
        !          1003:
        !          1004:        /* Disable the speaker until the device is opened.  */
        !          1005:        ess_speaker_off(sc);
        !          1006:        sc->spkr_state = SPKR_OFF;
        !          1007:
        !          1008:        snprintf(ess_device.name, sizeof ess_device.name, "ES%s",
        !          1009:            essmodel[sc->sc_model]);
        !          1010:        snprintf(ess_device.version, sizeof ess_device.version, "0x%04x",
        !          1011:            sc->sc_version);
        !          1012:
        !          1013:        if (ESS_USE_AUDIO1(sc->sc_model))
        !          1014:                audio_attach_mi(&ess_1788_hw_if, sc, &sc->sc_dev);
        !          1015:        else
        !          1016:                audio_attach_mi(&ess_1888_hw_if, sc, &sc->sc_dev);
        !          1017:
        !          1018:        arg.type = AUDIODEV_TYPE_OPL;
        !          1019:        arg.hwif = 0;
        !          1020:        arg.hdl = 0;
        !          1021:        (void)config_found(&sc->sc_dev, &arg, audioprint);
        !          1022:
        !          1023: #ifdef AUDIO_DEBUG
        !          1024:        if (essdebug > 0)
        !          1025:                ess_printsc(sc);
        !          1026: #endif
        !          1027: }
        !          1028:
        !          1029: /*
        !          1030:  * Various routines to interface to higher level audio driver
        !          1031:  */
        !          1032:
        !          1033: int
        !          1034: ess_open(addr, flags)
        !          1035:        void *addr;
        !          1036:        int flags;
        !          1037: {
        !          1038:        struct ess_softc *sc = addr;
        !          1039:
        !          1040:        DPRINTF(("ess_open: sc=%p\n", sc));
        !          1041:
        !          1042:        if (sc->sc_open != 0 || ess_reset(sc) != 0)
        !          1043:                return ENXIO;
        !          1044:
        !          1045:        ess_setup(sc);          /* because we did a reset */
        !          1046:
        !          1047:        sc->sc_open = 1;
        !          1048:
        !          1049:        DPRINTF(("ess_open: opened\n"));
        !          1050:
        !          1051:        return (0);
        !          1052: }
        !          1053:
        !          1054: void
        !          1055: ess_1788_close(addr)
        !          1056:        void *addr;
        !          1057: {
        !          1058:        struct ess_softc *sc = addr;
        !          1059:
        !          1060:        DPRINTF(("ess_1788_close: sc=%p\n", sc));
        !          1061:
        !          1062:        ess_speaker_off(sc);
        !          1063:        sc->spkr_state = SPKR_OFF;
        !          1064:
        !          1065:        ess_audio1_halt(sc);
        !          1066:
        !          1067:        sc->sc_open = 0;
        !          1068:        DPRINTF(("ess_1788_close: closed\n"));
        !          1069: }
        !          1070:
        !          1071: void
        !          1072: ess_1888_close(addr)
        !          1073:        void *addr;
        !          1074: {
        !          1075:        struct ess_softc *sc = addr;
        !          1076:
        !          1077:        DPRINTF(("ess_1888_close: sc=%p\n", sc));
        !          1078:
        !          1079:        ess_speaker_off(sc);
        !          1080:        sc->spkr_state = SPKR_OFF;
        !          1081:
        !          1082:        ess_audio1_halt(sc);
        !          1083:        ess_audio2_halt(sc);
        !          1084:
        !          1085:        sc->sc_open = 0;
        !          1086:        DPRINTF(("ess_1888_close: closed\n"));
        !          1087: }
        !          1088:
        !          1089: /*
        !          1090:  * Wait for FIFO to drain, and analog section to settle.
        !          1091:  * XXX should check FIFO empty bit.
        !          1092:  */
        !          1093: int
        !          1094: ess_drain(addr)
        !          1095:        void *addr;
        !          1096: {
        !          1097:        tsleep(addr, PWAIT | PCATCH, "essdr", hz/20); /* XXX */
        !          1098:        return (0);
        !          1099: }
        !          1100:
        !          1101: /* XXX should use reference count */
        !          1102: int
        !          1103: ess_speaker_ctl(addr, newstate)
        !          1104:        void *addr;
        !          1105:        int newstate;
        !          1106: {
        !          1107:        struct ess_softc *sc = addr;
        !          1108:
        !          1109:        if ((newstate == SPKR_ON) && (sc->spkr_state == SPKR_OFF)) {
        !          1110:                ess_speaker_on(sc);
        !          1111:                sc->spkr_state = SPKR_ON;
        !          1112:        }
        !          1113:        if ((newstate == SPKR_OFF) && (sc->spkr_state == SPKR_ON)) {
        !          1114:                ess_speaker_off(sc);
        !          1115:                sc->spkr_state = SPKR_OFF;
        !          1116:        }
        !          1117:        return (0);
        !          1118: }
        !          1119:
        !          1120: int
        !          1121: ess_getdev(addr, retp)
        !          1122:        void *addr;
        !          1123:        struct audio_device *retp;
        !          1124: {
        !          1125:        *retp = ess_device;
        !          1126:        return (0);
        !          1127: }
        !          1128:
        !          1129: int
        !          1130: ess_query_encoding(addr, fp)
        !          1131:        void *addr;
        !          1132:        struct audio_encoding *fp;
        !          1133: {
        !          1134:        /*struct ess_softc *sc = addr;*/
        !          1135:
        !          1136:        switch (fp->index) {
        !          1137:        case 0:
        !          1138:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
        !          1139:                fp->encoding = AUDIO_ENCODING_ULINEAR;
        !          1140:                fp->precision = 8;
        !          1141:                fp->flags = 0;
        !          1142:                return (0);
        !          1143:        case 1:
        !          1144:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
        !          1145:                fp->encoding = AUDIO_ENCODING_ULAW;
        !          1146:                fp->precision = 8;
        !          1147:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !          1148:                return (0);
        !          1149:        case 2:
        !          1150:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
        !          1151:                fp->encoding = AUDIO_ENCODING_ALAW;
        !          1152:                fp->precision = 8;
        !          1153:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !          1154:                return (0);
        !          1155:        case 3:
        !          1156:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
        !          1157:                fp->encoding = AUDIO_ENCODING_SLINEAR;
        !          1158:                fp->precision = 8;
        !          1159:                fp->flags = 0;
        !          1160:                return (0);
        !          1161:        case 4:
        !          1162:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
        !          1163:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !          1164:                fp->precision = 16;
        !          1165:                fp->flags = 0;
        !          1166:                return (0);
        !          1167:        case 5:
        !          1168:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
        !          1169:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !          1170:                fp->precision = 16;
        !          1171:                fp->flags = 0;
        !          1172:                return (0);
        !          1173:        case 6:
        !          1174:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
        !          1175:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !          1176:                fp->precision = 16;
        !          1177:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !          1178:                return (0);
        !          1179:        case 7:
        !          1180:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
        !          1181:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !          1182:                fp->precision = 16;
        !          1183:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !          1184:                return (0);
        !          1185:        default:
        !          1186:                return EINVAL;
        !          1187:        }
        !          1188:        return (0);
        !          1189: }
        !          1190:
        !          1191: int
        !          1192: ess_set_params(addr, setmode, usemode, play, rec)
        !          1193:        void *addr;
        !          1194:        int setmode, usemode;
        !          1195:        struct audio_params *play, *rec;
        !          1196: {
        !          1197:        struct ess_softc *sc = addr;
        !          1198:        struct audio_params *p;
        !          1199:        int mode;
        !          1200:        int rate;
        !          1201:
        !          1202:        DPRINTF(("ess_set_params: set=%d use=%d\n", setmode, usemode));
        !          1203:
        !          1204:        /*
        !          1205:         * The ES1887 manual (page 39, `Full-Duplex DMA Mode') claims that in
        !          1206:         * full-duplex operation the sample rates must be the same for both
        !          1207:         * channels.  This appears to be false; the only bit in common is the
        !          1208:         * clock source selection.  However, we'll be conservative here.
        !          1209:         * - mycroft
        !          1210:         */
        !          1211:        if (play->sample_rate != rec->sample_rate &&
        !          1212:            usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
        !          1213:                if (setmode == AUMODE_PLAY) {
        !          1214:                        rec->sample_rate = play->sample_rate;
        !          1215:                        setmode |= AUMODE_RECORD;
        !          1216:                } else if (setmode == AUMODE_RECORD) {
        !          1217:                        play->sample_rate = rec->sample_rate;
        !          1218:                        setmode |= AUMODE_PLAY;
        !          1219:                } else
        !          1220:                        return (EINVAL);
        !          1221:        }
        !          1222:
        !          1223:        for (mode = AUMODE_RECORD; mode != -1;
        !          1224:             mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
        !          1225:                if ((setmode & mode) == 0)
        !          1226:                        continue;
        !          1227:
        !          1228:                p = mode == AUMODE_PLAY ? play : rec;
        !          1229:
        !          1230:                if (p->sample_rate < ESS_MINRATE ||
        !          1231:                    p->sample_rate > ESS_MAXRATE ||
        !          1232:                    (p->precision != 8 && p->precision != 16) ||
        !          1233:                    (p->channels != 1 && p->channels != 2))
        !          1234:                        return (EINVAL);
        !          1235:
        !          1236:                p->factor = 1;
        !          1237:                p->sw_code = 0;
        !          1238:                switch (p->encoding) {
        !          1239:                case AUDIO_ENCODING_SLINEAR_BE:
        !          1240:                case AUDIO_ENCODING_ULINEAR_BE:
        !          1241:                        if (p->precision == 16)
        !          1242:                                p->sw_code = swap_bytes;
        !          1243:                        break;
        !          1244:                case AUDIO_ENCODING_SLINEAR_LE:
        !          1245:                case AUDIO_ENCODING_ULINEAR_LE:
        !          1246:                        break;
        !          1247:                case AUDIO_ENCODING_ULAW:
        !          1248:                        if (mode == AUMODE_PLAY) {
        !          1249:                                p->factor = 2;
        !          1250:                                p->sw_code = mulaw_to_ulinear16;
        !          1251:                        } else
        !          1252:                                p->sw_code = ulinear8_to_mulaw;
        !          1253:                        break;
        !          1254:                case AUDIO_ENCODING_ALAW:
        !          1255:                        if (mode == AUMODE_PLAY) {
        !          1256:                                p->factor = 2;
        !          1257:                                p->sw_code = alaw_to_ulinear16;
        !          1258:                        } else
        !          1259:                                p->sw_code = ulinear8_to_alaw;
        !          1260:                        break;
        !          1261:                default:
        !          1262:                        return (EINVAL);
        !          1263:                }
        !          1264:        }
        !          1265:
        !          1266:        if (usemode == AUMODE_RECORD)
        !          1267:                rate = rec->sample_rate;
        !          1268:        else
        !          1269:                rate = play->sample_rate;
        !          1270:
        !          1271:        ess_write_x_reg(sc, ESS_XCMD_SAMPLE_RATE, ess_srtotc(rate));
        !          1272:        ess_write_x_reg(sc, ESS_XCMD_FILTER_CLOCK, ess_srtofc(rate));
        !          1273:
        !          1274:        if (!ESS_USE_AUDIO1(sc->sc_model)) {
        !          1275:                ess_write_mix_reg(sc, ESS_MREG_SAMPLE_RATE, ess_srtotc(rate));
        !          1276:                ess_write_mix_reg(sc, ESS_MREG_FILTER_CLOCK, ess_srtofc(rate));
        !          1277:        }
        !          1278:
        !          1279:        return (0);
        !          1280: }
        !          1281:
        !          1282: int
        !          1283: ess_audio1_trigger_output(addr, start, end, blksize, intr, arg, param)
        !          1284:        void *addr;
        !          1285:        void *start, *end;
        !          1286:        int blksize;
        !          1287:        void (*intr)(void *);
        !          1288:        void *arg;
        !          1289:        struct audio_params *param;
        !          1290: {
        !          1291:        struct ess_softc *sc = addr;
        !          1292:        u_int8_t reg;
        !          1293:
        !          1294:        DPRINTFN(1, ("ess_audio1_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
        !          1295:            addr, start, end, blksize, intr, arg));
        !          1296:
        !          1297:        if (sc->sc_audio1.active)
        !          1298:                panic("ess_audio1_trigger_output: already running");
        !          1299:
        !          1300:        sc->sc_audio1.active = 1;
        !          1301:        sc->sc_audio1.intr = intr;
        !          1302:        sc->sc_audio1.arg = arg;
        !          1303:        if (sc->sc_audio1.polled) {
        !          1304:                sc->sc_audio1.dmapos = 0;
        !          1305:                sc->sc_audio1.buffersize = (char *)end - (char *)start;
        !          1306:                sc->sc_audio1.dmacount = 0;
        !          1307:                sc->sc_audio1.blksize = blksize;
        !          1308:                timeout_add(&sc->sc_tmo1, hz/30);
        !          1309:        }
        !          1310:
        !          1311:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
        !          1312:        if (param->channels == 2) {
        !          1313:                reg &= ~ESS_AUDIO_CTRL_MONO;
        !          1314:                reg |= ESS_AUDIO_CTRL_STEREO;
        !          1315:        } else {
        !          1316:                reg |= ESS_AUDIO_CTRL_MONO;
        !          1317:                reg &= ~ESS_AUDIO_CTRL_STEREO;
        !          1318:        }
        !          1319:        ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
        !          1320:
        !          1321:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
        !          1322:        if (param->precision * param->factor == 16)
        !          1323:                reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
        !          1324:        else
        !          1325:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
        !          1326:        if (param->channels == 2)
        !          1327:                reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
        !          1328:        else
        !          1329:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
        !          1330:        if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
        !          1331:            param->encoding == AUDIO_ENCODING_SLINEAR_LE)
        !          1332:                reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
        !          1333:        else
        !          1334:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
        !          1335:        reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
        !          1336:        ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
        !          1337:
        !          1338:        isa_dmastart(sc->sc_isa, sc->sc_audio1.drq, start,
        !          1339:                     (char *)end - (char *)start, NULL,
        !          1340:            DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
        !          1341:
        !          1342:        /* Program transfer count registers with 2's complement of count. */
        !          1343:        blksize = -blksize;
        !          1344:        ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
        !          1345:        ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
        !          1346:
        !          1347:        /* Use 4 bytes per output DMA. */
        !          1348:        ess_set_xreg_bits(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
        !          1349:
        !          1350:        /* Start auto-init DMA */
        !          1351:        ess_wdsp(sc, ESS_ACMD_ENABLE_SPKR);
        !          1352:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
        !          1353:        reg &= ~(ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE);
        !          1354:        reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
        !          1355:        ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
        !          1356:
        !          1357:        return (0);
        !          1358: }
        !          1359:
        !          1360: int
        !          1361: ess_audio2_trigger_output(addr, start, end, blksize, intr, arg, param)
        !          1362:        void *addr;
        !          1363:        void *start, *end;
        !          1364:        int blksize;
        !          1365:        void (*intr)(void *);
        !          1366:        void *arg;
        !          1367:        struct audio_params *param;
        !          1368: {
        !          1369:        struct ess_softc *sc = addr;
        !          1370:        u_int8_t reg;
        !          1371:
        !          1372:        DPRINTFN(1, ("ess_audio2_trigger_output: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
        !          1373:            addr, start, end, blksize, intr, arg));
        !          1374:
        !          1375:        if (sc->sc_audio2.active)
        !          1376:                panic("ess_audio2_trigger_output: already running");
        !          1377:
        !          1378:        sc->sc_audio2.active = 1;
        !          1379:        sc->sc_audio2.intr = intr;
        !          1380:        sc->sc_audio2.arg = arg;
        !          1381:        if (sc->sc_audio2.polled) {
        !          1382:                sc->sc_audio2.dmapos = 0;
        !          1383:                sc->sc_audio2.buffersize = (char *)end - (char *)start;
        !          1384:                sc->sc_audio2.dmacount = 0;
        !          1385:                sc->sc_audio2.blksize = blksize;
        !          1386:                timeout_add(&sc->sc_tmo2, hz/30);
        !          1387:        }
        !          1388:
        !          1389:        reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2);
        !          1390:        if (param->precision * param->factor == 16)
        !          1391:                reg |= ESS_AUDIO2_CTRL2_FIFO_SIZE;
        !          1392:        else
        !          1393:                reg &= ~ESS_AUDIO2_CTRL2_FIFO_SIZE;
        !          1394:        if (param->channels == 2)
        !          1395:                reg |= ESS_AUDIO2_CTRL2_CHANNELS;
        !          1396:        else
        !          1397:                reg &= ~ESS_AUDIO2_CTRL2_CHANNELS;
        !          1398:        if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
        !          1399:            param->encoding == AUDIO_ENCODING_SLINEAR_LE)
        !          1400:                reg |= ESS_AUDIO2_CTRL2_FIFO_SIGNED;
        !          1401:        else
        !          1402:                reg &= ~ESS_AUDIO2_CTRL2_FIFO_SIGNED;
        !          1403:        ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2, reg);
        !          1404:
        !          1405:        isa_dmastart(sc->sc_isa, sc->sc_audio2.drq, start,
        !          1406:                     (char *)end - (char *)start, NULL,
        !          1407:            DMAMODE_WRITE | DMAMODE_LOOP, BUS_DMA_NOWAIT);
        !          1408:
        !          1409:        if (IS16BITDRQ(sc->sc_audio2.drq))
        !          1410:                blksize >>= 1;  /* use word count for 16 bit DMA */
        !          1411:        /* Program transfer count registers with 2's complement of count. */
        !          1412:        blksize = -blksize;
        !          1413:        ess_write_mix_reg(sc, ESS_MREG_XFER_COUNTLO, blksize);
        !          1414:        ess_write_mix_reg(sc, ESS_MREG_XFER_COUNTHI, blksize >> 8);
        !          1415:
        !          1416:        reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL1);
        !          1417:        if (IS16BITDRQ(sc->sc_audio2.drq))
        !          1418:                reg |= ESS_AUDIO2_CTRL1_XFER_SIZE;
        !          1419:        else
        !          1420:                reg &= ~ESS_AUDIO2_CTRL1_XFER_SIZE;
        !          1421:        reg |= ESS_AUDIO2_CTRL1_DEMAND_8;
        !          1422:        reg |= ESS_AUDIO2_CTRL1_DAC_ENABLE | ESS_AUDIO2_CTRL1_FIFO_ENABLE |
        !          1423:               ESS_AUDIO2_CTRL1_AUTO_INIT;
        !          1424:        ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL1, reg);
        !          1425:
        !          1426:        return (0);
        !          1427: }
        !          1428:
        !          1429: int
        !          1430: ess_audio1_trigger_input(addr, start, end, blksize, intr, arg, param)
        !          1431:        void *addr;
        !          1432:        void *start, *end;
        !          1433:        int blksize;
        !          1434:        void (*intr)(void *);
        !          1435:        void *arg;
        !          1436:        struct audio_params *param;
        !          1437: {
        !          1438:        struct ess_softc *sc = addr;
        !          1439:        u_int8_t reg;
        !          1440:
        !          1441:        DPRINTFN(1, ("ess_audio1_trigger_input: sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
        !          1442:            addr, start, end, blksize, intr, arg));
        !          1443:
        !          1444:        if (sc->sc_audio1.active)
        !          1445:                panic("ess_audio1_trigger_input: already running");
        !          1446:
        !          1447:        sc->sc_audio1.active = 1;
        !          1448:        sc->sc_audio1.intr = intr;
        !          1449:        sc->sc_audio1.arg = arg;
        !          1450:        if (sc->sc_audio1.polled) {
        !          1451:                sc->sc_audio1.dmapos = 0;
        !          1452:                sc->sc_audio1.buffersize = (char *)end - (char *)start;
        !          1453:                sc->sc_audio1.dmacount = 0;
        !          1454:                sc->sc_audio1.blksize = blksize;
        !          1455:                timeout_add(&sc->sc_tmo1, hz/30);
        !          1456:        }
        !          1457:
        !          1458:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
        !          1459:        if (param->channels == 2) {
        !          1460:                reg &= ~ESS_AUDIO_CTRL_MONO;
        !          1461:                reg |= ESS_AUDIO_CTRL_STEREO;
        !          1462:        } else {
        !          1463:                reg |= ESS_AUDIO_CTRL_MONO;
        !          1464:                reg &= ~ESS_AUDIO_CTRL_STEREO;
        !          1465:        }
        !          1466:        ess_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
        !          1467:
        !          1468:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
        !          1469:        if (param->precision * param->factor == 16)
        !          1470:                reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
        !          1471:        else
        !          1472:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
        !          1473:        if (param->channels == 2)
        !          1474:                reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
        !          1475:        else
        !          1476:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
        !          1477:        if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
        !          1478:            param->encoding == AUDIO_ENCODING_SLINEAR_LE)
        !          1479:                reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
        !          1480:        else
        !          1481:                reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
        !          1482:        reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
        !          1483:        ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
        !          1484:
        !          1485:        isa_dmastart(sc->sc_isa, sc->sc_audio1.drq, start,
        !          1486:                     (char *)end - (char *)start, NULL,
        !          1487:            DMAMODE_READ | DMAMODE_LOOP, BUS_DMA_NOWAIT);
        !          1488:
        !          1489:        /* Program transfer count registers with 2's complement of count. */
        !          1490:        blksize = -blksize;
        !          1491:        ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, blksize);
        !          1492:        ess_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, blksize >> 8);
        !          1493:
        !          1494:        /* Use 4 bytes per input DMA. */
        !          1495:        ess_set_xreg_bits(sc, ESS_XCMD_DEMAND_CTRL, ESS_DEMAND_CTRL_DEMAND_4);
        !          1496:
        !          1497:        /* Start auto-init DMA */
        !          1498:        ess_wdsp(sc, ESS_ACMD_DISABLE_SPKR);
        !          1499:        reg = ess_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
        !          1500:        reg |= ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE;
        !          1501:        reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
        !          1502:        ess_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
        !          1503:
        !          1504:        return (0);
        !          1505: }
        !          1506:
        !          1507: int
        !          1508: ess_audio1_halt(addr)
        !          1509:        void *addr;
        !          1510: {
        !          1511:        struct ess_softc *sc = addr;
        !          1512:
        !          1513:        DPRINTF(("ess_audio1_halt: sc=%p\n", sc));
        !          1514:
        !          1515:        if (sc->sc_audio1.active) {
        !          1516:                ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
        !          1517:                    ESS_AUDIO1_CTRL2_FIFO_ENABLE);
        !          1518:                isa_dmaabort(sc->sc_isa, sc->sc_audio1.drq);
        !          1519:                if (sc->sc_audio1.polled)
        !          1520:                        timeout_del(&sc->sc_tmo1);
        !          1521:                sc->sc_audio1.active = 0;
        !          1522:        }
        !          1523:
        !          1524:        return (0);
        !          1525: }
        !          1526:
        !          1527: int
        !          1528: ess_audio2_halt(addr)
        !          1529:        void *addr;
        !          1530: {
        !          1531:        struct ess_softc *sc = addr;
        !          1532:
        !          1533:        DPRINTF(("ess_audio2_halt: sc=%p\n", sc));
        !          1534:
        !          1535:        if (sc->sc_audio2.active) {
        !          1536:                ess_clear_mreg_bits(sc, ESS_MREG_AUDIO2_CTRL1,
        !          1537:                    ESS_AUDIO2_CTRL1_DAC_ENABLE |
        !          1538:                    ESS_AUDIO2_CTRL1_FIFO_ENABLE);
        !          1539:                isa_dmaabort(sc->sc_isa, sc->sc_audio2.drq);
        !          1540:                if (sc->sc_audio2.polled)
        !          1541:                        timeout_del(&sc->sc_tmo2);
        !          1542:                sc->sc_audio2.active = 0;
        !          1543:        }
        !          1544:
        !          1545:        return (0);
        !          1546: }
        !          1547:
        !          1548: int
        !          1549: ess_audio1_intr(arg)
        !          1550:        void *arg;
        !          1551: {
        !          1552:        struct ess_softc *sc = arg;
        !          1553:        u_int8_t reg;
        !          1554:
        !          1555:        DPRINTFN(1,("ess_audio1_intr: intr=%p\n", sc->sc_audio1.intr));
        !          1556:
        !          1557:        /* Check and clear interrupt on Audio1. */
        !          1558:        reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_RW_STATUS);
        !          1559:        if ((reg & ESS_DSP_READ_OFLOW) == 0)
        !          1560:                return (0);
        !          1561:        reg = EREAD1(sc->sc_iot, sc->sc_ioh, ESS_CLEAR_INTR);
        !          1562:
        !          1563:        sc->sc_audio1.nintr++;
        !          1564:
        !          1565:        if (sc->sc_audio1.active) {
        !          1566:                (*sc->sc_audio1.intr)(sc->sc_audio1.arg);
        !          1567:                return (1);
        !          1568:        } else
        !          1569:                return (0);
        !          1570: }
        !          1571:
        !          1572: int
        !          1573: ess_audio2_intr(arg)
        !          1574:        void *arg;
        !          1575: {
        !          1576:        struct ess_softc *sc = arg;
        !          1577:        u_int8_t reg;
        !          1578:
        !          1579:        DPRINTFN(1,("ess_audio2_intr: intr=%p\n", sc->sc_audio2.intr));
        !          1580:
        !          1581:        /* Check and clear interrupt on Audio2. */
        !          1582:        reg = ess_read_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2);
        !          1583:        if ((reg & ESS_AUDIO2_CTRL2_IRQ_LATCH) == 0)
        !          1584:                return (0);
        !          1585:        reg &= ~ESS_AUDIO2_CTRL2_IRQ_LATCH;
        !          1586:        ess_write_mix_reg(sc, ESS_MREG_AUDIO2_CTRL2, reg);
        !          1587:
        !          1588:        sc->sc_audio2.nintr++;
        !          1589:
        !          1590:        if (sc->sc_audio2.active) {
        !          1591:                (*sc->sc_audio2.intr)(sc->sc_audio2.arg);
        !          1592:                return (1);
        !          1593:        } else
        !          1594:                return (0);
        !          1595: }
        !          1596:
        !          1597: void
        !          1598: ess_audio1_poll(addr)
        !          1599:        void *addr;
        !          1600: {
        !          1601:        struct ess_softc *sc = addr;
        !          1602:        int dmapos, dmacount;
        !          1603:
        !          1604:        if (!sc->sc_audio1.active)
        !          1605:                return;
        !          1606:
        !          1607:        sc->sc_audio1.nintr++;
        !          1608:
        !          1609:        dmapos = isa_dmacount(sc->sc_isa, sc->sc_audio1.drq);
        !          1610:        dmacount = sc->sc_audio1.dmapos - dmapos;
        !          1611:        if (dmacount < 0)
        !          1612:                dmacount += sc->sc_audio1.buffersize;
        !          1613:        sc->sc_audio1.dmapos = dmapos;
        !          1614: #if 1
        !          1615:        dmacount += sc->sc_audio1.dmacount;
        !          1616:        while (dmacount > sc->sc_audio1.blksize) {
        !          1617:                dmacount -= sc->sc_audio1.blksize;
        !          1618:                (*sc->sc_audio1.intr)(sc->sc_audio1.arg);
        !          1619:        }
        !          1620:        sc->sc_audio1.dmacount = dmacount;
        !          1621: #else
        !          1622:        (*sc->sc_audio1.intr)(sc->sc_audio1.arg, dmacount);
        !          1623: #endif
        !          1624:
        !          1625:        timeout_add(&sc->sc_tmo1, hz/30);
        !          1626: }
        !          1627:
        !          1628: void
        !          1629: ess_audio2_poll(addr)
        !          1630:        void *addr;
        !          1631: {
        !          1632:        struct ess_softc *sc = addr;
        !          1633:        int dmapos, dmacount;
        !          1634:
        !          1635:        if (!sc->sc_audio2.active)
        !          1636:                return;
        !          1637:
        !          1638:        sc->sc_audio2.nintr++;
        !          1639:
        !          1640:        dmapos = isa_dmacount(sc->sc_isa, sc->sc_audio2.drq);
        !          1641:        dmacount = sc->sc_audio2.dmapos - dmapos;
        !          1642:        if (dmacount < 0)
        !          1643:                dmacount += sc->sc_audio2.buffersize;
        !          1644:        sc->sc_audio2.dmapos = dmapos;
        !          1645: #if 1
        !          1646:        dmacount += sc->sc_audio2.dmacount;
        !          1647:        while (dmacount > sc->sc_audio2.blksize) {
        !          1648:                dmacount -= sc->sc_audio2.blksize;
        !          1649:                (*sc->sc_audio2.intr)(sc->sc_audio2.arg);
        !          1650:        }
        !          1651:        sc->sc_audio2.dmacount = dmacount;
        !          1652: #else
        !          1653:        (*sc->sc_audio2.intr)(sc->sc_audio2.arg, dmacount);
        !          1654: #endif
        !          1655:
        !          1656:        timeout_add(&sc->sc_tmo2, hz/30);
        !          1657: }
        !          1658:
        !          1659: int
        !          1660: ess_round_blocksize(addr, blk)
        !          1661:        void *addr;
        !          1662:        int blk;
        !          1663: {
        !          1664:        return ((blk + 7) & -8);        /* round for max DMA size */
        !          1665: }
        !          1666:
        !          1667: int
        !          1668: ess_set_port(addr, cp)
        !          1669:        void *addr;
        !          1670:        mixer_ctrl_t *cp;
        !          1671: {
        !          1672:        struct ess_softc *sc = addr;
        !          1673:        int lgain, rgain;
        !          1674:
        !          1675:        DPRINTFN(5,("ess_set_port: port=%d num_channels=%d\n",
        !          1676:                    cp->dev, cp->un.value.num_channels));
        !          1677:
        !          1678:        switch (cp->dev) {
        !          1679:        /*
        !          1680:         * The following mixer ports are all stereo. If we get a
        !          1681:         * single-channel gain value passed in, then we duplicate it
        !          1682:         * to both left and right channels.
        !          1683:         */
        !          1684:        case ESS_MASTER_VOL:
        !          1685:        case ESS_DAC_PLAY_VOL:
        !          1686:        case ESS_MIC_PLAY_VOL:
        !          1687:        case ESS_LINE_PLAY_VOL:
        !          1688:        case ESS_SYNTH_PLAY_VOL:
        !          1689:        case ESS_CD_PLAY_VOL:
        !          1690:        case ESS_AUXB_PLAY_VOL:
        !          1691:        case ESS_RECORD_VOL:
        !          1692:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1693:                        return EINVAL;
        !          1694:
        !          1695:                switch (cp->un.value.num_channels) {
        !          1696:                case 1:
        !          1697:                        lgain = rgain = ESS_4BIT_GAIN(
        !          1698:                          cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1699:                        break;
        !          1700:                case 2:
        !          1701:                        lgain = ESS_4BIT_GAIN(
        !          1702:                          cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
        !          1703:                        rgain = ESS_4BIT_GAIN(
        !          1704:                          cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
        !          1705:                        break;
        !          1706:                default:
        !          1707:                        return EINVAL;
        !          1708:                }
        !          1709:
        !          1710:                sc->gain[cp->dev][ESS_LEFT]  = lgain;
        !          1711:                sc->gain[cp->dev][ESS_RIGHT] = rgain;
        !          1712:                ess_set_gain(sc, cp->dev, 1);
        !          1713:                return (0);
        !          1714:
        !          1715:        /*
        !          1716:         * The PC speaker port is mono. If we get a stereo gain value
        !          1717:         * passed in, then we return EINVAL.
        !          1718:         */
        !          1719:        case ESS_PCSPEAKER_VOL:
        !          1720:                if (cp->un.value.num_channels != 1)
        !          1721:                        return EINVAL;
        !          1722:
        !          1723:                sc->gain[cp->dev][ESS_LEFT] = sc->gain[cp->dev][ESS_RIGHT] =
        !          1724:                  ESS_3BIT_GAIN(cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1725:                ess_set_gain(sc, cp->dev, 1);
        !          1726:                return (0);
        !          1727:
        !          1728:        case ESS_RECORD_SOURCE:
        !          1729:                if (ESS_USE_AUDIO1(sc->sc_model)) {
        !          1730:                        if (cp->type == AUDIO_MIXER_ENUM)
        !          1731:                                return (ess_set_in_port(sc, cp->un.ord));
        !          1732:                        else
        !          1733:                                return (EINVAL);
        !          1734:                } else {
        !          1735:                        if (cp->type == AUDIO_MIXER_SET)
        !          1736:                                return (ess_set_in_ports(sc, cp->un.mask));
        !          1737:                        else
        !          1738:                                return (EINVAL);
        !          1739:                }
        !          1740:                return (0);
        !          1741:
        !          1742:        case ESS_RECORD_MONITOR:
        !          1743:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1744:                        return EINVAL;
        !          1745:
        !          1746:                if (cp->un.ord)
        !          1747:                        /* Enable monitor */
        !          1748:                        ess_set_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
        !          1749:                                          ESS_AUDIO_CTRL_MONITOR);
        !          1750:                else
        !          1751:                        /* Disable monitor */
        !          1752:                        ess_clear_xreg_bits(sc, ESS_XCMD_AUDIO_CTRL,
        !          1753:                                            ESS_AUDIO_CTRL_MONITOR);
        !          1754:                return (0);
        !          1755:        }
        !          1756:
        !          1757:        if (ESS_USE_AUDIO1(sc->sc_model))
        !          1758:                return (EINVAL);
        !          1759:
        !          1760:        switch (cp->dev) {
        !          1761:        case ESS_DAC_REC_VOL:
        !          1762:        case ESS_MIC_REC_VOL:
        !          1763:        case ESS_LINE_REC_VOL:
        !          1764:        case ESS_SYNTH_REC_VOL:
        !          1765:        case ESS_CD_REC_VOL:
        !          1766:        case ESS_AUXB_REC_VOL:
        !          1767:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1768:                        return EINVAL;
        !          1769:
        !          1770:                switch (cp->un.value.num_channels) {
        !          1771:                case 1:
        !          1772:                        lgain = rgain = ESS_4BIT_GAIN(
        !          1773:                          cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
        !          1774:                        break;
        !          1775:                case 2:
        !          1776:                        lgain = ESS_4BIT_GAIN(
        !          1777:                          cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
        !          1778:                        rgain = ESS_4BIT_GAIN(
        !          1779:                          cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
        !          1780:                        break;
        !          1781:                default:
        !          1782:                        return EINVAL;
        !          1783:                }
        !          1784:
        !          1785:                sc->gain[cp->dev][ESS_LEFT]  = lgain;
        !          1786:                sc->gain[cp->dev][ESS_RIGHT] = rgain;
        !          1787:                ess_set_gain(sc, cp->dev, 1);
        !          1788:                return (0);
        !          1789:
        !          1790:        case ESS_MIC_PREAMP:
        !          1791:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1792:                        return EINVAL;
        !          1793:
        !          1794:                if (cp->un.ord)
        !          1795:                        /* Enable microphone preamp */
        !          1796:                        ess_set_xreg_bits(sc, ESS_XCMD_PREAMP_CTRL,
        !          1797:                                          ESS_PREAMP_CTRL_ENABLE);
        !          1798:                else
        !          1799:                        /* Disable microphone preamp */
        !          1800:                        ess_clear_xreg_bits(sc, ESS_XCMD_PREAMP_CTRL,
        !          1801:                                          ESS_PREAMP_CTRL_ENABLE);
        !          1802:                return (0);
        !          1803:        }
        !          1804:
        !          1805:        return (EINVAL);
        !          1806: }
        !          1807:
        !          1808: int
        !          1809: ess_get_port(addr, cp)
        !          1810:        void *addr;
        !          1811:        mixer_ctrl_t *cp;
        !          1812: {
        !          1813:        struct ess_softc *sc = addr;
        !          1814:
        !          1815:        DPRINTFN(5,("ess_get_port: port=%d\n", cp->dev));
        !          1816:
        !          1817:        switch (cp->dev) {
        !          1818:        case ESS_MASTER_VOL:
        !          1819:        case ESS_DAC_PLAY_VOL:
        !          1820:        case ESS_MIC_PLAY_VOL:
        !          1821:        case ESS_LINE_PLAY_VOL:
        !          1822:        case ESS_SYNTH_PLAY_VOL:
        !          1823:        case ESS_CD_PLAY_VOL:
        !          1824:        case ESS_AUXB_PLAY_VOL:
        !          1825:        case ESS_RECORD_VOL:
        !          1826:                switch (cp->un.value.num_channels) {
        !          1827:                case 1:
        !          1828:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1829:                                sc->gain[cp->dev][ESS_LEFT];
        !          1830:                        break;
        !          1831:                case 2:
        !          1832:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1833:                                sc->gain[cp->dev][ESS_LEFT];
        !          1834:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1835:                                sc->gain[cp->dev][ESS_RIGHT];
        !          1836:                        break;
        !          1837:                default:
        !          1838:                        return EINVAL;
        !          1839:                }
        !          1840:                return (0);
        !          1841:
        !          1842:        case ESS_PCSPEAKER_VOL:
        !          1843:                if (cp->un.value.num_channels != 1)
        !          1844:                        return EINVAL;
        !          1845:
        !          1846:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1847:                        sc->gain[cp->dev][ESS_LEFT];
        !          1848:                return (0);
        !          1849:
        !          1850:        case ESS_RECORD_SOURCE:
        !          1851:                if (ESS_USE_AUDIO1(sc->sc_model))
        !          1852:                        cp->un.ord = sc->in_port;
        !          1853:                else
        !          1854:                        cp->un.mask = sc->in_mask;
        !          1855:                return (0);
        !          1856:
        !          1857:        case ESS_RECORD_MONITOR:
        !          1858:                cp->un.ord = (ess_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL) &
        !          1859:                              ESS_AUDIO_CTRL_MONITOR) ? 1 : 0;
        !          1860:                return (0);
        !          1861:        }
        !          1862:
        !          1863:        if (ESS_USE_AUDIO1(sc->sc_model))
        !          1864:                return (EINVAL);
        !          1865:
        !          1866:        switch (cp->dev) {
        !          1867:        case ESS_DAC_REC_VOL:
        !          1868:        case ESS_MIC_REC_VOL:
        !          1869:        case ESS_LINE_REC_VOL:
        !          1870:        case ESS_SYNTH_REC_VOL:
        !          1871:        case ESS_CD_REC_VOL:
        !          1872:        case ESS_AUXB_REC_VOL:
        !          1873:                switch (cp->un.value.num_channels) {
        !          1874:                case 1:
        !          1875:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1876:                                sc->gain[cp->dev][ESS_LEFT];
        !          1877:                        break;
        !          1878:                case 2:
        !          1879:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1880:                                sc->gain[cp->dev][ESS_LEFT];
        !          1881:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1882:                                sc->gain[cp->dev][ESS_RIGHT];
        !          1883:                        break;
        !          1884:                default:
        !          1885:                        return EINVAL;
        !          1886:                }
        !          1887:                return (0);
        !          1888:
        !          1889:        case ESS_MIC_PREAMP:
        !          1890:                cp->un.ord = (ess_read_x_reg(sc, ESS_XCMD_PREAMP_CTRL) &
        !          1891:                              ESS_PREAMP_CTRL_ENABLE) ? 1 : 0;
        !          1892:                return (0);
        !          1893:        }
        !          1894:
        !          1895:        return (EINVAL);
        !          1896: }
        !          1897:
        !          1898: int
        !          1899: ess_query_devinfo(addr, dip)
        !          1900:        void *addr;
        !          1901:        mixer_devinfo_t *dip;
        !          1902: {
        !          1903:        struct ess_softc *sc = addr;
        !          1904:
        !          1905:        DPRINTFN(5,("ess_query_devinfo: model=%d index=%d\n",
        !          1906:                    sc->sc_model, dip->index));
        !          1907:
        !          1908:        /*
        !          1909:         * REVISIT: There are some slight differences between the
        !          1910:         *          mixers on the different ESS chips, which can
        !          1911:         *          be sorted out using the chip model rather than a
        !          1912:         *          separate mixer model.
        !          1913:         *          This is currently coded assuming an ES1887; we
        !          1914:         *          need to work out which bits are not applicable to
        !          1915:         *          the other models (1888 and 888).
        !          1916:         */
        !          1917:        switch (dip->index) {
        !          1918:        case ESS_DAC_PLAY_VOL:
        !          1919:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1920:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1921:                strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          1922:                dip->type = AUDIO_MIXER_VALUE;
        !          1923:                dip->un.v.num_channels = 2;
        !          1924:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1925:                    sizeof dip->un.v.units.name);
        !          1926:                return (0);
        !          1927:
        !          1928:        case ESS_MIC_PLAY_VOL:
        !          1929:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1930:                dip->prev = AUDIO_MIXER_LAST;
        !          1931:                if (ESS_USE_AUDIO1(sc->sc_model))
        !          1932:                        dip->next = AUDIO_MIXER_LAST;
        !          1933:                else
        !          1934:                        dip->next = ESS_MIC_PREAMP;
        !          1935:                strlcpy(dip->label.name, AudioNmicrophone,
        !          1936:                    sizeof dip->label.name);
        !          1937:                dip->type = AUDIO_MIXER_VALUE;
        !          1938:                dip->un.v.num_channels = 2;
        !          1939:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1940:                    sizeof dip->un.v.units.name);
        !          1941:                return (0);
        !          1942:
        !          1943:        case ESS_LINE_PLAY_VOL:
        !          1944:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1945:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1946:                strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
        !          1947:                dip->type = AUDIO_MIXER_VALUE;
        !          1948:                dip->un.v.num_channels = 2;
        !          1949:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1950:                    sizeof dip->un.v.units.name);
        !          1951:                return (0);
        !          1952:
        !          1953:        case ESS_SYNTH_PLAY_VOL:
        !          1954:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1955:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1956:                strlcpy(dip->label.name, AudioNfmsynth,
        !          1957:                    sizeof dip->label.name);
        !          1958:                dip->type = AUDIO_MIXER_VALUE;
        !          1959:                dip->un.v.num_channels = 2;
        !          1960:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1961:                    sizeof dip->un.v.units.name);
        !          1962:                return (0);
        !          1963:
        !          1964:        case ESS_CD_PLAY_VOL:
        !          1965:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1966:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1967:                strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          1968:                dip->type = AUDIO_MIXER_VALUE;
        !          1969:                dip->un.v.num_channels = 2;
        !          1970:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1971:                    sizeof dip->un.v.units.name);
        !          1972:                return (0);
        !          1973:
        !          1974:        case ESS_AUXB_PLAY_VOL:
        !          1975:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1976:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1977:                strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
        !          1978:                dip->type = AUDIO_MIXER_VALUE;
        !          1979:                dip->un.v.num_channels = 2;
        !          1980:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1981:                    sizeof dip->un.v.units.name);
        !          1982:                return (0);
        !          1983:
        !          1984:        case ESS_INPUT_CLASS:
        !          1985:                dip->mixer_class = ESS_INPUT_CLASS;
        !          1986:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1987:                strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
        !          1988:                dip->type = AUDIO_MIXER_CLASS;
        !          1989:                return (0);
        !          1990:
        !          1991:        case ESS_MASTER_VOL:
        !          1992:                dip->mixer_class = ESS_OUTPUT_CLASS;
        !          1993:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1994:                strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
        !          1995:                dip->type = AUDIO_MIXER_VALUE;
        !          1996:                dip->un.v.num_channels = 2;
        !          1997:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1998:                    sizeof dip->un.v.units.name);
        !          1999:                return (0);
        !          2000:
        !          2001:        case ESS_PCSPEAKER_VOL:
        !          2002:                dip->mixer_class = ESS_OUTPUT_CLASS;
        !          2003:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2004:                strlcpy(dip->label.name, "pc_speaker", sizeof dip->label.name);
        !          2005:                dip->type = AUDIO_MIXER_VALUE;
        !          2006:                dip->un.v.num_channels = 1;
        !          2007:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2008:                    sizeof dip->un.v.units.name);
        !          2009:                return (0);
        !          2010:
        !          2011:        case ESS_OUTPUT_CLASS:
        !          2012:                dip->mixer_class = ESS_OUTPUT_CLASS;
        !          2013:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2014:                strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
        !          2015:                dip->type = AUDIO_MIXER_CLASS;
        !          2016:                return (0);
        !          2017:
        !          2018:        case ESS_RECORD_VOL:
        !          2019:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2020:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2021:                strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
        !          2022:                dip->type = AUDIO_MIXER_VALUE;
        !          2023:                dip->un.v.num_channels = 2;
        !          2024:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2025:                    sizeof dip->un.v.units.name);
        !          2026:                return (0);
        !          2027:
        !          2028:        case ESS_RECORD_SOURCE:
        !          2029:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2030:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2031:                strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
        !          2032:                if (ESS_USE_AUDIO1(sc->sc_model)) {
        !          2033:                        /*
        !          2034:                         * The 1788 doesn't use the input mixer control that
        !          2035:                         * the 1888 uses, because it's a pain when you only
        !          2036:                         * have one mixer.
        !          2037:                         * Perhaps it could be emulated by keeping both sets of
        !          2038:                         * gain values, and doing a `context switch' of the
        !          2039:                         * mixer registers when shifting from playing to
        !          2040:                         * recording.
        !          2041:                         */
        !          2042:                        dip->type = AUDIO_MIXER_ENUM;
        !          2043:                        dip->un.e.num_mem = 4;
        !          2044:                        strlcpy(dip->un.e.member[0].label.name,
        !          2045:                            AudioNmicrophone,
        !          2046:                            sizeof dip->un.e.member[0].label.name);
        !          2047:                        dip->un.e.member[0].ord = ESS_SOURCE_MIC;
        !          2048:                        strlcpy(dip->un.e.member[1].label.name, AudioNline,
        !          2049:                            sizeof dip->un.e.member[1].label.name);
        !          2050:                        dip->un.e.member[1].ord = ESS_SOURCE_LINE;
        !          2051:                        strlcpy(dip->un.e.member[2].label.name, AudioNcd,
        !          2052:                            sizeof dip->un.e.member[2].label.name);
        !          2053:                        dip->un.e.member[2].ord = ESS_SOURCE_CD;
        !          2054:                        strlcpy(dip->un.e.member[3].label.name, AudioNmixerout,
        !          2055:                            sizeof dip->un.e.member[3].label.name);
        !          2056:                        dip->un.e.member[3].ord = ESS_SOURCE_MIXER;
        !          2057:                } else {
        !          2058:                        dip->type = AUDIO_MIXER_SET;
        !          2059:                        dip->un.s.num_mem = 6;
        !          2060:                        strlcpy(dip->un.s.member[0].label.name, AudioNdac,
        !          2061:                            sizeof dip->un.e.member[0].label.name);
        !          2062:                        dip->un.s.member[0].mask = 1 << ESS_DAC_REC_VOL;
        !          2063:                        strlcpy(dip->un.s.member[1].label.name,
        !          2064:                            AudioNmicrophone,
        !          2065:                            sizeof dip->un.e.member[1].label.name);
        !          2066:                        dip->un.s.member[1].mask = 1 << ESS_MIC_REC_VOL;
        !          2067:                        strlcpy(dip->un.s.member[2].label.name, AudioNline,
        !          2068:                            sizeof dip->un.e.member[2].label.name);
        !          2069:                        dip->un.s.member[2].mask = 1 << ESS_LINE_REC_VOL;
        !          2070:                        strlcpy(dip->un.s.member[3].label.name, AudioNfmsynth,
        !          2071:                            sizeof dip->un.e.member[3].label.name);
        !          2072:                        dip->un.s.member[3].mask = 1 << ESS_SYNTH_REC_VOL;
        !          2073:                        strlcpy(dip->un.s.member[4].label.name, AudioNcd,
        !          2074:                            sizeof dip->un.e.member[4].label.name);
        !          2075:                        dip->un.s.member[4].mask = 1 << ESS_CD_REC_VOL;
        !          2076:                        strlcpy(dip->un.s.member[5].label.name, "auxb",
        !          2077:                            sizeof dip->un.e.member[5].label.name);
        !          2078:                        dip->un.s.member[5].mask = 1 << ESS_AUXB_REC_VOL;
        !          2079:                }
        !          2080:                return (0);
        !          2081:
        !          2082:        case ESS_RECORD_CLASS:
        !          2083:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2084:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2085:                strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
        !          2086:                dip->type = AUDIO_MIXER_CLASS;
        !          2087:                return (0);
        !          2088:
        !          2089:        case ESS_RECORD_MONITOR:
        !          2090:                dip->prev = dip->next = AUDIO_MIXER_LAST;
        !          2091:                strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
        !          2092:                dip->type = AUDIO_MIXER_ENUM;
        !          2093:                dip->mixer_class = ESS_MONITOR_CLASS;
        !          2094:                dip->un.e.num_mem = 2;
        !          2095:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          2096:                    sizeof dip->un.e.member[0].label.name);
        !          2097:                dip->un.e.member[0].ord = 0;
        !          2098:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          2099:                    sizeof dip->un.e.member[1].label.name);
        !          2100:                dip->un.e.member[1].ord = 1;
        !          2101:                return (0);
        !          2102:
        !          2103:        case ESS_MONITOR_CLASS:
        !          2104:                dip->mixer_class = ESS_MONITOR_CLASS;
        !          2105:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2106:                strlcpy(dip->label.name, AudioCmonitor,
        !          2107:                    sizeof dip->label.name);
        !          2108:                dip->type = AUDIO_MIXER_CLASS;
        !          2109:                return (0);
        !          2110:        }
        !          2111:
        !          2112:        if (ESS_USE_AUDIO1(sc->sc_model))
        !          2113:                return (ENXIO);
        !          2114:
        !          2115:        switch (dip->index) {
        !          2116:        case ESS_DAC_REC_VOL:
        !          2117:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2118:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2119:                strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          2120:                dip->type = AUDIO_MIXER_VALUE;
        !          2121:                dip->un.v.num_channels = 2;
        !          2122:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2123:                    sizeof dip->un.v.units.name);
        !          2124:                return (0);
        !          2125:
        !          2126:        case ESS_MIC_REC_VOL:
        !          2127:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2128:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2129:                strlcpy(dip->label.name, AudioNmicrophone,
        !          2130:                    sizeof dip->label.name);
        !          2131:                dip->type = AUDIO_MIXER_VALUE;
        !          2132:                dip->un.v.num_channels = 2;
        !          2133:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2134:                    sizeof dip->un.v.units.name);
        !          2135:                return (0);
        !          2136:
        !          2137:        case ESS_LINE_REC_VOL:
        !          2138:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2139:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2140:                strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
        !          2141:                dip->type = AUDIO_MIXER_VALUE;
        !          2142:                dip->un.v.num_channels = 2;
        !          2143:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2144:                    sizeof dip->un.v.units.name);
        !          2145:                return (0);
        !          2146:
        !          2147:        case ESS_SYNTH_REC_VOL:
        !          2148:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2149:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2150:                strlcpy(dip->label.name, AudioNfmsynth,
        !          2151:                    sizeof dip->label.name);
        !          2152:                dip->type = AUDIO_MIXER_VALUE;
        !          2153:                dip->un.v.num_channels = 2;
        !          2154:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2155:                    sizeof dip->un.v.units.name);
        !          2156:                return (0);
        !          2157:
        !          2158:        case ESS_CD_REC_VOL:
        !          2159:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2160:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2161:                strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          2162:                dip->type = AUDIO_MIXER_VALUE;
        !          2163:                dip->un.v.num_channels = 2;
        !          2164:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2165:                    sizeof dip->un.v.units.name);
        !          2166:                return (0);
        !          2167:
        !          2168:        case ESS_AUXB_REC_VOL:
        !          2169:                dip->mixer_class = ESS_RECORD_CLASS;
        !          2170:                dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          2171:                strlcpy(dip->label.name, "auxb", sizeof dip->label.name);
        !          2172:                dip->type = AUDIO_MIXER_VALUE;
        !          2173:                dip->un.v.num_channels = 2;
        !          2174:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          2175:                    sizeof dip->un.v.units.name);
        !          2176:                return (0);
        !          2177:
        !          2178:        case ESS_MIC_PREAMP:
        !          2179:                dip->mixer_class = ESS_INPUT_CLASS;
        !          2180:                dip->prev = ESS_MIC_PLAY_VOL;
        !          2181:                dip->next = AUDIO_MIXER_LAST;
        !          2182:                strlcpy(dip->label.name, AudioNpreamp, sizeof dip->label.name);
        !          2183:                dip->type = AUDIO_MIXER_ENUM;
        !          2184:                dip->un.e.num_mem = 2;
        !          2185:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          2186:                    sizeof dip->un.e.member[0].label.name);
        !          2187:                dip->un.e.member[0].ord = 0;
        !          2188:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          2189:                    sizeof dip->un.e.member[1].label.name);
        !          2190:                dip->un.e.member[1].ord = 1;
        !          2191:                return (0);
        !          2192:        }
        !          2193:
        !          2194:        return (ENXIO);
        !          2195: }
        !          2196:
        !          2197: void *
        !          2198: ess_malloc(addr, direction, size, pool, flags)
        !          2199:        void *addr;
        !          2200:        int direction;
        !          2201:        size_t size;
        !          2202:        int pool, flags;
        !          2203: {
        !          2204:        struct ess_softc *sc = addr;
        !          2205:        int drq;
        !          2206:
        !          2207:        if (!ESS_USE_AUDIO1(sc->sc_model))
        !          2208:                drq = sc->sc_audio2.drq;
        !          2209:        else
        !          2210:                drq = sc->sc_audio1.drq;
        !          2211:        return (isa_malloc(sc->sc_isa, drq, size, pool, flags));
        !          2212: }
        !          2213:
        !          2214: void
        !          2215: ess_free(addr, ptr, pool)
        !          2216:        void *addr;
        !          2217:        void *ptr;
        !          2218:        int pool;
        !          2219: {
        !          2220:        isa_free(ptr, pool);
        !          2221: }
        !          2222:
        !          2223: size_t
        !          2224: ess_round_buffersize(addr, direction, size)
        !          2225:        void *addr;
        !          2226:        int direction;
        !          2227:        size_t size;
        !          2228: {
        !          2229:        if (size > MAX_ISADMA)
        !          2230:                size = MAX_ISADMA;
        !          2231:        return (size);
        !          2232: }
        !          2233:
        !          2234: paddr_t
        !          2235: ess_mappage(addr, mem, off, prot)
        !          2236:        void *addr;
        !          2237:        void *mem;
        !          2238:        off_t off;
        !          2239:        int prot;
        !          2240: {
        !          2241:        return (isa_mappage(mem, off, prot));
        !          2242: }
        !          2243:
        !          2244: int
        !          2245: ess_1788_get_props(addr)
        !          2246:        void *addr;
        !          2247: {
        !          2248:
        !          2249:        return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT);
        !          2250: }
        !          2251:
        !          2252: int
        !          2253: ess_1888_get_props(addr)
        !          2254:        void *addr;
        !          2255: {
        !          2256:
        !          2257:        return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
        !          2258: }
        !          2259:
        !          2260: /* ============================================
        !          2261:  * Generic functions for ess, not used by audio h/w i/f
        !          2262:  * =============================================
        !          2263:  */
        !          2264:
        !          2265: /*
        !          2266:  * Reset the chip.
        !          2267:  * Return non-zero if the chip isn't detected.
        !          2268:  */
        !          2269: int
        !          2270: ess_reset(sc)
        !          2271:        struct ess_softc *sc;
        !          2272: {
        !          2273:        bus_space_tag_t iot = sc->sc_iot;
        !          2274:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2275:
        !          2276:        sc->sc_audio1.active = 0;
        !          2277:        sc->sc_audio2.active = 0;
        !          2278:
        !          2279:        EWRITE1(iot, ioh, ESS_DSP_RESET, ESS_RESET_EXT);
        !          2280:        delay(10000);
        !          2281:        EWRITE1(iot, ioh, ESS_DSP_RESET, 0);
        !          2282:        if (ess_rdsp(sc) != ESS_MAGIC)
        !          2283:                return (1);
        !          2284:
        !          2285:        /* Enable access to the ESS extension commands. */
        !          2286:        ess_wdsp(sc, ESS_ACMD_ENABLE_EXT);
        !          2287:
        !          2288:        return (0);
        !          2289: }
        !          2290:
        !          2291: void
        !          2292: ess_set_gain(sc, port, on)
        !          2293:        struct ess_softc *sc;
        !          2294:        int port;
        !          2295:        int on;
        !          2296: {
        !          2297:        int gain, left, right;
        !          2298:        int mix;
        !          2299:        int src;
        !          2300:        int stereo;
        !          2301:
        !          2302:        /*
        !          2303:         * Most gain controls are found in the mixer registers and
        !          2304:         * are stereo. Any that are not, must set mix and stereo as
        !          2305:         * required.
        !          2306:         */
        !          2307:        mix = 1;
        !          2308:        stereo = 1;
        !          2309:
        !          2310:        switch (port) {
        !          2311:        case ESS_MASTER_VOL:
        !          2312:                src = ESS_MREG_VOLUME_MASTER;
        !          2313:                break;
        !          2314:        case ESS_DAC_PLAY_VOL:
        !          2315:                if (ESS_USE_AUDIO1(sc->sc_model))
        !          2316:                        src = ESS_MREG_VOLUME_VOICE;
        !          2317:                else
        !          2318:                        src = 0x7C;
        !          2319:                break;
        !          2320:        case ESS_MIC_PLAY_VOL:
        !          2321:                src = ESS_MREG_VOLUME_MIC;
        !          2322:                break;
        !          2323:        case ESS_LINE_PLAY_VOL:
        !          2324:                src = ESS_MREG_VOLUME_LINE;
        !          2325:                break;
        !          2326:        case ESS_SYNTH_PLAY_VOL:
        !          2327:                src = ESS_MREG_VOLUME_SYNTH;
        !          2328:                break;
        !          2329:        case ESS_CD_PLAY_VOL:
        !          2330:                src = ESS_MREG_VOLUME_CD;
        !          2331:                break;
        !          2332:        case ESS_AUXB_PLAY_VOL:
        !          2333:                src = ESS_MREG_VOLUME_AUXB;
        !          2334:                break;
        !          2335:        case ESS_PCSPEAKER_VOL:
        !          2336:                src = ESS_MREG_VOLUME_PCSPKR;
        !          2337:                stereo = 0;
        !          2338:                break;
        !          2339:        case ESS_DAC_REC_VOL:
        !          2340:                src = 0x69;
        !          2341:                break;
        !          2342:        case ESS_MIC_REC_VOL:
        !          2343:                src = 0x68;
        !          2344:                break;
        !          2345:        case ESS_LINE_REC_VOL:
        !          2346:                src = 0x6E;
        !          2347:                break;
        !          2348:        case ESS_SYNTH_REC_VOL:
        !          2349:                src = 0x6B;
        !          2350:                break;
        !          2351:        case ESS_CD_REC_VOL:
        !          2352:                src = 0x6A;
        !          2353:                break;
        !          2354:        case ESS_AUXB_REC_VOL:
        !          2355:                src = 0x6C;
        !          2356:                break;
        !          2357:        case ESS_RECORD_VOL:
        !          2358:                src = ESS_XCMD_VOLIN_CTRL;
        !          2359:                mix = 0;
        !          2360:                break;
        !          2361:        default:
        !          2362:                return;
        !          2363:        }
        !          2364:
        !          2365:        /* 1788 doesn't have a separate recording mixer */
        !          2366:        if (ESS_USE_AUDIO1(sc->sc_model) && mix && src > 0x62)
        !          2367:                return;
        !          2368:
        !          2369:        if (on) {
        !          2370:                left = sc->gain[port][ESS_LEFT];
        !          2371:                right = sc->gain[port][ESS_RIGHT];
        !          2372:        } else {
        !          2373:                left = right = 0;
        !          2374:        }
        !          2375:
        !          2376:        if (stereo)
        !          2377:                gain = ESS_STEREO_GAIN(left, right);
        !          2378:        else
        !          2379:                gain = ESS_MONO_GAIN(left);
        !          2380:
        !          2381:        if (mix)
        !          2382:                ess_write_mix_reg(sc, src, gain);
        !          2383:        else
        !          2384:                ess_write_x_reg(sc, src, gain);
        !          2385: }
        !          2386:
        !          2387: /* Set the input device on devices without an input mixer. */
        !          2388: int
        !          2389: ess_set_in_port(sc, ord)
        !          2390:        struct ess_softc *sc;
        !          2391:        int ord;
        !          2392: {
        !          2393:        mixer_devinfo_t di;
        !          2394:        int i;
        !          2395:
        !          2396:        DPRINTF(("ess_set_in_port: ord=0x%x\n", ord));
        !          2397:
        !          2398:        /*
        !          2399:         * Get the device info for the record source control,
        !          2400:         * including the list of available sources.
        !          2401:         */
        !          2402:        di.index = ESS_RECORD_SOURCE;
        !          2403:        if (ess_query_devinfo(sc, &di))
        !          2404:                return EINVAL;
        !          2405:
        !          2406:        /* See if the given ord value was anywhere in the list. */
        !          2407:        for (i = 0; i < di.un.e.num_mem; i++) {
        !          2408:                if (ord == di.un.e.member[i].ord)
        !          2409:                        break;
        !          2410:        }
        !          2411:        if (i == di.un.e.num_mem)
        !          2412:                return EINVAL;
        !          2413:
        !          2414:        ess_write_mix_reg(sc, ESS_MREG_ADC_SOURCE, ord);
        !          2415:
        !          2416:        sc->in_port = ord;
        !          2417:        return (0);
        !          2418: }
        !          2419:
        !          2420: /* Set the input device levels on input-mixer-enabled devices. */
        !          2421: int
        !          2422: ess_set_in_ports(sc, mask)
        !          2423:        struct ess_softc *sc;
        !          2424:        int mask;
        !          2425: {
        !          2426:        mixer_devinfo_t di;
        !          2427:        int i, port;
        !          2428:
        !          2429:        DPRINTF(("ess_set_in_ports: mask=0x%x\n", mask));
        !          2430:
        !          2431:        /*
        !          2432:         * Get the device info for the record source control,
        !          2433:         * including the list of available sources.
        !          2434:         */
        !          2435:        di.index = ESS_RECORD_SOURCE;
        !          2436:        if (ess_query_devinfo(sc, &di))
        !          2437:                return EINVAL;
        !          2438:
        !          2439:        /*
        !          2440:         * Set or disable the record volume control for each of the
        !          2441:         * possible sources.
        !          2442:         */
        !          2443:        for (i = 0; i < di.un.s.num_mem; i++) {
        !          2444:                /*
        !          2445:                 * Calculate the source port number from its mask.
        !          2446:                 */
        !          2447:                port = ffs(di.un.s.member[i].mask);
        !          2448:
        !          2449:                /*
        !          2450:                 * Set the source gain:
        !          2451:                 *      to the current value if source is enabled
        !          2452:                 *      to zero if source is disabled
        !          2453:                 */
        !          2454:                ess_set_gain(sc, port, mask & di.un.s.member[i].mask);
        !          2455:        }
        !          2456:
        !          2457:        sc->in_mask = mask;
        !          2458:        return (0);
        !          2459: }
        !          2460:
        !          2461: void
        !          2462: ess_speaker_on(sc)
        !          2463:        struct ess_softc *sc;
        !          2464: {
        !          2465:        /* Unmute the DAC. */
        !          2466:        ess_set_gain(sc, ESS_DAC_PLAY_VOL, 1);
        !          2467: }
        !          2468:
        !          2469: void
        !          2470: ess_speaker_off(sc)
        !          2471:        struct ess_softc *sc;
        !          2472: {
        !          2473:        /* Mute the DAC. */
        !          2474:        ess_set_gain(sc, ESS_DAC_PLAY_VOL, 0);
        !          2475: }
        !          2476:
        !          2477: /*
        !          2478:  * Calculate the time constant for the requested sampling rate.
        !          2479:  */
        !          2480: u_int
        !          2481: ess_srtotc(rate)
        !          2482:        u_int rate;
        !          2483: {
        !          2484:        u_int tc;
        !          2485:
        !          2486:        /* The following formulae are from the ESS data sheet. */
        !          2487:        if (rate <= 22050)
        !          2488:                tc = 128 - 397700L / rate;
        !          2489:        else
        !          2490:                tc = 256 - 795500L / rate;
        !          2491:
        !          2492:        return (tc);
        !          2493: }
        !          2494:
        !          2495:
        !          2496: /*
        !          2497:  * Calculate the filter constant for the reuqested sampling rate.
        !          2498:  */
        !          2499: u_int
        !          2500: ess_srtofc(rate)
        !          2501:        u_int rate;
        !          2502: {
        !          2503:        /*
        !          2504:         * The following formula is derived from the information in
        !          2505:         * the ES1887 data sheet, based on a roll-off frequency of
        !          2506:         * 87%.
        !          2507:         */
        !          2508:        return (256 - 200279L / rate);
        !          2509: }
        !          2510:
        !          2511:
        !          2512: /*
        !          2513:  * Return the status of the DSP.
        !          2514:  */
        !          2515: u_char
        !          2516: ess_get_dsp_status(sc)
        !          2517:        struct ess_softc *sc;
        !          2518: {
        !          2519:        return (EREAD1(sc->sc_iot, sc->sc_ioh, ESS_DSP_RW_STATUS));
        !          2520: }
        !          2521:
        !          2522:
        !          2523: /*
        !          2524:  * Return the read status of the DSP:  1 -> DSP ready for reading
        !          2525:  *                                     0 -> DSP not ready for reading
        !          2526:  */
        !          2527: u_char
        !          2528: ess_dsp_read_ready(sc)
        !          2529:        struct ess_softc *sc;
        !          2530: {
        !          2531:        return ((ess_get_dsp_status(sc) & ESS_DSP_READ_READY) ? 1 : 0);
        !          2532: }
        !          2533:
        !          2534:
        !          2535: /*
        !          2536:  * Return the write status of the DSP: 1 -> DSP ready for writing
        !          2537:  *                                     0 -> DSP not ready for writing
        !          2538:  */
        !          2539: u_char
        !          2540: ess_dsp_write_ready(sc)
        !          2541:        struct ess_softc *sc;
        !          2542: {
        !          2543:        return ((ess_get_dsp_status(sc) & ESS_DSP_WRITE_BUSY) ? 0 : 1);
        !          2544: }
        !          2545:
        !          2546:
        !          2547: /*
        !          2548:  * Read a byte from the DSP.
        !          2549:  */
        !          2550: int
        !          2551: ess_rdsp(sc)
        !          2552:        struct ess_softc *sc;
        !          2553: {
        !          2554:        bus_space_tag_t iot = sc->sc_iot;
        !          2555:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2556:        int i;
        !          2557:
        !          2558:        for (i = ESS_READ_TIMEOUT; i > 0; --i) {
        !          2559:                if (ess_dsp_read_ready(sc)) {
        !          2560:                        i = EREAD1(iot, ioh, ESS_DSP_READ);
        !          2561:                        DPRINTFN(8,("ess_rdsp() = 0x%02x\n", i));
        !          2562:                        return i;
        !          2563:                } else
        !          2564:                        delay(10);
        !          2565:        }
        !          2566:
        !          2567:        DPRINTF(("ess_rdsp: timed out\n"));
        !          2568:        return (-1);
        !          2569: }
        !          2570:
        !          2571: /*
        !          2572:  * Write a byte to the DSP.
        !          2573:  */
        !          2574: int
        !          2575: ess_wdsp(sc, v)
        !          2576:        struct ess_softc *sc;
        !          2577:        u_char v;
        !          2578: {
        !          2579:        bus_space_tag_t iot = sc->sc_iot;
        !          2580:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2581:        int i;
        !          2582:
        !          2583:        DPRINTFN(8,("ess_wdsp(0x%02x)\n", v));
        !          2584:
        !          2585:        for (i = ESS_WRITE_TIMEOUT; i > 0; --i) {
        !          2586:                if (ess_dsp_write_ready(sc)) {
        !          2587:                        EWRITE1(iot, ioh, ESS_DSP_WRITE, v);
        !          2588:                        return (0);
        !          2589:                } else
        !          2590:                        delay(10);
        !          2591:        }
        !          2592:
        !          2593:        DPRINTF(("ess_wdsp(0x%02x): timed out\n", v));
        !          2594:        return (-1);
        !          2595: }
        !          2596:
        !          2597: /*
        !          2598:  * Write a value to one of the ESS extended registers.
        !          2599:  */
        !          2600: int
        !          2601: ess_write_x_reg(sc, reg, val)
        !          2602:        struct ess_softc *sc;
        !          2603:        u_char reg;
        !          2604:        u_char val;
        !          2605: {
        !          2606:        int error;
        !          2607:
        !          2608:        DPRINTFN(2,("ess_write_x_reg: %02x=%02x\n", reg, val));
        !          2609:        if ((error = ess_wdsp(sc, reg)) == 0)
        !          2610:                error = ess_wdsp(sc, val);
        !          2611:
        !          2612:        return error;
        !          2613: }
        !          2614:
        !          2615: /*
        !          2616:  * Read the value of one of the ESS extended registers.
        !          2617:  */
        !          2618: u_char
        !          2619: ess_read_x_reg(sc, reg)
        !          2620:        struct ess_softc *sc;
        !          2621:        u_char reg;
        !          2622: {
        !          2623:        int error;
        !          2624:        int val;
        !          2625:
        !          2626:        if ((error = ess_wdsp(sc, 0xC0)) == 0)
        !          2627:                error = ess_wdsp(sc, reg);
        !          2628:        if (error)
        !          2629:                DPRINTF(("Error reading extended register 0x%02x\n", reg));
        !          2630: /* REVISIT: what if an error is returned above? */
        !          2631:        val = ess_rdsp(sc);
        !          2632:        DPRINTFN(2,("ess_read_x_reg: %02x=%02x\n", reg, val));
        !          2633:        return val;
        !          2634: }
        !          2635:
        !          2636: void
        !          2637: ess_clear_xreg_bits(sc, reg, mask)
        !          2638:        struct ess_softc *sc;
        !          2639:        u_char reg;
        !          2640:        u_char mask;
        !          2641: {
        !          2642:        if (ess_write_x_reg(sc, reg, ess_read_x_reg(sc, reg) & ~mask) == -1)
        !          2643:                DPRINTF(("Error clearing bits in extended register 0x%02x\n",
        !          2644:                         reg));
        !          2645: }
        !          2646:
        !          2647: void
        !          2648: ess_set_xreg_bits(sc, reg, mask)
        !          2649:        struct ess_softc *sc;
        !          2650:        u_char reg;
        !          2651:        u_char mask;
        !          2652: {
        !          2653:        if (ess_write_x_reg(sc, reg, ess_read_x_reg(sc, reg) | mask) == -1)
        !          2654:                DPRINTF(("Error setting bits in extended register 0x%02x\n",
        !          2655:                         reg));
        !          2656: }
        !          2657:
        !          2658:
        !          2659: /*
        !          2660:  * Write a value to one of the ESS mixer registers.
        !          2661:  */
        !          2662: void
        !          2663: ess_write_mix_reg(sc, reg, val)
        !          2664:        struct ess_softc *sc;
        !          2665:        u_char reg;
        !          2666:        u_char val;
        !          2667: {
        !          2668:        bus_space_tag_t iot = sc->sc_iot;
        !          2669:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2670:        int s;
        !          2671:
        !          2672:        DPRINTFN(2,("ess_write_mix_reg: %x=%x\n", reg, val));
        !          2673:
        !          2674:        s = splaudio();
        !          2675:        EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
        !          2676:        EWRITE1(iot, ioh, ESS_MIX_REG_DATA, val);
        !          2677:        splx(s);
        !          2678: }
        !          2679:
        !          2680: /*
        !          2681:  * Read the value of one of the ESS mixer registers.
        !          2682:  */
        !          2683: u_char
        !          2684: ess_read_mix_reg(sc, reg)
        !          2685:        struct ess_softc *sc;
        !          2686:        u_char reg;
        !          2687: {
        !          2688:        bus_space_tag_t iot = sc->sc_iot;
        !          2689:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2690:        int s;
        !          2691:        u_char val;
        !          2692:
        !          2693:        s = splaudio();
        !          2694:        EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
        !          2695:        val = EREAD1(iot, ioh, ESS_MIX_REG_DATA);
        !          2696:        splx(s);
        !          2697:
        !          2698:        DPRINTFN(2,("ess_read_mix_reg: %x=%x\n", reg, val));
        !          2699:        return val;
        !          2700: }
        !          2701:
        !          2702: void
        !          2703: ess_clear_mreg_bits(sc, reg, mask)
        !          2704:        struct ess_softc *sc;
        !          2705:        u_char reg;
        !          2706:        u_char mask;
        !          2707: {
        !          2708:        ess_write_mix_reg(sc, reg, ess_read_mix_reg(sc, reg) & ~mask);
        !          2709: }
        !          2710:
        !          2711: void
        !          2712: ess_set_mreg_bits(sc, reg, mask)
        !          2713:        struct ess_softc *sc;
        !          2714:        u_char reg;
        !          2715:        u_char mask;
        !          2716: {
        !          2717:        ess_write_mix_reg(sc, reg, ess_read_mix_reg(sc, reg) | mask);
        !          2718: }
        !          2719:
        !          2720: void
        !          2721: ess_read_multi_mix_reg(sc, reg, datap, count)
        !          2722:        struct ess_softc *sc;
        !          2723:        u_char reg;
        !          2724:        u_int8_t *datap;
        !          2725:        bus_size_t count;
        !          2726: {
        !          2727:        bus_space_tag_t iot = sc->sc_iot;
        !          2728:        bus_space_handle_t ioh = sc->sc_ioh;
        !          2729:        int s;
        !          2730:
        !          2731:        s = splaudio();
        !          2732:        EWRITE1(iot, ioh, ESS_MIX_REG_SELECT, reg);
        !          2733:        bus_space_read_multi_1(iot, ioh, ESS_MIX_REG_DATA, datap, count);
        !          2734:        splx(s);
        !          2735: }

CVSweb