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

Annotation of sys/arch/macppc/dev/awacs.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: awacs.c,v 1.19 2007/04/22 22:31:14 deraadt Exp $      */
                      2: /*     $NetBSD: awacs.c,v 1.4 2001/02/26 21:07:51 wiz Exp $    */
                      3:
                      4: /*-
                      5:  * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
                     27:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  */
                     29:
                     30: #include <sys/param.h>
                     31: #include <sys/audioio.h>
                     32: #include <sys/device.h>
                     33: #include <sys/malloc.h>
                     34: #include <sys/systm.h>
                     35:
                     36: #include <dev/auconv.h>
                     37: #include <dev/audio_if.h>
                     38: #include <dev/mulaw.h>
                     39:
                     40: #include <machine/bus.h>
                     41: #include <machine/autoconf.h>
                     42: #include <macppc/dev/dbdma.h>
                     43:
                     44: #ifdef AWACS_DEBUG
                     45: # define DPRINTF printf
                     46: #else
                     47: # define DPRINTF while (0) printf
                     48: #endif
                     49:
                     50: #define        AWACS_DMALIST_MAX       32
                     51: #define        AWACS_DMASEG_MAX        NBPG
                     52:
                     53: struct awacs_dma {
                     54:        bus_dmamap_t map;
                     55:        caddr_t addr;
                     56:        bus_dma_segment_t segs[AWACS_DMALIST_MAX];
                     57:        int nsegs;
                     58:        size_t size;
                     59:        struct awacs_dma *next;
                     60: };
                     61:
                     62:
                     63: struct awacs_softc {
                     64:        struct device sc_dev;
                     65:
                     66:        void (*sc_ointr)(void *);       /* dma completion intr handler */
                     67:        void *sc_oarg;                  /* arg for sc_ointr() */
                     68:
                     69:        void (*sc_iintr)(void *);       /* dma completion intr handler */
                     70:        void *sc_iarg;                  /* arg for sc_iintr() */
                     71:
                     72:        u_int sc_record_source;         /* recording source mask */
                     73:        u_int sc_output_mask;           /* output source mask */
                     74:
                     75:        char *sc_reg;
                     76:        u_int sc_codecctl0;
                     77:        u_int sc_codecctl1;
                     78:        u_int sc_codecctl2;
                     79:        u_int sc_codecctl4;
                     80:        u_int sc_soundctl;
                     81:
                     82:        bus_dma_tag_t sc_dmat;
                     83:        struct dbdma_regmap *sc_odma;
                     84:        struct dbdma_regmap *sc_idma;
                     85:        struct dbdma_command *sc_odmacmd, *sc_odmap;
                     86:        struct dbdma_command *sc_idmacmd, *sc_idmap;
                     87:        dbdma_t sc_odbdma, sc_idbdma;
                     88:
                     89:        struct awacs_dma *sc_dmas;
                     90: };
                     91:
                     92: int awacs_match(struct device *, void *, void *);
                     93: void awacs_attach(struct device *, struct device *, void *);
                     94: int awacs_intr(void *);
                     95: int awacs_tx_intr(void *);
                     96: int awacs_rx_intr(void *);
                     97:
                     98: int awacs_open(void *, int);
                     99: void awacs_close(void *);
                    100: int awacs_query_encoding(void *, struct audio_encoding *);
                    101: int awacs_set_params(void *, int, int, struct audio_params *,
                    102:                         struct audio_params *);
                    103: int awacs_round_blocksize(void *, int);
                    104: int awacs_trigger_output(void *, void *, void *, int, void (*)(void *),
                    105:                             void *, struct audio_params *);
                    106: int awacs_trigger_input(void *, void *, void *, int, void (*)(void *),
                    107:                            void *, struct audio_params *);
                    108: int awacs_halt_output(void *);
                    109: int awacs_halt_input(void *);
                    110: int awacs_getdev(void *, struct audio_device *);
                    111: int awacs_set_port(void *, mixer_ctrl_t *);
                    112: int awacs_get_port(void *, mixer_ctrl_t *);
                    113: int awacs_query_devinfo(void *, mixer_devinfo_t *);
                    114: size_t awacs_round_buffersize(void *, int, size_t);
                    115: paddr_t awacs_mappage(void *, void *, off_t, int);
                    116: int awacs_get_props(void *);
                    117: void *awacs_allocm(void *, int, size_t, int, int);
                    118:
                    119: static inline u_int awacs_read_reg(struct awacs_softc *, int);
                    120: static inline void awacs_write_reg(struct awacs_softc *, int, int);
                    121: void awacs_write_codec(struct awacs_softc *, int);
                    122: void awacs_set_speaker_volume(struct awacs_softc *, int, int);
                    123: void awacs_set_ext_volume(struct awacs_softc *, int, int);
                    124: void awacs_set_rate(struct awacs_softc *, struct audio_params *);
                    125: void awacs_mono16_to_stereo16(void *, u_char *, int);
                    126: void awacs_swap_bytes_mono16_to_stereo16(void *, u_char *, int);
                    127: void awacs_cvt_ulinear_mono_16_be(void *, u_char *, int);
                    128: void awacs_cvt_ulinear_mono_16_le(void *, u_char *, int);
                    129:
                    130: struct cfattach awacs_ca = {
                    131:        sizeof(struct awacs_softc), awacs_match, awacs_attach
                    132: };
                    133:
                    134: struct cfdriver awacs_cd = {
                    135:        NULL, "awacs", DV_DULL
                    136: };
                    137:
                    138: struct audio_hw_if awacs_hw_if = {
                    139:        awacs_open,
                    140:        awacs_close,
                    141:        NULL,                   /* drain */
                    142:        awacs_query_encoding,
                    143:        awacs_set_params,
                    144:        awacs_round_blocksize,
                    145:        NULL,                   /* commit_setting */
                    146:        NULL,                   /* init_output */
                    147:        NULL,                   /* init_input */
                    148:        NULL,                   /* start_output */
                    149:        NULL,                   /* start_input */
                    150:        awacs_halt_output,
                    151:        awacs_halt_input,
                    152:        NULL,                   /* speaker_ctl */
                    153:        awacs_getdev,
                    154:        NULL,                   /* getfd */
                    155:        awacs_set_port,
                    156:        awacs_get_port,
                    157:        awacs_query_devinfo,
                    158:        awacs_allocm,           /* allocm */
                    159:        NULL,                   /* freem */
                    160:        awacs_round_buffersize, /* round_buffersize */
                    161:        awacs_mappage,
                    162:        awacs_get_props,
                    163:        awacs_trigger_output,
                    164:        awacs_trigger_input
                    165: };
                    166:
                    167: struct audio_device awacs_device = {
                    168:        "AWACS",
                    169:        "",
                    170:        "awacs"
                    171: };
                    172:
                    173: /* register offset */
                    174: #define AWACS_SOUND_CTRL       0x00
                    175: #define AWACS_CODEC_CTRL       0x10
                    176: #define AWACS_CODEC_STATUS     0x20
                    177: #define AWACS_CLIP_COUNT       0x30
                    178: #define AWACS_BYTE_SWAP                0x40
                    179:
                    180: /* sound control */
                    181: #define AWACS_INPUT_SUBFRAME0  0x00000001
                    182: #define AWACS_INPUT_SUBFRAME1  0x00000002
                    183: #define AWACS_INPUT_SUBFRAME2  0x00000004
                    184: #define AWACS_INPUT_SUBFRAME3  0x00000008
                    185:
                    186: #define AWACS_OUTPUT_SUBFRAME0 0x00000010
                    187: #define AWACS_OUTPUT_SUBFRAME1 0x00000020
                    188: #define AWACS_OUTPUT_SUBFRAME2 0x00000040
                    189: #define AWACS_OUTPUT_SUBFRAME3 0x00000080
                    190:
                    191: #define AWACS_RATE_44100       0x00000000
                    192: #define AWACS_RATE_29400       0x00000100
                    193: #define AWACS_RATE_22050       0x00000200
                    194: #define AWACS_RATE_17640       0x00000300
                    195: #define AWACS_RATE_14700       0x00000400
                    196: #define AWACS_RATE_11025       0x00000500
                    197: #define AWACS_RATE_8820                0x00000600
                    198: #define AWACS_RATE_7350                0x00000700
                    199: #define AWACS_RATE_MASK                0x00000700
                    200:
                    201: #define AWACS_CTL_CNTRLERR     (1 << 11)
                    202: #define AWACS_CTL_PORTCHG      (1 << 12)
                    203: #define AWACS_INT_CNTRLERR     (1 << 13)
                    204: #define AWACS_INT_PORTCHG      (1 << 14)
                    205:
                    206: /* codec control */
                    207: #define AWACS_CODEC_ADDR0      0x00000000
                    208: #define AWACS_CODEC_ADDR1      0x00001000
                    209: #define AWACS_CODEC_ADDR2      0x00002000
                    210: #define AWACS_CODEC_ADDR4      0x00004000
                    211: #define AWACS_CODEC_EMSEL0     0x00000000
                    212: #define AWACS_CODEC_EMSEL1     0x00400000
                    213: #define AWACS_CODEC_EMSEL2     0x00800000
                    214: #define AWACS_CODEC_EMSEL4     0x00c00000
                    215: #define AWACS_CODEC_BUSY       0x01000000
                    216:
                    217: /* cc0 */
                    218: #define AWACS_DEFAULT_CD_GAIN  0x000000bb
                    219: #define AWACS_INPUT_CD         0x00000200
                    220: #define AWACS_INPUT_LINE       0x00000400
                    221: #define AWACS_INPUT_MICROPHONE 0x00000800
                    222: #define AWACS_INPUT_MASK       0x00000e00
                    223:
                    224: /* cc1 */
                    225: #define AWACS_MUTE_SPEAKER     0x00000080
                    226: #define AWACS_MUTE_HEADPHONE   0x00000200
                    227:
                    228: const struct awacs_speed_tab {
                    229:        int rate;
                    230:        u_int32_t bits;
                    231: } awacs_speeds[] = {
                    232:        {  7350, AWACS_RATE_7350 },
                    233:        {  8820, AWACS_RATE_8820 },
                    234:        { 11025, AWACS_RATE_11025 },
                    235:        { 14700, AWACS_RATE_14700 },
                    236:        { 17640, AWACS_RATE_17640 },
                    237:        { 22050, AWACS_RATE_22050 },
                    238:        { 29400, AWACS_RATE_29400 },
                    239:        { 44100, AWACS_RATE_44100 },
                    240: };
                    241:
                    242: int
                    243: awacs_match(struct device *parent, void *match, void *aux)
                    244: {
                    245:        struct confargs *ca = aux;
                    246:
                    247:        if (strcmp(ca->ca_name, "awacs") != 0 &&
                    248:            strcmp(ca->ca_name, "davbus") != 0)
                    249:                return 0;
                    250:
                    251: #ifdef DEBUG
                    252:        printf("awacs: matched %s nreg %d nintr %d\n",
                    253:                ca->ca_name, ca->ca_nreg, ca->ca_nintr);
                    254: #endif
                    255:
                    256:        if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
                    257:                return 0;
                    258:
                    259:        /* XXX for now
                    260:        if (ca->ca_nintr > 12)
                    261:                return 0;
                    262:        */
                    263:
                    264:        return 1;
                    265: }
                    266:
                    267: void
                    268: awacs_attach(struct device *parent, struct device *self, void *aux)
                    269: {
                    270:        struct awacs_softc *sc = (struct awacs_softc *)self;
                    271:        struct confargs *ca = aux;
                    272:        int cirq, oirq, iirq;
                    273:        int cirq_type, oirq_type, iirq_type;
                    274:
                    275:        ca->ca_reg[0] += ca->ca_baseaddr;
                    276:        ca->ca_reg[2] += ca->ca_baseaddr;
                    277:        ca->ca_reg[4] += ca->ca_baseaddr;
                    278:
                    279:        sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1]);
                    280:
                    281:        sc->sc_dmat = ca->ca_dmat;
                    282:        sc->sc_odma = mapiodev(ca->ca_reg[2], ca->ca_reg[3]); /* out */
                    283:        sc->sc_idma = mapiodev(ca->ca_reg[4], ca->ca_reg[5]); /* in */
                    284:        sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
                    285:        sc->sc_odmacmd = sc->sc_odbdma->d_addr;
                    286:        sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, AWACS_DMALIST_MAX);
                    287:        sc->sc_idmacmd = sc->sc_idbdma->d_addr;
                    288:
                    289:        if (ca->ca_nintr == 24) {
                    290:                cirq = ca->ca_intr[0];
                    291:                oirq = ca->ca_intr[2];
                    292:                iirq = ca->ca_intr[4];
                    293:                cirq_type = ca->ca_intr[1] ? IST_LEVEL : IST_EDGE;
                    294:                oirq_type = ca->ca_intr[3] ? IST_LEVEL : IST_EDGE;
                    295:                iirq_type = ca->ca_intr[5] ? IST_LEVEL : IST_EDGE;
                    296:        } else {
                    297:                cirq = ca->ca_intr[0];
                    298:                oirq = ca->ca_intr[1];
                    299:                iirq = ca->ca_intr[2];
                    300:                cirq_type = oirq_type = iirq_type = IST_LEVEL;
                    301:        }
                    302:        mac_intr_establish(parent, cirq, cirq_type, IPL_AUDIO, awacs_intr,
                    303:            sc, sc->sc_dev.dv_xname);
                    304:        mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO, awacs_tx_intr,
                    305:            sc, sc->sc_dev.dv_xname);
                    306:        mac_intr_establish(parent, iirq, iirq_type, IPL_AUDIO, awacs_rx_intr,
                    307:            sc, sc->sc_dev.dv_xname);
                    308:
                    309:        printf(": irq %d,%d,%d",
                    310:                cirq, oirq, iirq);
                    311:
                    312:        sc->sc_soundctl = AWACS_INPUT_SUBFRAME0 | AWACS_OUTPUT_SUBFRAME0 |
                    313:            AWACS_RATE_44100 | AWACS_INT_PORTCHG;
                    314:        awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
                    315:
                    316:        sc->sc_codecctl0 = AWACS_CODEC_ADDR0 | AWACS_CODEC_EMSEL0;
                    317:        sc->sc_codecctl1 = AWACS_CODEC_ADDR1 | AWACS_CODEC_EMSEL0;
                    318:        sc->sc_codecctl2 = AWACS_CODEC_ADDR2 | AWACS_CODEC_EMSEL0;
                    319:        sc->sc_codecctl4 = AWACS_CODEC_ADDR4 | AWACS_CODEC_EMSEL0;
                    320:
                    321:        sc->sc_codecctl0 |= AWACS_INPUT_CD | AWACS_DEFAULT_CD_GAIN;
                    322:        awacs_write_codec(sc, sc->sc_codecctl0);
                    323:
                    324:        /* Set initial volume[s] */
                    325:        awacs_set_speaker_volume(sc, 80, 80);
                    326:        awacs_set_ext_volume(sc, 80, 80);
                    327:
                    328:        /* Set loopback (for CD?) */
                    329:        /* sc->sc_codecctl1 |= 0x440; */
                    330:        sc->sc_codecctl1 |= 0x40;
                    331:        awacs_write_codec(sc, sc->sc_codecctl1);
                    332:
                    333:        /* check for headphone present */
                    334:        if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
                    335:                /* default output to speakers */
                    336:                printf(" headphones");
                    337:                sc->sc_output_mask = 1 << 1;
                    338:                sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
                    339:                sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
                    340:                awacs_write_codec(sc, sc->sc_codecctl1);
                    341:        } else {
                    342:                /* default output to speakers */
                    343:                printf(" speaker");
                    344:                sc->sc_output_mask = 1 << 0;
                    345:                sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
                    346:                sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
                    347:                awacs_write_codec(sc, sc->sc_codecctl1);
                    348:        }
                    349:
                    350:        /* default input from CD */
                    351:        sc->sc_record_source = 1 << 0;
                    352:        sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
                    353:        sc->sc_codecctl0 |= AWACS_INPUT_CD;
                    354:        awacs_write_codec(sc, sc->sc_codecctl0);
                    355:
                    356:        /* Enable interrupts and looping mode. */
                    357:        /* XXX ... */
                    358:        awacs_halt_output(sc);
                    359:        awacs_halt_input(sc);
                    360:        printf("\n");
                    361:
                    362:        audio_attach_mi(&awacs_hw_if, sc, &sc->sc_dev);
                    363: }
                    364:
                    365: u_int
                    366: awacs_read_reg(struct awacs_softc *sc, int reg)
                    367: {
                    368:        char *addr = sc->sc_reg;
                    369:
                    370:        return in32rb(addr + reg);
                    371: }
                    372:
                    373: void
                    374: awacs_write_reg(struct awacs_softc *sc, int reg, int val)
                    375: {
                    376:        char *addr = sc->sc_reg;
                    377:
                    378:        out32rb(addr + reg, val);
                    379: }
                    380:
                    381: void
                    382: awacs_write_codec(struct awacs_softc *sc, int value)
                    383: {
                    384:        awacs_write_reg(sc, AWACS_CODEC_CTRL, value);
                    385:        while (awacs_read_reg(sc, AWACS_CODEC_CTRL) & AWACS_CODEC_BUSY);
                    386: }
                    387:
                    388: int
                    389: awacs_intr(void *v)
                    390: {
                    391:        int reason;
                    392:        struct awacs_softc *sc = v;
                    393:        reason = awacs_read_reg(sc, AWACS_SOUND_CTRL);
                    394:
                    395:        if (reason & AWACS_CTL_CNTRLERR) {
                    396:                /* change outputs ?? */
                    397:        }
                    398:        if (reason & AWACS_CTL_PORTCHG) {
                    399: #ifdef DEBUG
                    400:                printf("status = %x\n", awacs_read_reg(sc, AWACS_CODEC_STATUS));
                    401: #endif
                    402:
                    403:                if (awacs_read_reg(sc, AWACS_CODEC_STATUS) & 0x8) {
                    404:                        /* default output to speakers */
                    405:                        sc->sc_output_mask = 1 << 1;
                    406:                        sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
                    407:                        sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER;
                    408:                        awacs_write_codec(sc, sc->sc_codecctl1);
                    409:                } else {
                    410:                        /* default output to speakers */
                    411:                        sc->sc_output_mask = 1 << 0;
                    412:                        sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
                    413:                        sc->sc_codecctl1 |= AWACS_MUTE_HEADPHONE;
                    414:                        awacs_write_codec(sc, sc->sc_codecctl1);
                    415:                }
                    416:        }
                    417:
                    418:        awacs_write_reg(sc, AWACS_SOUND_CTRL, reason); /* clear interrupt */
                    419:        return 1;
                    420: }
                    421:
                    422: int
                    423: awacs_tx_intr(void *v)
                    424: {
                    425:        struct awacs_softc *sc = v;
                    426:        struct dbdma_command *cmd = sc->sc_odmap;
                    427:        u_int16_t c, status;
                    428:
                    429:        /* if not set we are not running */
                    430:        if (!cmd)
                    431:                return (0);
                    432:
                    433:        c = in16rb(&cmd->d_command);
                    434:        status = in16rb(&cmd->d_status);
                    435:
                    436:        if (c >> 12 == DBDMA_CMD_OUT_LAST)
                    437:                sc->sc_odmap = sc->sc_odmacmd;
                    438:        else
                    439:                sc->sc_odmap++;
                    440:
                    441:        if (c & (DBDMA_INT_ALWAYS << 4)) {
                    442:                cmd->d_status = 0;
                    443:                if (status)     /* status == 0x8400 */
                    444:                        if (sc->sc_ointr)
                    445:                                (*sc->sc_ointr)(sc->sc_oarg);
                    446:        }
                    447:
                    448:        return (1);
                    449: }
                    450: int
                    451: awacs_rx_intr(void *v)
                    452: {
                    453:        struct awacs_softc *sc = v;
                    454:        struct dbdma_command *cmd = sc->sc_idmap;
                    455:        u_int16_t c, status;
                    456:
                    457:        /* if not set we are not running */
                    458:        if (!cmd)
                    459:                return (0);
                    460:
                    461:        c = in16rb(&cmd->d_command);
                    462:        status = in16rb(&cmd->d_status);
                    463:
                    464:        if (c >> 12 == DBDMA_CMD_IN_LAST)
                    465:                sc->sc_idmap = sc->sc_idmacmd;
                    466:        else
                    467:                sc->sc_idmap++;
                    468:
                    469:        if (c & (DBDMA_INT_ALWAYS << 4)) {
                    470:                cmd->d_status = 0;
                    471:                if (status)     /* status == 0x8400 */
                    472:                        if (sc->sc_iintr)
                    473:                                (*sc->sc_iintr)(sc->sc_iarg);
                    474:        }
                    475:
                    476:        return (1);
                    477: }
                    478:
                    479: int
                    480: awacs_open(void *h, int flags)
                    481: {
                    482:        return 0;
                    483: }
                    484:
                    485: /*
                    486:  * Close function is called at splaudio().
                    487:  */
                    488: void
                    489: awacs_close(void *h)
                    490: {
                    491:        struct awacs_softc *sc = h;
                    492:
                    493:        awacs_halt_output(sc);
                    494:        awacs_halt_input(sc);
                    495:
                    496:        sc->sc_ointr = 0;
                    497:        sc->sc_iintr = 0;
                    498: }
                    499:
                    500: int
                    501: awacs_query_encoding(void *h, struct audio_encoding *ae)
                    502: {
                    503:        switch (ae->index) {
                    504:        case 0:
                    505:                strlcpy(ae->name, AudioEslinear, sizeof ae->name);
                    506:                ae->encoding = AUDIO_ENCODING_SLINEAR;
                    507:                ae->precision = 16;
                    508:                ae->flags = 0;
                    509:                break;
                    510:        case 1:
                    511:                strlcpy(ae->name, AudioEslinear_be, sizeof ae->name);
                    512:                ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    513:                ae->precision = 16;
                    514:                ae->flags = 0;
                    515:                break;
                    516:        case 2:
                    517:                strlcpy(ae->name, AudioEslinear_le, sizeof ae->name);
                    518:                ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    519:                ae->precision = 16;
                    520:                ae->flags = 0;
                    521:                break;
                    522:        case 3:
                    523:                strlcpy(ae->name, AudioEmulaw, sizeof ae->name);
                    524:                ae->encoding = AUDIO_ENCODING_ULAW;
                    525:                ae->precision = 8;
                    526:                ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    527:                break;
                    528:        case 4:
                    529:                strlcpy(ae->name, AudioEalaw, sizeof ae->name);
                    530:                ae->encoding = AUDIO_ENCODING_ALAW;
                    531:                ae->precision = 8;
                    532:                ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    533:                break;
                    534:        case 5:
                    535:                strlcpy(ae->name, AudioEulinear, sizeof ae->name);
                    536:                ae->encoding = AUDIO_ENCODING_ULINEAR;
                    537:                ae->precision = 16;
                    538:                ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    539:                break;
                    540:        case 6:
                    541:                strlcpy(ae->name, AudioEulinear_le, sizeof ae->name);
                    542:                ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    543:                ae->precision = 16;
                    544:                ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    545:                break;
                    546:        case 7:
                    547:                strlcpy(ae->name, AudioEulinear_be, sizeof ae->name);
                    548:                ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    549:                ae->precision = 16;
                    550:                ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    551:                break;
                    552:        default:
                    553:                return (EINVAL);
                    554:        }
                    555:        return (0);
                    556: }
                    557:
                    558: void
                    559: awacs_mono16_to_stereo16(void *v, u_char *p, int cc)
                    560: {
                    561:        int x;
                    562:        int16_t *src, *dst;
                    563:
                    564:        src = (void *)(p + cc);
                    565:        dst = (void *)(p + cc * 2);
                    566:        while (cc > 0) {
                    567:                x = *--src;
                    568:                *--dst = x;
                    569:                *--dst = x;
                    570:                cc -= 2;
                    571:        }
                    572: }
                    573:
                    574: void
                    575: awacs_swap_bytes_mono16_to_stereo16(void *v, u_char *p, int cc)
                    576: {
                    577:        swap_bytes(v, p, cc);
                    578:        awacs_mono16_to_stereo16(v, p, cc);
                    579: }
                    580:
                    581: void
                    582: awacs_cvt_ulinear_mono_16_le(void *v, u_char *p, int cc)
                    583: {
                    584:        swap_bytes_change_sign16_be(v, p, cc);
                    585:        awacs_mono16_to_stereo16(v, p, cc);
                    586: }
                    587:
                    588: void
                    589: awacs_cvt_ulinear_mono_16_be(void *v, u_char *p, int cc)
                    590: {
                    591:        change_sign16_be(v, p, cc);
                    592:        awacs_mono16_to_stereo16(v, p, cc);
                    593: }
                    594:
                    595: int
                    596: awacs_set_params(void *h, int setmode, int usemode, struct audio_params *play,
                    597:     struct audio_params *rec)
                    598: {
                    599:        struct awacs_softc *sc = h;
                    600:        struct audio_params *p;
                    601:        int mode;
                    602:
                    603:        /*
                    604:         * This device only has one clock, so make the sample rates match.
                    605:         */
                    606:        if (play->sample_rate != rec->sample_rate &&
                    607:            usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
                    608:                if (setmode == AUMODE_PLAY) {
                    609:                        rec->sample_rate = play->sample_rate;
                    610:                        setmode |= AUMODE_RECORD;
                    611:                } else if (setmode == AUMODE_RECORD) {
                    612:                        play->sample_rate = rec->sample_rate;
                    613:                        setmode |= AUMODE_PLAY;
                    614:                } else
                    615:                        return EINVAL;
                    616:        }
                    617:
                    618:        for (mode = AUMODE_RECORD; mode != -1;
                    619:             mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
                    620:                if ((setmode & mode) == 0)
                    621:                        continue;
                    622:
                    623:                p = mode == AUMODE_PLAY ? play : rec;
                    624:
                    625:                if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
                    626:                    (p->precision != 8 && p->precision != 16) ||
                    627:                    (p->channels != 1 && p->channels != 2))
                    628:                        return EINVAL;
                    629:
                    630:                p->factor = 1;
                    631:                p->sw_code = NULL;
                    632:                awacs_write_reg(sc, AWACS_BYTE_SWAP, 0);
                    633:
                    634:                switch (p->encoding) {
                    635:
                    636:                case AUDIO_ENCODING_SLINEAR_LE:
                    637:                        if (p->channels == 2 && p->precision == 16) {
                    638:                                p->sw_code = swap_bytes;
                    639:                                break;
                    640:                        }
                    641:                        if (p->channels == 1 && p->precision == 16) {
                    642:                                p->factor = 2;
                    643:                                p->sw_code =
                    644:                                    awacs_swap_bytes_mono16_to_stereo16;
                    645:                                break;
                    646:                        }
                    647:                        return (EINVAL);
                    648:                case AUDIO_ENCODING_SLINEAR_BE:
                    649:                        if (p->channels == 2 && p->precision == 16)
                    650:                                break;
                    651:                        if (p->channels == 1 && p->precision == 16) {
                    652:                                p->factor = 2;
                    653:                                p->sw_code = awacs_mono16_to_stereo16;
                    654:                                break;
                    655:                        }
                    656:                        return (EINVAL);
                    657:                case AUDIO_ENCODING_ULINEAR_LE:
                    658:                        if (p->channels == 2 && p->precision == 16) {
                    659:                                p->sw_code = swap_bytes_change_sign16_be;
                    660:                                break;
                    661:                        }
                    662:                        if (p->channels == 1 && p->precision == 16) {
                    663:                                p->factor = 2;
                    664:                                p->sw_code = awacs_cvt_ulinear_mono_16_le;
                    665:                                break;
                    666:                        }
                    667:                        return (EINVAL);
                    668:                case AUDIO_ENCODING_ULINEAR_BE:
                    669:                        if (p->channels == 2 && p->precision == 16) {
                    670:                                p->sw_code = change_sign16_be;
                    671:                                break;
                    672:                        }
                    673:                        if (p->channels == 1 && p->precision == 16) {
                    674:                                p->factor = 2;
                    675:                                p->sw_code = awacs_cvt_ulinear_mono_16_be;
                    676:                                break;
                    677:                        }
                    678:                        return (EINVAL);
                    679:                case AUDIO_ENCODING_ULAW:
                    680:                        if (mode == AUMODE_PLAY) {
                    681:                                p->factor = 2;
                    682:                                p->sw_code = mulaw_to_slinear16_be;
                    683:                                break;
                    684:                        } else
                    685:                                break;  /* XXX */
                    686:                        return (EINVAL);
                    687:                case AUDIO_ENCODING_ALAW:
                    688:                        if (mode == AUMODE_PLAY) {
                    689:                                p->factor = 2;
                    690:                                p->sw_code = alaw_to_slinear16_be;
                    691:                                break;
                    692:                        }
                    693:                        return (EINVAL);
                    694:                default:
                    695:                        return (EINVAL);
                    696:                }
                    697:        }
                    698:
                    699:        /* Set the speed */
                    700:        awacs_set_rate(sc, p);
                    701:
                    702:        return (0);
                    703: }
                    704:
                    705: int
                    706: awacs_round_blocksize(void *h, int size)
                    707: {
                    708:        if (size < PAGE_SIZE)
                    709:                size = PAGE_SIZE;
                    710:        return (size + PAGE_SIZE / 2) & ~(PGOFSET);
                    711: }
                    712:
                    713: int
                    714: awacs_halt_output(void *h)
                    715: {
                    716:        struct awacs_softc *sc = h;
                    717:
                    718:        dbdma_stop(sc->sc_odma);
                    719:        dbdma_reset(sc->sc_odma);
                    720:        dbdma_stop(sc->sc_odma);
                    721:        sc->sc_odmap = NULL;
                    722:        return 0;
                    723: }
                    724:
                    725: int
                    726: awacs_halt_input(void *h)
                    727: {
                    728:        struct awacs_softc *sc = h;
                    729:
                    730:        dbdma_stop(sc->sc_idma);
                    731:        dbdma_reset(sc->sc_idma);
                    732:        return 0;
                    733: }
                    734:
                    735: int
                    736: awacs_getdev(void *h, struct audio_device *retp)
                    737: {
                    738:        *retp = awacs_device;
                    739:        return 0;
                    740: }
                    741:
                    742: enum {
                    743:        AWACS_OUTPUT_SELECT,
                    744:        AWACS_VOL_SPEAKER,
                    745:        AWACS_VOL_HEADPHONE,
                    746:        AWACS_OUTPUT_CLASS,
                    747:        AWACS_MONITOR_CLASS,
                    748:        AWACS_INPUT_SELECT,
                    749:        AWACS_VOL_INPUT,
                    750:        AWACS_INPUT_CLASS,
                    751:        AWACS_RECORD_CLASS,
                    752:        AWACS_ENUM_LAST
                    753: };
                    754:
                    755: int
                    756: awacs_set_port(void *h, mixer_ctrl_t *mc)
                    757: {
                    758:        struct awacs_softc *sc = h;
                    759:        int l, r;
                    760:
                    761:        DPRINTF("awacs_set_port dev = %d, type = %d\n", mc->dev, mc->type);
                    762:
                    763:        l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                    764:        r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                    765:
                    766:        switch (mc->dev) {
                    767:        case AWACS_OUTPUT_SELECT:
                    768:                /* no change necessary? */
                    769:                if (mc->un.mask == sc->sc_output_mask)
                    770:                        return 0;
                    771:                sc->sc_codecctl1 |= AWACS_MUTE_SPEAKER | AWACS_MUTE_HEADPHONE;
                    772:                if (mc->un.mask & 1 << 0)
                    773:                        sc->sc_codecctl1 &= ~AWACS_MUTE_SPEAKER;
                    774:                if (mc->un.mask & 1 << 1)
                    775:                        sc->sc_codecctl1 &= ~AWACS_MUTE_HEADPHONE;
                    776:
                    777:                awacs_write_codec(sc, sc->sc_codecctl1);
                    778:                sc->sc_output_mask = mc->un.mask;
                    779:                return 0;
                    780:
                    781:        case AWACS_VOL_SPEAKER:
                    782:                awacs_set_speaker_volume(sc, l, r);
                    783:                return 0;
                    784:
                    785:        case AWACS_VOL_HEADPHONE:
                    786:                awacs_set_ext_volume(sc, l, r);
                    787:                return 0;
                    788:
                    789:        case AWACS_VOL_INPUT:
                    790:                sc->sc_codecctl0 &= ~0xff;
                    791:                sc->sc_codecctl0 |= (l & 0xf0) | (r >> 4);
                    792:                awacs_write_codec(sc, sc->sc_codecctl0);
                    793:                return 0;
                    794:
                    795:        case AWACS_INPUT_SELECT:
                    796:                /* no change necessary? */
                    797:                if (mc->un.mask == sc->sc_record_source)
                    798:                        return 0;
                    799:                switch(mc->un.mask) {
                    800:                case 1<<0: /* CD */
                    801:                        sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
                    802:                        sc->sc_codecctl0 |= AWACS_INPUT_CD;
                    803:                        awacs_write_codec(sc, sc->sc_codecctl0);
                    804:                        break;
                    805:                case 1<<1: /* microphone */
                    806:                        sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
                    807:                        sc->sc_codecctl0 |= AWACS_INPUT_MICROPHONE;
                    808:                        awacs_write_codec(sc, sc->sc_codecctl0);
                    809:                        break;
                    810:                case 1<<2: /* line in */
                    811:                        sc->sc_codecctl0 &= ~AWACS_INPUT_MASK;
                    812:                        sc->sc_codecctl0 |= AWACS_INPUT_LINE;
                    813:                        awacs_write_codec(sc, sc->sc_codecctl0);
                    814:                        break;
                    815:                default: /* invalid argument */
                    816:                        return -1;
                    817:                }
                    818:                sc->sc_record_source = mc->un.mask;
                    819:                return 0;
                    820:        }
                    821:
                    822:        return ENXIO;
                    823: }
                    824:
                    825: int
                    826: awacs_get_port(void *h, mixer_ctrl_t *mc)
                    827: {
                    828:        struct awacs_softc *sc = h;
                    829:        int vol, l, r;
                    830:
                    831:        DPRINTF("awacs_get_port dev = %d, type = %d\n", mc->dev, mc->type);
                    832:
                    833:        switch (mc->dev) {
                    834:        case AWACS_OUTPUT_SELECT:
                    835:                mc->un.mask = sc->sc_output_mask;
                    836:                return 0;
                    837:
                    838:        case AWACS_VOL_SPEAKER:
                    839:                vol = sc->sc_codecctl4;
                    840:                l = (15 - ((vol & 0x3c0) >> 6)) * 16;
                    841:                r = (15 - (vol & 0x0f)) * 16;
                    842:                mc->un.mask = 1 << 0;
                    843:                mc->un.value.num_channels = 2;
                    844:                mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
                    845:                mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
                    846:                return 0;
                    847:
                    848:        case AWACS_VOL_HEADPHONE:
                    849:                vol = sc->sc_codecctl2;
                    850:                l = (15 - ((vol & 0x3c0) >> 6)) * 16;
                    851:                r = (15 - (vol & 0x0f)) * 16;
                    852:                mc->un.mask = 1 << 1;
                    853:                mc->un.value.num_channels = 2;
                    854:                mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
                    855:                mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
                    856:                return 0;
                    857:
                    858:        case AWACS_INPUT_SELECT:
                    859:                mc->un.mask = sc->sc_record_source;
                    860:                return 0;
                    861:
                    862:        case AWACS_VOL_INPUT:
                    863:                vol = sc->sc_codecctl0 & 0xff;
                    864:                l = (vol & 0xf0);
                    865:                r = (vol & 0x0f) << 4;
                    866:                mc->un.mask = sc->sc_record_source;
                    867:                mc->un.value.num_channels = 2;
                    868:                mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
                    869:                mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
                    870:                return 0;
                    871:
                    872:        default:
                    873:                return ENXIO;
                    874:        }
                    875:
                    876:        return 0;
                    877: }
                    878:
                    879: int
                    880: awacs_query_devinfo(void *h, mixer_devinfo_t *dip)
                    881: {
                    882:        DPRINTF("query_devinfo %d\n", dip->index);
                    883:
                    884:        switch (dip->index) {
                    885:
                    886:        case AWACS_OUTPUT_SELECT:
                    887:                dip->mixer_class = AWACS_OUTPUT_CLASS;
                    888:                strlcpy(dip->label.name, AudioNselect, sizeof dip->label.name);
                    889:                dip->type = AUDIO_MIXER_SET;
                    890:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    891:                dip->un.s.num_mem = 2;
                    892:                strlcpy(dip->un.s.member[0].label.name, AudioNspeaker,
                    893:                    sizeof dip->un.s.member[0].label.name);
                    894:                dip->un.s.member[0].mask = 1 << 0;
                    895:                strlcpy(dip->un.s.member[1].label.name, AudioNheadphone,
                    896:                    sizeof dip->un.s.member[0].label.name);
                    897:                dip->un.s.member[1].mask = 1 << 1;
                    898:                return 0;
                    899:
                    900:        case AWACS_VOL_SPEAKER:
                    901:                dip->mixer_class = AWACS_OUTPUT_CLASS;
                    902:                strlcpy(dip->label.name, AudioNspeaker,
                    903:                    sizeof dip->label.name);
                    904:                dip->type = AUDIO_MIXER_VALUE;
                    905:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    906:                dip->un.v.num_channels = 2;
                    907:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    908:                    sizeof dip->un.v.units.name);
                    909:                return 0;
                    910:
                    911:        case AWACS_VOL_HEADPHONE:
                    912:                dip->mixer_class = AWACS_OUTPUT_CLASS;
                    913:                strlcpy(dip->label.name, AudioNheadphone,
                    914:                    sizeof dip->label.name);
                    915:                dip->type = AUDIO_MIXER_VALUE;
                    916:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    917:                dip->un.v.num_channels = 2;
                    918:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    919:                    sizeof dip->un.v.units.name);
                    920:                return 0;
                    921:
                    922:        case AWACS_INPUT_SELECT:
                    923:                dip->mixer_class = AWACS_RECORD_CLASS;
                    924:                strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
                    925:                dip->type = AUDIO_MIXER_SET;
                    926:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    927:                dip->un.s.num_mem = 3;
                    928:                strlcpy(dip->un.s.member[0].label.name, AudioNcd,
                    929:                    sizeof dip->un.s.member[0].label.name);
                    930:                dip->un.s.member[0].mask = 1 << 0;
                    931:                strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone,
                    932:                    sizeof dip->un.s.member[1].label.name);
                    933:                dip->un.s.member[1].mask = 1 << 1;
                    934:                strlcpy(dip->un.s.member[2].label.name, AudioNline,
                    935:                    sizeof dip->un.s.member[2].label.name);
                    936:                dip->un.s.member[2].mask = 1 << 2;
                    937:                return 0;
                    938:
                    939:        case AWACS_VOL_INPUT:
                    940:                dip->mixer_class = AWACS_RECORD_CLASS;
                    941:                strlcpy(dip->label.name, AudioNmaster, sizeof dip->label.name);
                    942:                dip->type = AUDIO_MIXER_VALUE;
                    943:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    944:                dip->un.v.num_channels = 2;
                    945:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    946:                    sizeof dip->un.v.units.name);
                    947:                return 0;
                    948:
                    949:        case AWACS_MONITOR_CLASS:
                    950:                dip->mixer_class = AWACS_MONITOR_CLASS;
                    951:                strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
                    952:                dip->type = AUDIO_MIXER_CLASS;
                    953:                dip->next = dip->prev = AUDIO_MIXER_LAST;
                    954:                return 0;
                    955:
                    956:        case AWACS_OUTPUT_CLASS:
                    957:                dip->mixer_class = AWACS_OUTPUT_CLASS;
                    958:                strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
                    959:                dip->type = AUDIO_MIXER_CLASS;
                    960:                dip->next = dip->prev = AUDIO_MIXER_LAST;
                    961:                return 0;
                    962:
                    963:        case AWACS_RECORD_CLASS:
                    964:                dip->mixer_class = AWACS_MONITOR_CLASS;
                    965:                strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
                    966:                dip->type = AUDIO_MIXER_CLASS;
                    967:                dip->next = dip->prev = AUDIO_MIXER_LAST;
                    968:                return 0;
                    969:        }
                    970:
                    971:        return ENXIO;
                    972: }
                    973:
                    974: size_t
                    975: awacs_round_buffersize(void *h, int dir, size_t size)
                    976: {
                    977:        size = (size + PGOFSET) & ~(PGOFSET);
                    978:        if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
                    979:                size = AWACS_DMALIST_MAX * AWACS_DMASEG_MAX;
                    980:        return (size);
                    981: }
                    982:
                    983: void *
                    984: awacs_allocm(void *h, int dir, size_t size, int type, int flags)
                    985: {
                    986:        struct awacs_softc *sc = h;
                    987:        struct awacs_dma *p;
                    988:        int error;
                    989:
                    990:        if (size > AWACS_DMALIST_MAX * AWACS_DMASEG_MAX)
                    991:                return (NULL);
                    992:
                    993:        p = malloc(sizeof(*p), type, flags);
                    994:        if (!p)
                    995:                return (NULL);
                    996:        bzero(p, sizeof(*p));
                    997:
                    998:        /* convert to the bus.h style, not used otherwise */
                    999:        if (flags & M_NOWAIT)
                   1000:                flags = BUS_DMA_NOWAIT;
                   1001:
                   1002:        p->size = size;
                   1003:        if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs,
                   1004:            1, &p->nsegs, flags)) != 0) {
                   1005:                printf("%s: unable to allocate dma, error = %d\n",
                   1006:                    sc->sc_dev.dv_xname, error);
                   1007:                free(p, type);
                   1008:                return NULL;
                   1009:        }
                   1010:
                   1011:        if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
                   1012:            &p->addr, flags | BUS_DMA_COHERENT)) != 0) {
                   1013:                printf("%s: unable to map dma, error = %d\n",
                   1014:                    sc->sc_dev.dv_xname, error);
                   1015:                bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
                   1016:                free(p, type);
                   1017:                return NULL;
                   1018:        }
                   1019:
                   1020:        if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1,
                   1021:            p->size, 0, flags, &p->map)) != 0) {
                   1022:                printf("%s: unable to create dma map, error = %d\n",
                   1023:                    sc->sc_dev.dv_xname, error);
                   1024:                bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
                   1025:                bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
                   1026:                free(p, type);
                   1027:                return NULL;
                   1028:        }
                   1029:
                   1030:        if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size,
                   1031:            NULL, flags)) != 0) {
                   1032:                printf("%s: unable to load dma map, error = %d\n",
                   1033:                    sc->sc_dev.dv_xname, error);
                   1034:                bus_dmamap_destroy(sc->sc_dmat, p->map);
                   1035:                bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
                   1036:                bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
                   1037:                free(p, type);
                   1038:                return NULL;
                   1039:        }
                   1040:
                   1041:        p->next = sc->sc_dmas;
                   1042:        sc->sc_dmas = p;
                   1043:
                   1044:        return p->addr;
                   1045: }
                   1046:
                   1047: paddr_t
                   1048: awacs_mappage(void *h, void *mem, off_t off, int prot)
                   1049: {
                   1050:        if (off < 0)
                   1051:                return -1;
                   1052:        return -1;      /* XXX */
                   1053: }
                   1054:
                   1055: int
                   1056: awacs_get_props(void *h)
                   1057: {
                   1058:        return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
                   1059: }
                   1060:
                   1061: int
                   1062: awacs_trigger_output(void *h, void *start, void *end, int bsize,
                   1063:     void (*intr)(void *), void *arg, struct audio_params *param)
                   1064: {
                   1065:        struct awacs_softc *sc = h;
                   1066:        struct awacs_dma *p;
                   1067:        struct dbdma_command *cmd = sc->sc_odmacmd;
                   1068:        vaddr_t spa, pa, epa;
                   1069:        int c;
                   1070:
                   1071:        DPRINTF("trigger_output %p %p 0x%x\n", start, end, bsize);
                   1072:
                   1073:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
                   1074:        if (!p)
                   1075:                return -1;
                   1076:
                   1077:        sc->sc_ointr = intr;
                   1078:        sc->sc_oarg = arg;
                   1079:        sc->sc_odmap = sc->sc_odmacmd;
                   1080:
                   1081:        spa = p->segs[0].ds_addr;
                   1082:        c = DBDMA_CMD_OUT_MORE;
                   1083:        for (pa = spa, epa = spa + (end - start);
                   1084:            pa < epa; pa += bsize, cmd++) {
                   1085:
                   1086:                if (pa + bsize == epa)
                   1087:                        c = DBDMA_CMD_OUT_LAST;
                   1088:
                   1089:                DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
                   1090:                        DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                   1091:        }
                   1092:
                   1093:        DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
                   1094:                DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
                   1095:        dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr);
                   1096:
                   1097:        dbdma_start(sc->sc_odma, sc->sc_odbdma);
                   1098:
                   1099:        return 0;
                   1100: }
                   1101:
                   1102: int
                   1103: awacs_trigger_input(void *h, void *start, void *end, int bsize,
                   1104:     void (*intr)(void *), void *arg, struct audio_params *param)
                   1105: {
                   1106:        struct awacs_softc *sc = h;
                   1107:        struct awacs_dma *p;
                   1108:        struct dbdma_command *cmd = sc->sc_idmacmd;
                   1109:        vaddr_t spa, pa, epa;
                   1110:        int c;
                   1111:
                   1112:        printf("trigger_input %p %p 0x%x\n", start, end, bsize);
                   1113:
                   1114:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
                   1115:        if (!p)
                   1116:                return -1;
                   1117:
                   1118:        sc->sc_iintr = intr;
                   1119:        sc->sc_iarg = arg;
                   1120:        sc->sc_idmap = sc->sc_idmacmd;
                   1121:
                   1122:        spa = p->segs[0].ds_addr;
                   1123:        c = DBDMA_CMD_IN_MORE;
                   1124:        for (pa = spa, epa = spa + (end - start);
                   1125:            pa < epa; pa += bsize, cmd++) {
                   1126:
                   1127:                if (pa + bsize == epa)
                   1128:                        c = DBDMA_CMD_IN_LAST;
                   1129:
                   1130:                DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
                   1131:                        DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                   1132:        }
                   1133:
                   1134:        DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
                   1135:                DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
                   1136:        dbdma_st32(&cmd->d_cmddep, sc->sc_idbdma->d_paddr);
                   1137:
                   1138:        dbdma_start(sc->sc_idma, sc->sc_idbdma);
                   1139:
                   1140:        return 0;
                   1141: }
                   1142:
                   1143: void
                   1144: awacs_set_speaker_volume(struct awacs_softc *sc, int left, int  right)
                   1145: {
                   1146:        int lval = 15 - (left  & 0xff) / 16;
                   1147:        int rval = 15 - (right & 0xff) / 16;
                   1148:
                   1149:        DPRINTF("speaker_volume %d %d\n", lval, rval);
                   1150:
                   1151:        sc->sc_codecctl4 &= ~0x3cf;
                   1152:        sc->sc_codecctl4 |= (lval << 6) | rval;
                   1153:        awacs_write_codec(sc, sc->sc_codecctl4);
                   1154: }
                   1155:
                   1156: void
                   1157: awacs_set_ext_volume(struct awacs_softc *sc, int left, int  right)
                   1158: {
                   1159:        int lval = 15 - (left  & 0xff) / 16;
                   1160:        int rval = 15 - (right & 0xff) / 16;
                   1161:
                   1162:        DPRINTF("ext_volume %d %d\n", lval, rval);
                   1163:
                   1164:        sc->sc_codecctl2 &= ~0x3cf;
                   1165:        sc->sc_codecctl2 |= (lval << 6) | rval;
                   1166:        awacs_write_codec(sc, sc->sc_codecctl2);
                   1167: }
                   1168:
                   1169: void
                   1170: awacs_set_rate(struct awacs_softc *sc, struct audio_params *p)
                   1171: {
                   1172:        int selected = -1;
                   1173:        size_t n, i;
                   1174:
                   1175:        n = sizeof(awacs_speeds)/sizeof(awacs_speeds[0]);
                   1176:
                   1177:        if (p->sample_rate < awacs_speeds[0].rate)
                   1178:                selected = 0;
                   1179:        if (p->sample_rate > awacs_speeds[n - 1].rate)
                   1180:                selected = n - 1;
                   1181:
                   1182:        for (i = 1; selected == -1 && i < n; i++) {
                   1183:                if (p->sample_rate == awacs_speeds[i].rate)
                   1184:                        selected = i;
                   1185:                else if (p->sample_rate < awacs_speeds[i].rate) {
                   1186:                        u_int diff1, diff2;
                   1187:
                   1188:                        diff1 = p->sample_rate - awacs_speeds[i - 1].rate;
                   1189:                        diff2 = awacs_speeds[i].rate - p->sample_rate;
                   1190:                        selected = (diff1 < diff2) ? i - 1 : i;
                   1191:                }
                   1192:        }
                   1193:
                   1194:        if (selected == -1)
                   1195:                selected = 0;
                   1196:
                   1197:        sc->sc_soundctl &= ~AWACS_RATE_MASK;
                   1198:        sc->sc_soundctl |= awacs_speeds[selected].bits;
                   1199:        p->sample_rate = awacs_speeds[selected].rate;
                   1200:        awacs_write_reg(sc, AWACS_SOUND_CTRL, sc->sc_soundctl);
                   1201: }

CVSweb