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

Annotation of sys/dev/sbus/cs4231.c, Revision 1.1

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

CVSweb