[BACK]Return to ce4231.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / dev

Annotation of sys/arch/sparc64/dev/ce4231.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ce4231.c,v 1.21 2005/09/08 15:25:54 martin Exp $      */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            26:  * POSSIBILITY OF SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: /*
        !            30:  * Driver for CS4231 based audio found in some sun4u systems (cs4231)
        !            31:  * based on ideas from the S/Linux project and the NetBSD project.
        !            32:  *
        !            33:  * Effort sponsored in part by the Defense Advanced Research Projects
        !            34:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            35:  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
        !            36:  *
        !            37:  */
        !            38:
        !            39: #include <sys/param.h>
        !            40: #include <sys/systm.h>
        !            41: #include <sys/errno.h>
        !            42: #include <sys/ioctl.h>
        !            43: #include <sys/device.h>
        !            44: #include <sys/proc.h>
        !            45: #include <sys/malloc.h>
        !            46:
        !            47: #include <machine/cpu.h>
        !            48: #include <machine/bus.h>
        !            49: #include <machine/intr.h>
        !            50: #include <machine/autoconf.h>
        !            51:
        !            52: #include <sys/audioio.h>
        !            53: #include <dev/audio_if.h>
        !            54: #include <dev/auconv.h>
        !            55:
        !            56: #include <sparc64/dev/ebusreg.h>
        !            57: #include <sparc64/dev/ebusvar.h>
        !            58: #include <sparc64/dev/ce4231var.h>
        !            59:
        !            60: #include <dev/ic/ad1848reg.h>
        !            61: #include <dev/ic/cs4231reg.h>
        !            62:
        !            63: #define        CSAUDIO_DAC_LVL         0
        !            64: #define        CSAUDIO_LINE_IN_LVL     1
        !            65: #define        CSAUDIO_MIC_LVL         2
        !            66: #define        CSAUDIO_CD_LVL          3
        !            67: #define        CSAUDIO_MONITOR_LVL     4
        !            68: #define        CSAUDIO_OUTPUT_LVL      5
        !            69: #define        CSAUDIO_LINE_IN_MUTE    6
        !            70: #define        CSAUDIO_DAC_MUTE        7
        !            71: #define        CSAUDIO_CD_MUTE         8
        !            72: #define        CSAUDIO_MIC_MUTE        9
        !            73: #define        CSAUDIO_MONITOR_MUTE    10
        !            74: #define        CSAUDIO_OUTPUT_MUTE     11
        !            75: #define        CSAUDIO_REC_LVL         12
        !            76: #define        CSAUDIO_RECORD_SOURCE   13
        !            77: #define        CSAUDIO_OUTPUT          14
        !            78: #define        CSAUDIO_INPUT_CLASS     15
        !            79: #define        CSAUDIO_OUTPUT_CLASS    16
        !            80: #define        CSAUDIO_RECORD_CLASS    17
        !            81: #define        CSAUDIO_MONITOR_CLASS   18
        !            82:
        !            83: #define        CSPORT_AUX2             0
        !            84: #define        CSPORT_AUX1             1
        !            85: #define        CSPORT_DAC              2
        !            86: #define        CSPORT_LINEIN           3
        !            87: #define        CSPORT_MONO             4
        !            88: #define        CSPORT_MONITOR          5
        !            89: #define        CSPORT_SPEAKER          6
        !            90: #define        CSPORT_LINEOUT          7
        !            91: #define        CSPORT_HEADPHONE        8
        !            92:
        !            93: #define MIC_IN_PORT    0
        !            94: #define LINE_IN_PORT   1
        !            95: #define AUX1_IN_PORT   2
        !            96: #define DAC_IN_PORT    3
        !            97:
        !            98: #ifdef AUDIO_DEBUG
        !            99: #define        DPRINTF(x)      printf x
        !           100: #else
        !           101: #define        DPRINTF(x)
        !           102: #endif
        !           103:
        !           104: #define        CS_TIMEOUT      90000
        !           105:
        !           106: #define        CS_PC_LINEMUTE  XCTL0_ENABLE
        !           107: #define        CS_PC_HDPHMUTE  XCTL1_ENABLE
        !           108: #define        CS_AFS_PI       0x10
        !           109:
        !           110: /* Read/write CS4231 direct registers */
        !           111: #define CS_WRITE(sc,r,v)       \
        !           112:     bus_space_write_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2, (v))
        !           113: #define        CS_READ(sc,r)           \
        !           114:     bus_space_read_1((sc)->sc_bustag, (sc)->sc_cshandle, (r) << 2)
        !           115:
        !           116: /* Read/write EBDMA playback registers */
        !           117: #define        P_WRITE(sc,r,v)         \
        !           118:     bus_space_write_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r), (v))
        !           119: #define        P_READ(sc,r)            \
        !           120:     bus_space_read_4((sc)->sc_bustag, (sc)->sc_pdmahandle, (r))
        !           121:
        !           122: /* Read/write EBDMA capture registers */
        !           123: #define        C_WRITE(sc,r,v)         \
        !           124:     bus_space_write_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r), (v))
        !           125: #define        C_READ(sc,r)            \
        !           126:     bus_space_read_4((sc)->sc_bustag, (sc)->sc_cdmahandle, (r))
        !           127:
        !           128: int    ce4231_match(struct device *, void *, void *);
        !           129: void   ce4231_attach(struct device *, struct device *, void *);
        !           130: int    ce4231_cintr(void *);
        !           131: int    ce4231_pintr(void *);
        !           132:
        !           133: int    ce4231_set_speed(struct ce4231_softc *, u_long *);
        !           134: void   ce4231_setup_output(struct ce4231_softc *sc);
        !           135:
        !           136: void           ce4231_write(struct ce4231_softc *, u_int8_t, u_int8_t);
        !           137: u_int8_t       ce4231_read(struct ce4231_softc *, u_int8_t);
        !           138:
        !           139: /* Audio interface */
        !           140: int    ce4231_open(void *, int);
        !           141: void   ce4231_close(void *);
        !           142: int    ce4231_query_encoding(void *, struct audio_encoding *);
        !           143: int    ce4231_set_params(void *, int, int, struct audio_params *,
        !           144:     struct audio_params *);
        !           145: int    ce4231_round_blocksize(void *, int);
        !           146: int    ce4231_commit_settings(void *);
        !           147: int    ce4231_halt_output(void *);
        !           148: int    ce4231_halt_input(void *);
        !           149: int    ce4231_getdev(void *, struct audio_device *);
        !           150: int    ce4231_set_port(void *, mixer_ctrl_t *);
        !           151: int    ce4231_get_port(void *, mixer_ctrl_t *);
        !           152: int    ce4231_query_devinfo(void *addr, mixer_devinfo_t *);
        !           153: void * ce4231_alloc(void *, int, size_t, int, int);
        !           154: void   ce4231_free(void *, void *, int);
        !           155: int    ce4231_get_props(void *);
        !           156: int    ce4231_trigger_output(void *, void *, void *, int,
        !           157:     void (*intr)(void *), void *arg, struct audio_params *);
        !           158: int    ce4231_trigger_input(void *, void *, void *, int,
        !           159:     void (*intr)(void *), void *arg, struct audio_params *);
        !           160:
        !           161: struct audio_hw_if ce4231_sa_hw_if = {
        !           162:        ce4231_open,
        !           163:        ce4231_close,
        !           164:        0,
        !           165:        ce4231_query_encoding,
        !           166:        ce4231_set_params,
        !           167:        ce4231_round_blocksize,
        !           168:        ce4231_commit_settings,
        !           169:        0,
        !           170:        0,
        !           171:        0,
        !           172:        0,
        !           173:        ce4231_halt_output,
        !           174:        ce4231_halt_input,
        !           175:        0,
        !           176:        ce4231_getdev,
        !           177:        0,
        !           178:        ce4231_set_port,
        !           179:        ce4231_get_port,
        !           180:        ce4231_query_devinfo,
        !           181:        ce4231_alloc,
        !           182:        ce4231_free,
        !           183:        0,
        !           184:        0,
        !           185:        ce4231_get_props,
        !           186:        ce4231_trigger_output,
        !           187:        ce4231_trigger_input
        !           188: };
        !           189:
        !           190: struct cfattach audioce_ca = {
        !           191:        sizeof (struct ce4231_softc), ce4231_match, ce4231_attach
        !           192: };
        !           193:
        !           194: struct cfdriver audioce_cd = {
        !           195:        NULL, "audioce", DV_DULL
        !           196: };
        !           197:
        !           198: struct audio_device ce4231_device = {
        !           199:        "SUNW,CS4231",
        !           200:        "b",
        !           201:        "onboard1",
        !           202: };
        !           203:
        !           204: int
        !           205: ce4231_match(parent, vcf, aux)
        !           206:        struct device *parent;
        !           207:        void *vcf, *aux;
        !           208: {
        !           209:        struct ebus_attach_args *ea = aux;
        !           210:
        !           211:        if (!strcmp("SUNW,CS4231", ea->ea_name) ||
        !           212:            !strcmp("audio", ea->ea_name))
        !           213:                return (1);
        !           214:        return (0);
        !           215: }
        !           216:
        !           217: void
        !           218: ce4231_attach(parent, self, aux)
        !           219:        struct device *parent, *self;
        !           220:        void *aux;
        !           221: {
        !           222:        struct ebus_attach_args *ea = aux;
        !           223:        struct ce4231_softc *sc = (struct ce4231_softc *)self;
        !           224:        int node;
        !           225:
        !           226:        node = ea->ea_node;
        !           227:
        !           228:        sc->sc_last_format = 0xffffffff;
        !           229:
        !           230:        /* Pass on the bus tags */
        !           231:        sc->sc_bustag = ea->ea_memtag;
        !           232:        sc->sc_dmatag = ea->ea_dmatag;
        !           233:
        !           234:        /* Make sure things are sane. */
        !           235:        if (ea->ea_nintrs != 2) {
        !           236:                printf(": expected 2 interrupts, got %d\n", ea->ea_nintrs);
        !           237:                return;
        !           238:        }
        !           239:        if (ea->ea_nregs != 4) {
        !           240:                printf(": expected 4 register set, got %d\n",
        !           241:                    ea->ea_nregs);
        !           242:                return;
        !           243:        }
        !           244:
        !           245:        sc->sc_cih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[0],
        !           246:            IPL_AUDIO, 0, ce4231_cintr, sc, self->dv_xname);
        !           247:        if (sc->sc_cih == NULL) {
        !           248:                printf(": couldn't establish capture interrupt\n");
        !           249:                return;
        !           250:        }
        !           251:        sc->sc_pih = bus_intr_establish(sc->sc_bustag, ea->ea_intrs[1],
        !           252:            IPL_AUDIO, 0, ce4231_pintr, sc, self->dv_xname);
        !           253:        if (sc->sc_pih == NULL) {
        !           254:                printf(": couldn't establish play interrupt1\n");
        !           255:                return;
        !           256:        }
        !           257:
        !           258:        /* XXX what if prom has already mapped?! */
        !           259:
        !           260:        if (ebus_bus_map(sc->sc_bustag, 0,
        !           261:            EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size,
        !           262:            BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cshandle) != 0) {
        !           263:                printf(": couldn't map cs4231 registers\n");
        !           264:                return;
        !           265:        }
        !           266:
        !           267:        if (ebus_bus_map(sc->sc_bustag, 0,
        !           268:            EBUS_PADDR_FROM_REG(&ea->ea_regs[1]), ea->ea_regs[1].size,
        !           269:            BUS_SPACE_MAP_LINEAR, 0, &sc->sc_pdmahandle) != 0) {
        !           270:                printf(": couldn't map dma1 registers\n");
        !           271:                return;
        !           272:        }
        !           273:
        !           274:        if (ebus_bus_map(sc->sc_bustag, 0,
        !           275:            EBUS_PADDR_FROM_REG(&ea->ea_regs[2]), ea->ea_regs[2].size,
        !           276:            BUS_SPACE_MAP_LINEAR, 0, &sc->sc_cdmahandle) != 0) {
        !           277:                printf(": couldn't map dma2 registers\n");
        !           278:                return;
        !           279:        }
        !           280:
        !           281:        if (ebus_bus_map(sc->sc_bustag, 0,
        !           282:            EBUS_PADDR_FROM_REG(&ea->ea_regs[3]), ea->ea_regs[3].size,
        !           283:            BUS_SPACE_MAP_LINEAR, 0, &sc->sc_auxhandle) != 0) {
        !           284:                printf(": couldn't map aux registers\n");
        !           285:                return;
        !           286:        }
        !           287:
        !           288:        printf(": nvaddrs %d\n", ea->ea_nvaddrs);
        !           289:
        !           290:        audio_attach_mi(&ce4231_sa_hw_if, sc, &sc->sc_dev);
        !           291:
        !           292:        /* Default to speaker, unmuted, reasonable volume */
        !           293:        sc->sc_out_port = CSPORT_SPEAKER;
        !           294:        sc->sc_mute[CSPORT_SPEAKER] = 1;
        !           295:        sc->sc_mute[CSPORT_MONITOR] = 1;
        !           296:        sc->sc_volume[CSPORT_SPEAKER].left = 192;
        !           297:        sc->sc_volume[CSPORT_SPEAKER].right = 192;
        !           298:
        !           299:        /* XXX get real burst... */
        !           300:        sc->sc_burst = EBDCSR_BURST_8;
        !           301: }
        !           302:
        !           303: /*
        !           304:  * Write to one of the indexed registers of cs4231.
        !           305:  */
        !           306: void
        !           307: ce4231_write(sc, r, v)
        !           308:        struct ce4231_softc *sc;
        !           309:        u_int8_t r, v;
        !           310: {
        !           311:        CS_WRITE(sc, AD1848_IADDR, r);
        !           312:        CS_WRITE(sc, AD1848_IDATA, v);
        !           313: }
        !           314:
        !           315: /*
        !           316:  * Read from one of the indexed registers of cs4231.
        !           317:  */
        !           318: u_int8_t
        !           319: ce4231_read(sc, r)
        !           320:        struct ce4231_softc *sc;
        !           321:        u_int8_t r;
        !           322: {
        !           323:        CS_WRITE(sc, AD1848_IADDR, r);
        !           324:        return (CS_READ(sc, AD1848_IDATA));
        !           325: }
        !           326:
        !           327: int
        !           328: ce4231_set_speed(sc, argp)
        !           329:        struct ce4231_softc *sc;
        !           330:        u_long *argp;
        !           331:
        !           332: {
        !           333:        /*
        !           334:         * The available speeds are in the following table. Keep the speeds in
        !           335:         * the increasing order.
        !           336:         */
        !           337:        typedef struct {
        !           338:                int speed;
        !           339:                u_char bits;
        !           340:        } speed_struct;
        !           341:        u_long arg = *argp;
        !           342:
        !           343:        static speed_struct speed_table[] = {
        !           344:                {5510,  (0 << 1) | CLOCK_XTAL2},
        !           345:                {5510,  (0 << 1) | CLOCK_XTAL2},
        !           346:                {6620,  (7 << 1) | CLOCK_XTAL2},
        !           347:                {8000,  (0 << 1) | CLOCK_XTAL1},
        !           348:                {9600,  (7 << 1) | CLOCK_XTAL1},
        !           349:                {11025, (1 << 1) | CLOCK_XTAL2},
        !           350:                {16000, (1 << 1) | CLOCK_XTAL1},
        !           351:                {18900, (2 << 1) | CLOCK_XTAL2},
        !           352:                {22050, (3 << 1) | CLOCK_XTAL2},
        !           353:                {27420, (2 << 1) | CLOCK_XTAL1},
        !           354:                {32000, (3 << 1) | CLOCK_XTAL1},
        !           355:                {33075, (6 << 1) | CLOCK_XTAL2},
        !           356:                {33075, (4 << 1) | CLOCK_XTAL2},
        !           357:                {44100, (5 << 1) | CLOCK_XTAL2},
        !           358:                {48000, (6 << 1) | CLOCK_XTAL1},
        !           359:        };
        !           360:
        !           361:        int i, n, selected = -1;
        !           362:
        !           363:        n = sizeof(speed_table) / sizeof(speed_struct);
        !           364:
        !           365:        if (arg < speed_table[0].speed)
        !           366:                selected = 0;
        !           367:        if (arg > speed_table[n - 1].speed)
        !           368:                selected = n - 1;
        !           369:
        !           370:        for (i = 1; selected == -1 && i < n; i++) {
        !           371:                if (speed_table[i].speed == arg)
        !           372:                        selected = i;
        !           373:                else if (speed_table[i].speed > arg) {
        !           374:                        int diff1, diff2;
        !           375:
        !           376:                        diff1 = arg - speed_table[i - 1].speed;
        !           377:                        diff2 = speed_table[i].speed - arg;
        !           378:                        if (diff1 < diff2)
        !           379:                                selected = i - 1;
        !           380:                        else
        !           381:                                selected = i;
        !           382:                }
        !           383:        }
        !           384:
        !           385:        if (selected == -1)
        !           386:                selected = 3;
        !           387:
        !           388:        sc->sc_speed_bits = speed_table[selected].bits;
        !           389:        sc->sc_need_commit = 1;
        !           390:        *argp = speed_table[selected].speed;
        !           391:
        !           392:        return (0);
        !           393: }
        !           394:
        !           395: /*
        !           396:  * Audio interface functions
        !           397:  */
        !           398: int
        !           399: ce4231_open(addr, flags)
        !           400:        void *addr;
        !           401:        int flags;
        !           402: {
        !           403:        struct ce4231_softc *sc = addr;
        !           404:        int tries;
        !           405:
        !           406:        if (sc->sc_open)
        !           407:                return (EBUSY);
        !           408:        sc->sc_open = 1;
        !           409:        sc->sc_locked = 0;
        !           410:        sc->sc_rintr = 0;
        !           411:        sc->sc_rarg = 0;
        !           412:        sc->sc_pintr = 0;
        !           413:        sc->sc_parg = 0;
        !           414:
        !           415:        P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
        !           416:        C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
        !           417:        P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
        !           418:        C_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
        !           419:
        !           420:        DELAY(20);
        !           421:
        !           422:        for (tries = CS_TIMEOUT;
        !           423:             tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
        !           424:                DELAY(10);
        !           425:        if (tries == 0)
        !           426:                printf("%s: timeout waiting for reset\n", sc->sc_dev.dv_xname);
        !           427:
        !           428:        /* Turn on cs4231 mode */
        !           429:        ce4231_write(sc, SP_MISC_INFO,
        !           430:            ce4231_read(sc, SP_MISC_INFO) | MODE2);
        !           431:
        !           432:        ce4231_setup_output(sc);
        !           433:
        !           434:        ce4231_write(sc, SP_PIN_CONTROL,
        !           435:            ce4231_read(sc, SP_PIN_CONTROL) | INTERRUPT_ENABLE);
        !           436:
        !           437:        return (0);
        !           438: }
        !           439:
        !           440: void
        !           441: ce4231_setup_output(sc)
        !           442:        struct ce4231_softc *sc;
        !           443: {
        !           444:        u_int8_t pc, mi, rm, lm;
        !           445:
        !           446:        pc = ce4231_read(sc, SP_PIN_CONTROL) | CS_PC_HDPHMUTE | CS_PC_LINEMUTE;
        !           447:
        !           448:        mi = ce4231_read(sc, CS_MONO_IO_CONTROL) | MONO_OUTPUT_MUTE;
        !           449:
        !           450:        lm = ce4231_read(sc, SP_LEFT_OUTPUT_CONTROL);
        !           451:        lm &= ~OUTPUT_ATTEN_BITS;
        !           452:        lm |= ((~(sc->sc_volume[CSPORT_SPEAKER].left >> 2)) &
        !           453:            OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
        !           454:
        !           455:        rm = ce4231_read(sc, SP_RIGHT_OUTPUT_CONTROL);
        !           456:        rm &= ~OUTPUT_ATTEN_BITS;
        !           457:        rm |= ((~(sc->sc_volume[CSPORT_SPEAKER].right >> 2)) &
        !           458:            OUTPUT_ATTEN_BITS) | OUTPUT_MUTE;
        !           459:
        !           460:        if (sc->sc_mute[CSPORT_MONITOR]) {
        !           461:                lm &= ~OUTPUT_MUTE;
        !           462:                rm &= ~OUTPUT_MUTE;
        !           463:        }
        !           464:
        !           465:        switch (sc->sc_out_port) {
        !           466:        case CSPORT_HEADPHONE:
        !           467:                if (sc->sc_mute[CSPORT_SPEAKER])
        !           468:                        pc &= ~CS_PC_HDPHMUTE;
        !           469:                break;
        !           470:        case CSPORT_SPEAKER:
        !           471:                if (sc->sc_mute[CSPORT_SPEAKER])
        !           472:                        mi &= ~MONO_OUTPUT_MUTE;
        !           473:                break;
        !           474:        case CSPORT_LINEOUT:
        !           475:                if (sc->sc_mute[CSPORT_SPEAKER])
        !           476:                        pc &= ~CS_PC_LINEMUTE;
        !           477:                break;
        !           478:        }
        !           479:
        !           480:        ce4231_write(sc, SP_LEFT_OUTPUT_CONTROL, lm);
        !           481:        ce4231_write(sc, SP_RIGHT_OUTPUT_CONTROL, rm);
        !           482:        ce4231_write(sc, SP_PIN_CONTROL, pc);
        !           483:        ce4231_write(sc, CS_MONO_IO_CONTROL, mi);
        !           484: }
        !           485:
        !           486: void
        !           487: ce4231_close(addr)
        !           488:        void *addr;
        !           489: {
        !           490:        struct ce4231_softc *sc = addr;
        !           491:
        !           492:        ce4231_halt_input(sc);
        !           493:        ce4231_halt_output(sc);
        !           494:        ce4231_write(sc, SP_PIN_CONTROL,
        !           495:            ce4231_read(sc, SP_PIN_CONTROL) & (~INTERRUPT_ENABLE));
        !           496:        sc->sc_open = 0;
        !           497: }
        !           498:
        !           499: int
        !           500: ce4231_query_encoding(addr, fp)
        !           501:        void *addr;
        !           502:        struct audio_encoding *fp;
        !           503: {
        !           504:        int err = 0;
        !           505:
        !           506:        switch (fp->index) {
        !           507:        case 0:
        !           508:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
        !           509:                fp->encoding = AUDIO_ENCODING_ULAW;
        !           510:                fp->precision = 8;
        !           511:                fp->flags = 0;
        !           512:                break;
        !           513:        case 1:
        !           514:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
        !           515:                fp->encoding = AUDIO_ENCODING_ALAW;
        !           516:                fp->precision = 8;
        !           517:                fp->flags = 0;
        !           518:                break;
        !           519:        case 2:
        !           520:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
        !           521:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !           522:                fp->precision = 16;
        !           523:                fp->flags = 0;
        !           524:                break;
        !           525:        case 3:
        !           526:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
        !           527:                fp->encoding = AUDIO_ENCODING_ULINEAR;
        !           528:                fp->precision = 8;
        !           529:                fp->flags = 0;
        !           530:                break;
        !           531:        case 4:
        !           532:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
        !           533:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !           534:                fp->precision = 16;
        !           535:                fp->flags = 0;
        !           536:                break;
        !           537:        case 5:
        !           538:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
        !           539:                fp->encoding = AUDIO_ENCODING_SLINEAR;
        !           540:                fp->precision = 8;
        !           541:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           542:                break;
        !           543:        case 6:
        !           544:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
        !           545:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !           546:                fp->precision = 16;
        !           547:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           548:                break;
        !           549:        case 7:
        !           550:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
        !           551:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !           552:                fp->precision = 16;
        !           553:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           554:                break;
        !           555:        case 8:
        !           556:                strlcpy(fp->name, AudioEadpcm, sizeof fp->name);
        !           557:                fp->encoding = AUDIO_ENCODING_ADPCM;
        !           558:                fp->precision = 8;
        !           559:                fp->flags = 0;
        !           560:                break;
        !           561:        default:
        !           562:                err = EINVAL;
        !           563:        }
        !           564:        return (err);
        !           565: }
        !           566:
        !           567: int
        !           568: ce4231_set_params(addr, setmode, usemode, p, r)
        !           569:        void *addr;
        !           570:        int setmode, usemode;
        !           571:        struct audio_params *p, *r;
        !           572: {
        !           573:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           574:        int err, bits, enc = p->encoding;
        !           575:        void (*pswcode)(void *, u_char *, int cnt) = NULL;
        !           576:        void (*rswcode)(void *, u_char *, int cnt) = NULL;
        !           577:
        !           578:        switch (enc) {
        !           579:        case AUDIO_ENCODING_ULAW:
        !           580:                if (p->precision != 8)
        !           581:                        return (EINVAL);
        !           582:                bits = FMT_ULAW >> 5;
        !           583:                break;
        !           584:        case AUDIO_ENCODING_ALAW:
        !           585:                if (p->precision != 8)
        !           586:                        return (EINVAL);
        !           587:                bits = FMT_ALAW >> 5;
        !           588:                break;
        !           589:        case AUDIO_ENCODING_SLINEAR_LE:
        !           590:                if (p->precision == 8) {
        !           591:                        bits = FMT_PCM8 >> 5;
        !           592:                        pswcode = rswcode = change_sign8;
        !           593:                } else if (p->precision == 16)
        !           594:                        bits = FMT_TWOS_COMP >> 5;
        !           595:                else
        !           596:                        return (EINVAL);
        !           597:                break;
        !           598:        case AUDIO_ENCODING_ULINEAR:
        !           599:                if (p->precision != 8)
        !           600:                        return (EINVAL);
        !           601:                bits = FMT_PCM8 >> 5;
        !           602:                break;
        !           603:        case AUDIO_ENCODING_SLINEAR_BE:
        !           604:                if (p->precision == 8) {
        !           605:                        bits = FMT_PCM8 >> 5;
        !           606:                        pswcode = rswcode = change_sign8;
        !           607:                } else if (p->precision == 16)
        !           608:                        bits = FMT_TWOS_COMP_BE >> 5;
        !           609:                else
        !           610:                        return (EINVAL);
        !           611:                break;
        !           612:        case AUDIO_ENCODING_SLINEAR:
        !           613:                if (p->precision != 8)
        !           614:                        return (EINVAL);
        !           615:                bits = FMT_PCM8 >> 5;
        !           616:                pswcode = rswcode = change_sign8;
        !           617:                break;
        !           618:        case AUDIO_ENCODING_ULINEAR_LE:
        !           619:                if (p->precision == 8)
        !           620:                        bits = FMT_PCM8 >> 5;
        !           621:                else if (p->precision == 16) {
        !           622:                        bits = FMT_TWOS_COMP >> 5;
        !           623:                        pswcode = rswcode = change_sign16_le;
        !           624:                } else
        !           625:                        return (EINVAL);
        !           626:                break;
        !           627:        case AUDIO_ENCODING_ULINEAR_BE:
        !           628:                if (p->precision == 8)
        !           629:                        bits = FMT_PCM8 >> 5;
        !           630:                else if (p->precision == 16) {
        !           631:                        bits = FMT_TWOS_COMP_BE >> 5;
        !           632:                        pswcode = rswcode = change_sign16_be;
        !           633:                } else
        !           634:                        return (EINVAL);
        !           635:                break;
        !           636:        case AUDIO_ENCODING_ADPCM:
        !           637:                if (p->precision != 8)
        !           638:                        return (EINVAL);
        !           639:                bits = FMT_ADPCM >> 5;
        !           640:                break;
        !           641:        default:
        !           642:                return (EINVAL);
        !           643:        }
        !           644:
        !           645:        if (p->channels != 1 && p->channels != 2)
        !           646:                return (EINVAL);
        !           647:
        !           648:        err = ce4231_set_speed(sc, &p->sample_rate);
        !           649:        if (err)
        !           650:                return (err);
        !           651:
        !           652:        p->sw_code = pswcode;
        !           653:        r->sw_code = rswcode;
        !           654:
        !           655:        sc->sc_format_bits = bits;
        !           656:        sc->sc_channels = p->channels;
        !           657:        sc->sc_precision = p->precision;
        !           658:        sc->sc_need_commit = 1;
        !           659:        return (0);
        !           660: }
        !           661:
        !           662: int
        !           663: ce4231_round_blocksize(addr, blk)
        !           664:        void *addr;
        !           665:        int blk;
        !           666: {
        !           667:        return ((blk + 3) & (-4));
        !           668: }
        !           669:
        !           670: int
        !           671: ce4231_commit_settings(addr)
        !           672:        void *addr;
        !           673: {
        !           674:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           675:        int s, tries;
        !           676:        u_int8_t r, fs;
        !           677:
        !           678:        if (sc->sc_need_commit == 0)
        !           679:                return (0);
        !           680:
        !           681:        fs = sc->sc_speed_bits | (sc->sc_format_bits << 5);
        !           682:        if (sc->sc_channels == 2)
        !           683:                fs |= FMT_STEREO;
        !           684:
        !           685:        if (sc->sc_last_format == fs) {
        !           686:                sc->sc_need_commit = 0;
        !           687:                return (0);
        !           688:        }
        !           689:
        !           690:        s = splaudio();
        !           691:
        !           692:        r = ce4231_read(sc, SP_INTERFACE_CONFIG) | AUTO_CAL_ENABLE;
        !           693:        CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE);
        !           694:        CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_INTERFACE_CONFIG);
        !           695:        CS_WRITE(sc, AD1848_IDATA, r);
        !           696:
        !           697:        CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | SP_CLOCK_DATA_FORMAT);
        !           698:        CS_WRITE(sc, AD1848_IDATA, fs);
        !           699:        CS_READ(sc, AD1848_IDATA);
        !           700:        CS_READ(sc, AD1848_IDATA);
        !           701:        tries = CS_TIMEOUT;
        !           702:        for (tries = CS_TIMEOUT;
        !           703:             tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
        !           704:                DELAY(10);
        !           705:        if (tries == 0)
        !           706:                printf("%s: timeout committing fspb\n", sc->sc_dev.dv_xname);
        !           707:
        !           708:        CS_WRITE(sc, AD1848_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT);
        !           709:        CS_WRITE(sc, AD1848_IDATA, fs);
        !           710:        CS_READ(sc, AD1848_IDATA);
        !           711:        CS_READ(sc, AD1848_IDATA);
        !           712:        for (tries = CS_TIMEOUT;
        !           713:             tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
        !           714:                DELAY(10);
        !           715:        if (tries == 0)
        !           716:                printf("%s: timeout committing cdf\n", sc->sc_dev.dv_xname);
        !           717:
        !           718:        CS_WRITE(sc, AD1848_IADDR, 0);
        !           719:        for (tries = CS_TIMEOUT;
        !           720:             tries && CS_READ(sc, AD1848_IADDR) == SP_IN_INIT; tries--)
        !           721:                DELAY(10);
        !           722:        if (tries == 0)
        !           723:                printf("%s: timeout waiting for !mce\n", sc->sc_dev.dv_xname);
        !           724:
        !           725:        CS_WRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
        !           726:        for (tries = CS_TIMEOUT;
        !           727:             tries && CS_READ(sc, AD1848_IDATA) & AUTO_CAL_IN_PROG; tries--)
        !           728:                DELAY(10);
        !           729:        if (tries == 0)
        !           730:                printf("%s: timeout waiting for autocalibration\n",
        !           731:                    sc->sc_dev.dv_xname);
        !           732:
        !           733:        splx(s);
        !           734:
        !           735:        sc->sc_need_commit = 0;
        !           736:        return (0);
        !           737: }
        !           738:
        !           739: int
        !           740: ce4231_halt_output(addr)
        !           741:        void *addr;
        !           742: {
        !           743:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           744:
        !           745:        P_WRITE(sc, EBDMA_DCSR,
        !           746:            P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
        !           747:        ce4231_write(sc, SP_INTERFACE_CONFIG,
        !           748:            ce4231_read(sc, SP_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE));
        !           749:        sc->sc_locked = 0;
        !           750:        return (0);
        !           751: }
        !           752:
        !           753: int
        !           754: ce4231_halt_input(addr)
        !           755:        void *addr;
        !           756: {
        !           757:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           758:
        !           759:        C_WRITE(sc, EBDMA_DCSR,
        !           760:            C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN);
        !           761:        ce4231_write(sc, SP_INTERFACE_CONFIG,
        !           762:            ce4231_read(sc, SP_INTERFACE_CONFIG) & (~CAPTURE_ENABLE));
        !           763:        sc->sc_locked = 0;
        !           764:        return (0);
        !           765: }
        !           766:
        !           767: int
        !           768: ce4231_getdev(addr, retp)
        !           769:        void *addr;
        !           770:        struct audio_device *retp;
        !           771: {
        !           772:        *retp = ce4231_device;
        !           773:        return (0);
        !           774: }
        !           775:
        !           776: int
        !           777: ce4231_set_port(addr, cp)
        !           778:        void *addr;
        !           779:        mixer_ctrl_t *cp;
        !           780: {
        !           781:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           782:        int error = EINVAL;
        !           783:
        !           784:        DPRINTF(("ce4231_set_port: port=%d type=%d\n", cp->dev, cp->type));
        !           785:
        !           786:        switch (cp->dev) {
        !           787:        case CSAUDIO_DAC_LVL:
        !           788:                if (cp->type != AUDIO_MIXER_VALUE)
        !           789:                        break;
        !           790:                if (cp->un.value.num_channels == 1)
        !           791:                        ce4231_write(sc, SP_LEFT_AUX1_CONTROL,
        !           792:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
        !           793:                            LINE_INPUT_ATTEN_BITS);
        !           794:                else if (cp->un.value.num_channels == 2) {
        !           795:                        ce4231_write(sc, SP_LEFT_AUX1_CONTROL,
        !           796:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
        !           797:                            LINE_INPUT_ATTEN_BITS);
        !           798:                        ce4231_write(sc, SP_RIGHT_AUX1_CONTROL,
        !           799:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
        !           800:                            LINE_INPUT_ATTEN_BITS);
        !           801:                } else
        !           802:                        break;
        !           803:                error = 0;
        !           804:                break;
        !           805:        case CSAUDIO_LINE_IN_LVL:
        !           806:                if (cp->type != AUDIO_MIXER_VALUE)
        !           807:                        break;
        !           808:                if (cp->un.value.num_channels == 1)
        !           809:                        ce4231_write(sc, CS_LEFT_LINE_CONTROL,
        !           810:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
        !           811:                            AUX_INPUT_ATTEN_BITS);
        !           812:                else if (cp->un.value.num_channels == 2) {
        !           813:                        ce4231_write(sc, CS_LEFT_LINE_CONTROL,
        !           814:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
        !           815:                            AUX_INPUT_ATTEN_BITS);
        !           816:                        ce4231_write(sc, CS_RIGHT_LINE_CONTROL,
        !           817:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
        !           818:                            AUX_INPUT_ATTEN_BITS);
        !           819:                } else
        !           820:                        break;
        !           821:                error = 0;
        !           822:                break;
        !           823:        case CSAUDIO_MIC_LVL:
        !           824:                if (cp->type != AUDIO_MIXER_VALUE)
        !           825:                        break;
        !           826:                if (cp->un.value.num_channels == 1) {
        !           827: #if 0
        !           828:                        ce4231_write(sc, CS_MONO_IO_CONTROL,
        !           829:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
        !           830:                            MONO_INPUT_ATTEN_BITS);
        !           831: #endif
        !           832:                } else
        !           833:                        break;
        !           834:                error = 0;
        !           835:                break;
        !           836:        case CSAUDIO_CD_LVL:
        !           837:                if (cp->type != AUDIO_MIXER_VALUE)
        !           838:                        break;
        !           839:                if (cp->un.value.num_channels == 1) {
        !           840:                        ce4231_write(sc, SP_LEFT_AUX2_CONTROL,
        !           841:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] &
        !           842:                            LINE_INPUT_ATTEN_BITS);
        !           843:                } else if (cp->un.value.num_channels == 2) {
        !           844:                        ce4231_write(sc, SP_LEFT_AUX2_CONTROL,
        !           845:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] &
        !           846:                            LINE_INPUT_ATTEN_BITS);
        !           847:                        ce4231_write(sc, SP_RIGHT_AUX2_CONTROL,
        !           848:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] &
        !           849:                            LINE_INPUT_ATTEN_BITS);
        !           850:                } else
        !           851:                        break;
        !           852:                error = 0;
        !           853:                break;
        !           854:        case CSAUDIO_MONITOR_LVL:
        !           855:                if (cp->type != AUDIO_MIXER_VALUE)
        !           856:                        break;
        !           857:                if (cp->un.value.num_channels == 1)
        !           858:                        ce4231_write(sc, SP_DIGITAL_MIX,
        !           859:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] << 2);
        !           860:                else
        !           861:                        break;
        !           862:                error = 0;
        !           863:                break;
        !           864:        case CSAUDIO_OUTPUT_LVL:
        !           865:                if (cp->type != AUDIO_MIXER_VALUE)
        !           866:                        break;
        !           867:                if (cp->un.value.num_channels == 1) {
        !           868:                        sc->sc_volume[CSPORT_SPEAKER].left =
        !           869:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
        !           870:                        sc->sc_volume[CSPORT_SPEAKER].right =
        !           871:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
        !           872:                }
        !           873:                else if (cp->un.value.num_channels == 2) {
        !           874:                        sc->sc_volume[CSPORT_SPEAKER].left =
        !           875:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
        !           876:                        sc->sc_volume[CSPORT_SPEAKER].right =
        !           877:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
        !           878:                }
        !           879:                else
        !           880:                        break;
        !           881:
        !           882:                ce4231_setup_output(sc);
        !           883:                error = 0;
        !           884:                break;
        !           885:        case CSAUDIO_OUTPUT:
        !           886:                if (cp->type != AUDIO_MIXER_ENUM)
        !           887:                        break;
        !           888:                if (cp->un.ord != CSPORT_LINEOUT &&
        !           889:                    cp->un.ord != CSPORT_SPEAKER &&
        !           890:                    cp->un.ord != CSPORT_HEADPHONE)
        !           891:                        return (EINVAL);
        !           892:                sc->sc_out_port = cp->un.ord;
        !           893:                ce4231_setup_output(sc);
        !           894:                error = 0;
        !           895:                break;
        !           896:        case CSAUDIO_LINE_IN_MUTE:
        !           897:                if (cp->type != AUDIO_MIXER_ENUM)
        !           898:                        break;
        !           899:                sc->sc_mute[CSPORT_LINEIN] = cp->un.ord ? 1 : 0;
        !           900:                error = 0;
        !           901:                break;
        !           902:        case CSAUDIO_DAC_MUTE:
        !           903:                if (cp->type != AUDIO_MIXER_ENUM)
        !           904:                        break;
        !           905:                sc->sc_mute[CSPORT_AUX1] = cp->un.ord ? 1 : 0;
        !           906:                error = 0;
        !           907:                break;
        !           908:        case CSAUDIO_CD_MUTE:
        !           909:                if (cp->type != AUDIO_MIXER_ENUM)
        !           910:                        break;
        !           911:                sc->sc_mute[CSPORT_AUX2] = cp->un.ord ? 1 : 0;
        !           912:                error = 0;
        !           913:                break;
        !           914:        case CSAUDIO_MIC_MUTE:
        !           915:                if (cp->type != AUDIO_MIXER_ENUM)
        !           916:                        break;
        !           917:                sc->sc_mute[CSPORT_MONO] = cp->un.ord ? 1 : 0;
        !           918:                error = 0;
        !           919:                break;
        !           920:        case CSAUDIO_MONITOR_MUTE:
        !           921:                if (cp->type != AUDIO_MIXER_ENUM)
        !           922:                        break;
        !           923:                sc->sc_mute[CSPORT_MONITOR] = cp->un.ord ? 1 : 0;
        !           924:                error = 0;
        !           925:                break;
        !           926:        case CSAUDIO_OUTPUT_MUTE:
        !           927:                if (cp->type != AUDIO_MIXER_ENUM)
        !           928:                        break;
        !           929:                sc->sc_mute[CSPORT_SPEAKER] = cp->un.ord ? 1 : 0;
        !           930:                ce4231_setup_output(sc);
        !           931:                error = 0;
        !           932:                break;
        !           933:        case CSAUDIO_REC_LVL:
        !           934:                if (cp->type != AUDIO_MIXER_VALUE)
        !           935:                        break;
        !           936:                break;
        !           937:        case CSAUDIO_RECORD_SOURCE:
        !           938:                if (cp->type != AUDIO_MIXER_ENUM)
        !           939:                        break;
        !           940:                break;
        !           941:        }
        !           942:
        !           943:        return (error);
        !           944: }
        !           945:
        !           946: int
        !           947: ce4231_get_port(addr, cp)
        !           948:        void *addr;
        !           949:        mixer_ctrl_t *cp;
        !           950: {
        !           951:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !           952:        int error = EINVAL;
        !           953:
        !           954:        DPRINTF(("ce4231_get_port: port=%d type=%d\n", cp->dev, cp->type));
        !           955:
        !           956:        switch (cp->dev) {
        !           957:        case CSAUDIO_DAC_LVL:
        !           958:                if (cp->type != AUDIO_MIXER_VALUE)
        !           959:                        break;
        !           960:                if (cp->un.value.num_channels == 1)
        !           961:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]=
        !           962:                            ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
        !           963:                            LINE_INPUT_ATTEN_BITS;
        !           964:                else if (cp->un.value.num_channels == 2) {
        !           965:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !           966:                            ce4231_read(sc, SP_LEFT_AUX1_CONTROL) &
        !           967:                            LINE_INPUT_ATTEN_BITS;
        !           968:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !           969:                            ce4231_read(sc, SP_RIGHT_AUX1_CONTROL) &
        !           970:                            LINE_INPUT_ATTEN_BITS;
        !           971:                } else
        !           972:                        break;
        !           973:                error = 0;
        !           974:                break;
        !           975:        case CSAUDIO_LINE_IN_LVL:
        !           976:                if (cp->type != AUDIO_MIXER_VALUE)
        !           977:                        break;
        !           978:                if (cp->un.value.num_channels == 1)
        !           979:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !           980:                            ce4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
        !           981:                else if (cp->un.value.num_channels == 2) {
        !           982:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !           983:                            ce4231_read(sc, CS_LEFT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
        !           984:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !           985:                            ce4231_read(sc, CS_RIGHT_LINE_CONTROL) & AUX_INPUT_ATTEN_BITS;
        !           986:                } else
        !           987:                        break;
        !           988:                error = 0;
        !           989:                break;
        !           990:        case CSAUDIO_MIC_LVL:
        !           991:                if (cp->type != AUDIO_MIXER_VALUE)
        !           992:                        break;
        !           993:                if (cp->un.value.num_channels == 1) {
        !           994: #if 0
        !           995:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !           996:                            ce4231_read(sc, CS_MONO_IO_CONTROL) &
        !           997:                            MONO_INPUT_ATTEN_BITS;
        !           998: #endif
        !           999:                } else
        !          1000:                        break;
        !          1001:                error = 0;
        !          1002:                break;
        !          1003:        case CSAUDIO_CD_LVL:
        !          1004:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1005:                        break;
        !          1006:                if (cp->un.value.num_channels == 1)
        !          1007:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1008:                            ce4231_read(sc, SP_LEFT_AUX2_CONTROL) &
        !          1009:                            LINE_INPUT_ATTEN_BITS;
        !          1010:                else if (cp->un.value.num_channels == 2) {
        !          1011:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1012:                            ce4231_read(sc, SP_LEFT_AUX2_CONTROL) &
        !          1013:                            LINE_INPUT_ATTEN_BITS;
        !          1014:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1015:                            ce4231_read(sc, SP_RIGHT_AUX2_CONTROL) &
        !          1016:                            LINE_INPUT_ATTEN_BITS;
        !          1017:                }
        !          1018:                else
        !          1019:                        break;
        !          1020:                error = 0;
        !          1021:                break;
        !          1022:        case CSAUDIO_MONITOR_LVL:
        !          1023:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1024:                        break;
        !          1025:                if (cp->un.value.num_channels != 1)
        !          1026:                        break;
        !          1027:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1028:                    ce4231_read(sc, SP_DIGITAL_MIX) >> 2;
        !          1029:                error = 0;
        !          1030:                break;
        !          1031:        case CSAUDIO_OUTPUT_LVL:
        !          1032:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1033:                        break;
        !          1034:                if (cp->un.value.num_channels == 1)
        !          1035:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1036:                            sc->sc_volume[CSPORT_SPEAKER].left;
        !          1037:                else if (cp->un.value.num_channels == 2) {
        !          1038:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1039:                            sc->sc_volume[CSPORT_SPEAKER].left;
        !          1040:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1041:                            sc->sc_volume[CSPORT_SPEAKER].right;
        !          1042:                }
        !          1043:                else
        !          1044:                        break;
        !          1045:                error = 0;
        !          1046:                break;
        !          1047:        case CSAUDIO_LINE_IN_MUTE:
        !          1048:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1049:                        break;
        !          1050:                cp->un.ord = sc->sc_mute[CSPORT_LINEIN] ? 1 : 0;
        !          1051:                error = 0;
        !          1052:                break;
        !          1053:        case CSAUDIO_DAC_MUTE:
        !          1054:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1055:                        break;
        !          1056:                cp->un.ord = sc->sc_mute[CSPORT_AUX1] ? 1 : 0;
        !          1057:                error = 0;
        !          1058:                break;
        !          1059:        case CSAUDIO_CD_MUTE:
        !          1060:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1061:                        break;
        !          1062:                cp->un.ord = sc->sc_mute[CSPORT_AUX2] ? 1 : 0;
        !          1063:                error = 0;
        !          1064:                break;
        !          1065:        case CSAUDIO_MIC_MUTE:
        !          1066:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1067:                        break;
        !          1068:                cp->un.ord = sc->sc_mute[CSPORT_MONO] ? 1 : 0;
        !          1069:                error = 0;
        !          1070:                break;
        !          1071:        case CSAUDIO_MONITOR_MUTE:
        !          1072:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1073:                        break;
        !          1074:                cp->un.ord = sc->sc_mute[CSPORT_MONITOR] ? 1 : 0;
        !          1075:                error = 0;
        !          1076:                break;
        !          1077:        case CSAUDIO_OUTPUT_MUTE:
        !          1078:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1079:                        break;
        !          1080:                cp->un.ord = sc->sc_mute[CSPORT_SPEAKER] ? 1 : 0;
        !          1081:                error = 0;
        !          1082:                break;
        !          1083:        case CSAUDIO_REC_LVL:
        !          1084:                if (cp->type != AUDIO_MIXER_VALUE)
        !          1085:                        break;
        !          1086:                if (cp->un.value.num_channels == 1) {
        !          1087:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1088:                            AUDIO_MIN_GAIN;
        !          1089:                } else if (cp->un.value.num_channels == 2) {
        !          1090:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
        !          1091:                            AUDIO_MIN_GAIN;
        !          1092:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
        !          1093:                            AUDIO_MIN_GAIN;
        !          1094:                } else
        !          1095:                        break;
        !          1096:                error = 0;
        !          1097:                break;
        !          1098:        case CSAUDIO_RECORD_SOURCE:
        !          1099:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1100:                        break;
        !          1101:                cp->un.ord = MIC_IN_PORT;
        !          1102:                error = 0;
        !          1103:                break;
        !          1104:        case CSAUDIO_OUTPUT:
        !          1105:                if (cp->type != AUDIO_MIXER_ENUM)
        !          1106:                        break;
        !          1107:                cp->un.ord = sc->sc_out_port;
        !          1108:                error = 0;
        !          1109:                break;
        !          1110:        }
        !          1111:        return (error);
        !          1112: }
        !          1113:
        !          1114: int
        !          1115: ce4231_query_devinfo(addr, dip)
        !          1116:        void *addr;
        !          1117:        mixer_devinfo_t *dip;
        !          1118: {
        !          1119:        int err = 0;
        !          1120:
        !          1121:        switch (dip->index) {
        !          1122:        case CSAUDIO_MIC_LVL:           /* mono/microphone mixer */
        !          1123:                dip->type = AUDIO_MIXER_VALUE;
        !          1124:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1125:                dip->prev = AUDIO_MIXER_LAST;
        !          1126:                dip->next = CSAUDIO_MIC_MUTE;
        !          1127:                strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name);
        !          1128:                dip->un.v.num_channels = 1;
        !          1129:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1130:                    sizeof dip->un.v.units.name);
        !          1131:                break;
        !          1132:        case CSAUDIO_DAC_LVL:           /* dacout */
        !          1133:                dip->type = AUDIO_MIXER_VALUE;
        !          1134:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1135:                dip->prev = AUDIO_MIXER_LAST;
        !          1136:                dip->next = CSAUDIO_DAC_MUTE;
        !          1137:                strlcpy(dip->label.name, AudioNdac, sizeof dip->label.name);
        !          1138:                dip->un.v.num_channels = 2;
        !          1139:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1140:                    sizeof dip->un.v.units.name);
        !          1141:                break;
        !          1142:        case CSAUDIO_LINE_IN_LVL:       /* line */
        !          1143:                dip->type = AUDIO_MIXER_VALUE;
        !          1144:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1145:                dip->prev = AUDIO_MIXER_LAST;
        !          1146:                dip->next = CSAUDIO_LINE_IN_MUTE;
        !          1147:                strlcpy(dip->label.name, AudioNline, sizeof dip->label.name);
        !          1148:                dip->un.v.num_channels = 2;
        !          1149:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1150:                    sizeof dip->un.v.units.name);
        !          1151:                break;
        !          1152:        case CSAUDIO_CD_LVL:            /* cd */
        !          1153:                dip->type = AUDIO_MIXER_VALUE;
        !          1154:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1155:                dip->prev = AUDIO_MIXER_LAST;
        !          1156:                dip->next = CSAUDIO_CD_MUTE;
        !          1157:                strlcpy(dip->label.name, AudioNcd, sizeof dip->label.name);
        !          1158:                dip->un.v.num_channels = 2;
        !          1159:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1160:                    sizeof dip->un.v.units.name);
        !          1161:                break;
        !          1162:        case CSAUDIO_MONITOR_LVL:       /* monitor level */
        !          1163:                dip->type = AUDIO_MIXER_VALUE;
        !          1164:                dip->mixer_class = CSAUDIO_MONITOR_CLASS;
        !          1165:                dip->prev = AUDIO_MIXER_LAST;
        !          1166:                dip->next = CSAUDIO_MONITOR_MUTE;
        !          1167:                strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
        !          1168:                dip->un.v.num_channels = 1;
        !          1169:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1170:                    sizeof dip->un.v.units.name);
        !          1171:                break;
        !          1172:        case CSAUDIO_OUTPUT_LVL:
        !          1173:                dip->type = AUDIO_MIXER_VALUE;
        !          1174:                dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
        !          1175:                dip->prev = AUDIO_MIXER_LAST;
        !          1176:                dip->next = CSAUDIO_OUTPUT_MUTE;
        !          1177:                strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
        !          1178:                dip->un.v.num_channels = 2;
        !          1179:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1180:                    sizeof dip->un.v.units.name);
        !          1181:                break;
        !          1182:        case CSAUDIO_LINE_IN_MUTE:
        !          1183:                dip->type = AUDIO_MIXER_ENUM;
        !          1184:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1185:                dip->prev = CSAUDIO_LINE_IN_LVL;
        !          1186:                dip->next = AUDIO_MIXER_LAST;
        !          1187:                goto mute;
        !          1188:        case CSAUDIO_DAC_MUTE:
        !          1189:                dip->type = AUDIO_MIXER_ENUM;
        !          1190:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1191:                dip->prev = CSAUDIO_DAC_LVL;
        !          1192:                dip->next = AUDIO_MIXER_LAST;
        !          1193:                goto mute;
        !          1194:        case CSAUDIO_CD_MUTE:
        !          1195:                dip->type = AUDIO_MIXER_ENUM;
        !          1196:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1197:                dip->prev = CSAUDIO_CD_LVL;
        !          1198:                dip->next = AUDIO_MIXER_LAST;
        !          1199:                goto mute;
        !          1200:        case CSAUDIO_MIC_MUTE:
        !          1201:                dip->type = AUDIO_MIXER_ENUM;
        !          1202:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1203:                dip->prev = CSAUDIO_MIC_LVL;
        !          1204:                dip->next = AUDIO_MIXER_LAST;
        !          1205:                goto mute;
        !          1206:        case CSAUDIO_MONITOR_MUTE:
        !          1207:                dip->type = AUDIO_MIXER_ENUM;
        !          1208:                dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
        !          1209:                dip->prev = CSAUDIO_MONITOR_LVL;
        !          1210:                dip->next = AUDIO_MIXER_LAST;
        !          1211:                goto mute;
        !          1212:        case CSAUDIO_OUTPUT_MUTE:
        !          1213:                dip->type = AUDIO_MIXER_ENUM;
        !          1214:                dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
        !          1215:                dip->prev = CSAUDIO_OUTPUT_LVL;
        !          1216:                dip->next = AUDIO_MIXER_LAST;
        !          1217:                goto mute;
        !          1218:
        !          1219:        mute:
        !          1220:                strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
        !          1221:                dip->un.e.num_mem = 2;
        !          1222:                strlcpy(dip->un.e.member[0].label.name, AudioNon,
        !          1223:                    sizeof dip->un.e.member[0].label.name);
        !          1224:                dip->un.e.member[0].ord = 0;
        !          1225:                strlcpy(dip->un.e.member[1].label.name, AudioNoff,
        !          1226:                    sizeof dip->un.e.member[1].label.name);
        !          1227:                dip->un.e.member[1].ord = 1;
        !          1228:                break;
        !          1229:        case CSAUDIO_REC_LVL:           /* record level */
        !          1230:                dip->type = AUDIO_MIXER_VALUE;
        !          1231:                dip->mixer_class = CSAUDIO_RECORD_CLASS;
        !          1232:                dip->prev = AUDIO_MIXER_LAST;
        !          1233:                dip->next = CSAUDIO_RECORD_SOURCE;
        !          1234:                strlcpy(dip->label.name, AudioNrecord, sizeof dip->label.name);
        !          1235:                dip->un.v.num_channels = 2;
        !          1236:                strlcpy(dip->un.v.units.name, AudioNvolume,
        !          1237:                    sizeof dip->un.v.units.name);
        !          1238:                break;
        !          1239:        case CSAUDIO_RECORD_SOURCE:
        !          1240:                dip->type = AUDIO_MIXER_ENUM;
        !          1241:                dip->mixer_class = CSAUDIO_RECORD_CLASS;
        !          1242:                dip->prev = CSAUDIO_REC_LVL;
        !          1243:                dip->next = AUDIO_MIXER_LAST;
        !          1244:                strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
        !          1245:                dip->un.e.num_mem = 3;
        !          1246:                strlcpy(dip->un.e.member[0].label.name, AudioNcd,
        !          1247:                    sizeof dip->un.e.member[0].label.name);
        !          1248:                dip->un.e.member[0].ord = DAC_IN_PORT;
        !          1249:                strlcpy(dip->un.e.member[1].label.name, AudioNmicrophone,
        !          1250:                    sizeof dip->un.e.member[1].label.name);
        !          1251:                dip->un.e.member[1].ord = MIC_IN_PORT;
        !          1252:                strlcpy(dip->un.e.member[2].label.name, AudioNdac,
        !          1253:                    sizeof dip->un.e.member[2].label.name);
        !          1254:                dip->un.e.member[2].ord = AUX1_IN_PORT;
        !          1255:                strlcpy(dip->un.e.member[3].label.name, AudioNline,
        !          1256:                    sizeof dip->un.e.member[3].label.name);
        !          1257:                dip->un.e.member[3].ord = LINE_IN_PORT;
        !          1258:                break;
        !          1259:        case CSAUDIO_OUTPUT:
        !          1260:                dip->type = AUDIO_MIXER_ENUM;
        !          1261:                dip->mixer_class = CSAUDIO_MONITOR_CLASS;
        !          1262:                dip->prev = dip->next = AUDIO_MIXER_LAST;
        !          1263:                strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
        !          1264:                dip->un.e.num_mem = 3;
        !          1265:                strlcpy(dip->un.e.member[0].label.name, AudioNspeaker,
        !          1266:                    sizeof dip->un.e.member[0].label.name);
        !          1267:                dip->un.e.member[0].ord = CSPORT_SPEAKER;
        !          1268:                strlcpy(dip->un.e.member[1].label.name, AudioNline,
        !          1269:                    sizeof dip->un.e.member[1].label.name);
        !          1270:                dip->un.e.member[1].ord = CSPORT_LINEOUT;
        !          1271:                strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
        !          1272:                    sizeof dip->un.e.member[2].label.name);
        !          1273:                dip->un.e.member[2].ord = CSPORT_HEADPHONE;
        !          1274:                break;
        !          1275:        case CSAUDIO_INPUT_CLASS:       /* input class descriptor */
        !          1276:                dip->type = AUDIO_MIXER_CLASS;
        !          1277:                dip->mixer_class = CSAUDIO_INPUT_CLASS;
        !          1278:                dip->prev = AUDIO_MIXER_LAST;
        !          1279:                dip->next = AUDIO_MIXER_LAST;
        !          1280:                strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
        !          1281:                break;
        !          1282:        case CSAUDIO_OUTPUT_CLASS:      /* output class descriptor */
        !          1283:                dip->type = AUDIO_MIXER_CLASS;
        !          1284:                dip->mixer_class = CSAUDIO_OUTPUT_CLASS;
        !          1285:                dip->prev = AUDIO_MIXER_LAST;
        !          1286:                dip->next = AUDIO_MIXER_LAST;
        !          1287:                strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
        !          1288:                break;
        !          1289:        case CSAUDIO_MONITOR_CLASS:     /* monitor class descriptor */
        !          1290:                dip->type = AUDIO_MIXER_CLASS;
        !          1291:                dip->mixer_class = CSAUDIO_MONITOR_CLASS;
        !          1292:                dip->prev = AUDIO_MIXER_LAST;
        !          1293:                dip->next = AUDIO_MIXER_LAST;
        !          1294:                strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
        !          1295:                break;
        !          1296:        case CSAUDIO_RECORD_CLASS:      /* record class descriptor */
        !          1297:                dip->type = AUDIO_MIXER_CLASS;
        !          1298:                dip->mixer_class = CSAUDIO_RECORD_CLASS;
        !          1299:                dip->prev = AUDIO_MIXER_LAST;
        !          1300:                dip->next = AUDIO_MIXER_LAST;
        !          1301:                strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
        !          1302:                break;
        !          1303:        default:
        !          1304:                err = ENXIO;
        !          1305:        }
        !          1306:
        !          1307:        return (err);
        !          1308: }
        !          1309:
        !          1310: int
        !          1311: ce4231_get_props(addr)
        !          1312:        void *addr;
        !          1313: {
        !          1314:        return (AUDIO_PROP_FULLDUPLEX);
        !          1315: }
        !          1316:
        !          1317: /*
        !          1318:  * Hardware interrupt handler
        !          1319:  */
        !          1320: int
        !          1321: ce4231_cintr(v)
        !          1322:        void *v;
        !          1323: {
        !          1324:        return (0);
        !          1325: }
        !          1326:
        !          1327: int
        !          1328: ce4231_pintr(v)
        !          1329:        void *v;
        !          1330: {
        !          1331:        struct ce4231_softc *sc = (struct ce4231_softc *)v;
        !          1332:        u_int32_t csr;
        !          1333:        u_int8_t reg, status;
        !          1334:        struct cs_dma *p;
        !          1335:        int r = 0;
        !          1336:
        !          1337:        csr = P_READ(sc, EBDMA_DCSR);
        !          1338:        status = CS_READ(sc, AD1848_STATUS);
        !          1339:        if (status & (INTERRUPT_STATUS | SAMPLE_ERROR)) {
        !          1340:                reg = ce4231_read(sc, CS_IRQ_STATUS);
        !          1341:                if (reg & CS_AFS_PI) {
        !          1342:                        ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
        !          1343:                        ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
        !          1344:                }
        !          1345:                CS_WRITE(sc, AD1848_STATUS, 0);
        !          1346:        }
        !          1347:
        !          1348:        P_WRITE(sc, EBDMA_DCSR, csr);
        !          1349:
        !          1350:        if (csr & EBDCSR_INT)
        !          1351:                r = 1;
        !          1352:
        !          1353:        if ((csr & EBDCSR_TC) || ((csr & EBDCSR_A_LOADED) == 0)) {
        !          1354:                u_long nextaddr, togo;
        !          1355:
        !          1356:                p = sc->sc_nowplaying;
        !          1357:                togo = sc->sc_playsegsz - sc->sc_playcnt;
        !          1358:                if (togo == 0) {
        !          1359:                        nextaddr = (u_int32_t)p->dmamap->dm_segs[0].ds_addr;
        !          1360:                        sc->sc_playcnt = togo = sc->sc_blksz;
        !          1361:                } else {
        !          1362:                        nextaddr = sc->sc_lastaddr;
        !          1363:                        if (togo > sc->sc_blksz)
        !          1364:                                togo = sc->sc_blksz;
        !          1365:                        sc->sc_playcnt += togo;
        !          1366:                }
        !          1367:
        !          1368:                P_WRITE(sc, EBDMA_DCNT, togo);
        !          1369:                P_WRITE(sc, EBDMA_DADDR, nextaddr);
        !          1370:                sc->sc_lastaddr = nextaddr + togo;
        !          1371:
        !          1372:                if (sc->sc_pintr != NULL)
        !          1373:                        (*sc->sc_pintr)(sc->sc_parg);
        !          1374:                r = 1;
        !          1375:        }
        !          1376:
        !          1377:        return (r);
        !          1378: }
        !          1379:
        !          1380: void *
        !          1381: ce4231_alloc(addr, direction, size, pool, flags)
        !          1382:        void *addr;
        !          1383:        int direction;
        !          1384:        size_t size;
        !          1385:        int pool;
        !          1386:        int flags;
        !          1387: {
        !          1388:        struct ce4231_softc *sc = (struct ce4231_softc *)addr;
        !          1389:        bus_dma_tag_t dmat = sc->sc_dmatag;
        !          1390:        struct cs_dma *p;
        !          1391:
        !          1392:        p = (struct cs_dma *)malloc(sizeof(struct cs_dma), pool, flags);
        !          1393:        if (p == NULL)
        !          1394:                return (NULL);
        !          1395:
        !          1396:        if (bus_dmamap_create(dmat, size, 1, size, 0,
        !          1397:            BUS_DMA_NOWAIT, &p->dmamap) != 0)
        !          1398:                goto fail;
        !          1399:
        !          1400:        p->size = size;
        !          1401:
        !          1402:        if (bus_dmamem_alloc(dmat, size, 64*1024, 0, p->segs,
        !          1403:            sizeof(p->segs)/sizeof(p->segs[0]), &p->nsegs,
        !          1404:            BUS_DMA_NOWAIT) != 0)
        !          1405:                goto fail1;
        !          1406:
        !          1407:        if (bus_dmamem_map(dmat, p->segs, p->nsegs, p->size,
        !          1408:            &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
        !          1409:                goto fail2;
        !          1410:
        !          1411:        if (bus_dmamap_load(dmat, p->dmamap, p->addr, size, NULL,
        !          1412:            BUS_DMA_NOWAIT) != 0)
        !          1413:                goto fail3;
        !          1414:
        !          1415:        p->next = sc->sc_dmas;
        !          1416:        sc->sc_dmas = p;
        !          1417:        return (p->addr);
        !          1418:
        !          1419: fail3:
        !          1420:        bus_dmamem_unmap(dmat, p->addr, p->size);
        !          1421: fail2:
        !          1422:        bus_dmamem_free(dmat, p->segs, p->nsegs);
        !          1423: fail1:
        !          1424:        bus_dmamap_destroy(dmat, p->dmamap);
        !          1425: fail:
        !          1426:        free(p, pool);
        !          1427:        return (NULL);
        !          1428: }
        !          1429:
        !          1430: void
        !          1431: ce4231_free(addr, ptr, pool)
        !          1432:        void *addr;
        !          1433:        void *ptr;
        !          1434:        int pool;
        !          1435: {
        !          1436:        struct ce4231_softc *sc = addr;
        !          1437:        bus_dma_tag_t dmat = sc->sc_dmatag;
        !          1438:        struct cs_dma *p, **pp;
        !          1439:
        !          1440:        for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &(*pp)->next) {
        !          1441:                if (p->addr != ptr)
        !          1442:                        continue;
        !          1443:                bus_dmamap_unload(dmat, p->dmamap);
        !          1444:                bus_dmamem_unmap(dmat, p->addr, p->size);
        !          1445:                bus_dmamem_free(dmat, p->segs, p->nsegs);
        !          1446:                bus_dmamap_destroy(dmat, p->dmamap);
        !          1447:                *pp = p->next;
        !          1448:                free(p, pool);
        !          1449:                return;
        !          1450:        }
        !          1451:        printf("%s: attempt to free rogue pointer\n", sc->sc_dev.dv_xname);
        !          1452: }
        !          1453:
        !          1454: int
        !          1455: ce4231_trigger_output(addr, start, end, blksize, intr, arg, param)
        !          1456:        void *addr, *start, *end;
        !          1457:        int blksize;
        !          1458:        void (*intr)(void *);
        !          1459:        void *arg;
        !          1460:        struct audio_params *param;
        !          1461: {
        !          1462:        struct ce4231_softc *sc = addr;
        !          1463:        struct cs_dma *p;
        !          1464:        u_int32_t csr;
        !          1465:        vaddr_t n;
        !          1466:
        !          1467:        if (sc->sc_locked != 0) {
        !          1468:                printf("%s: trigger_output: already running\n",
        !          1469:                    sc->sc_dev.dv_xname);
        !          1470:                return (EINVAL);
        !          1471:        }
        !          1472:
        !          1473:        sc->sc_locked = 1;
        !          1474:        sc->sc_pintr = intr;
        !          1475:        sc->sc_parg = arg;
        !          1476:
        !          1477:        for (p = sc->sc_dmas; p->addr != start; p = p->next)
        !          1478:                /*EMPTY*/;
        !          1479:        if (p == NULL) {
        !          1480:                printf("%s: trigger_output: bad addr: %p\n",
        !          1481:                    sc->sc_dev.dv_xname, start);
        !          1482:                return (EINVAL);
        !          1483:        }
        !          1484:
        !          1485:        n = (char *)end - (char *)start;
        !          1486:
        !          1487:        /*
        !          1488:         * Do only `blksize' at a time, so audio_pint() is kept
        !          1489:         * synchronous with us...
        !          1490:         */
        !          1491:        sc->sc_blksz = blksize;
        !          1492:        sc->sc_nowplaying = p;
        !          1493:        sc->sc_playsegsz = n;
        !          1494:
        !          1495:        if (n > sc->sc_blksz)
        !          1496:                n = sc->sc_blksz;
        !          1497:
        !          1498:        sc->sc_playcnt = n;
        !          1499:
        !          1500:        csr = P_READ(sc, EBDMA_DCSR);
        !          1501:        if (csr & EBDCSR_DMAEN) {
        !          1502:                P_WRITE(sc, EBDMA_DCNT, (u_long)n);
        !          1503:                P_WRITE(sc, EBDMA_DADDR,
        !          1504:                    (u_long)p->dmamap->dm_segs[0].ds_addr);
        !          1505:        } else {
        !          1506:                P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET);
        !          1507:                P_WRITE(sc, EBDMA_DCSR, sc->sc_burst);
        !          1508:
        !          1509:                P_WRITE(sc, EBDMA_DCNT, (u_long)n);
        !          1510:                P_WRITE(sc, EBDMA_DADDR,
        !          1511:                    (u_long)p->dmamap->dm_segs[0].ds_addr);
        !          1512:
        !          1513:                P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | EBDCSR_DMAEN |
        !          1514:                    EBDCSR_INTEN | EBDCSR_CNTEN | EBDCSR_NEXTEN);
        !          1515:
        !          1516:                ce4231_write(sc, SP_LOWER_BASE_COUNT, 0xff);
        !          1517:                ce4231_write(sc, SP_UPPER_BASE_COUNT, 0xff);
        !          1518:                ce4231_write(sc, SP_INTERFACE_CONFIG,
        !          1519:                    ce4231_read(sc, SP_INTERFACE_CONFIG) | PLAYBACK_ENABLE);
        !          1520:        }
        !          1521:        sc->sc_lastaddr = p->dmamap->dm_segs[0].ds_addr + n;
        !          1522:
        !          1523:        return (0);
        !          1524: }
        !          1525:
        !          1526: int
        !          1527: ce4231_trigger_input(addr, start, end, blksize, intr, arg, param)
        !          1528:        void *addr, *start, *end;
        !          1529:        int blksize;
        !          1530:        void (*intr)(void *);
        !          1531:        void *arg;
        !          1532:        struct audio_params *param;
        !          1533: {
        !          1534:        return (ENXIO);
        !          1535: }

CVSweb