[BACK]Return to harmony.c CVS log [TXT][DIR] Up to [local] / sys / arch / hppa / gsc

Annotation of sys/arch/hppa/gsc/harmony.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: harmony.c,v 1.25 2006/05/20 01:58:27 mickey Exp $     */
                      2:
                      3: /*
                      4:  * Copyright (c) 2003 Jason L. Wright (jason@thought.net)
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     18:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     19:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     22:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     25:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     26:  * POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29: /*
                     30:  * Harmony (CS4215/AD1849 LASI) audio interface.
                     31:  */
                     32:
                     33: #include <sys/param.h>
                     34: #include <sys/kernel.h>
                     35: #include <sys/systm.h>
                     36: #include <sys/errno.h>
                     37: #include <sys/ioctl.h>
                     38: #include <sys/device.h>
                     39: #include <sys/proc.h>
                     40: #include <sys/malloc.h>
                     41:
                     42: #include <sys/audioio.h>
                     43: #include <dev/audio_if.h>
                     44: #include <dev/auconv.h>
                     45: #include <dev/rndvar.h>
                     46:
                     47: #include <machine/cpu.h>
                     48: #include <machine/intr.h>
                     49: #include <machine/iomod.h>
                     50: #include <machine/autoconf.h>
                     51: #include <machine/bus.h>
                     52:
                     53: #include <hppa/dev/cpudevs.h>
                     54: #include <hppa/gsc/gscbusvar.h>
                     55: #include <hppa/gsc/harmonyreg.h>
                     56: #include <hppa/gsc/harmonyvar.h>
                     57:
                     58: int     harmony_open(void *, int);
                     59: void    harmony_close(void *);
                     60: int     harmony_query_encoding(void *, struct audio_encoding *);
                     61: int     harmony_set_params(void *, int, int, struct audio_params *,
                     62:     struct audio_params *);
                     63: int     harmony_round_blocksize(void *, int);
                     64: int     harmony_commit_settings(void *);
                     65: int     harmony_halt_output(void *);
                     66: int     harmony_halt_input(void *);
                     67: int     harmony_getdev(void *, struct audio_device *);
                     68: int     harmony_set_port(void *, mixer_ctrl_t *);
                     69: int     harmony_get_port(void *, mixer_ctrl_t *);
                     70: int     harmony_query_devinfo(void *addr, mixer_devinfo_t *);
                     71: void *  harmony_allocm(void *, int, size_t, int, int);
                     72: void    harmony_freem(void *, void *, int);
                     73: size_t  harmony_round_buffersize(void *, int, size_t);
                     74: int     harmony_get_props(void *);
                     75: int     harmony_trigger_output(void *, void *, void *, int,
                     76:     void (*intr)(void *), void *, struct audio_params *);
                     77: int     harmony_trigger_input(void *, void *, void *, int,
                     78:     void (*intr)(void *), void *, struct audio_params *);
                     79:
                     80: struct audio_hw_if harmony_sa_hw_if = {
                     81:        harmony_open,
                     82:        harmony_close,
                     83:        NULL,
                     84:        harmony_query_encoding,
                     85:        harmony_set_params,
                     86:        harmony_round_blocksize,
                     87:        harmony_commit_settings,
                     88:        NULL,
                     89:        NULL,
                     90:        NULL,
                     91:        NULL,
                     92:        harmony_halt_output,
                     93:        harmony_halt_input,
                     94:        NULL,
                     95:        harmony_getdev,
                     96:        NULL,
                     97:        harmony_set_port,
                     98:        harmony_get_port,
                     99:        harmony_query_devinfo,
                    100:        harmony_allocm,
                    101:        harmony_freem,
                    102:        harmony_round_buffersize,
                    103:        NULL,
                    104:        harmony_get_props,
                    105:        harmony_trigger_output,
                    106:        harmony_trigger_input,
                    107: };
                    108:
                    109: int harmony_match(struct device *, void *, void *);
                    110: void harmony_attach(struct device *, struct device *, void *);
                    111: int harmony_intr(void *);
                    112: void harmony_intr_enable(struct harmony_softc *);
                    113: void harmony_intr_disable(struct harmony_softc *);
                    114: u_int32_t harmony_speed_bits(struct harmony_softc *, u_long *);
                    115: int harmony_set_gainctl(struct harmony_softc *);
                    116: void harmony_reset_codec(struct harmony_softc *);
                    117: void harmony_start_cp(struct harmony_softc *);
                    118: void harmony_tick_pb(void *);
                    119: void harmony_tick_cp(void *);
                    120: void harmony_try_more(struct harmony_softc *);
                    121:
                    122: void harmony_acc_tmo(void *);
                    123: #define        ADD_CLKALLICA(sc) do {                                          \
                    124:        (sc)->sc_acc <<= 1;                                             \
                    125:        (sc)->sc_acc |= READ_REG((sc), HARMONY_DIAG) & DIAG_CO;         \
                    126:        if ((sc)->sc_acc_cnt++ && !((sc)->sc_acc_cnt % 32))             \
                    127:                add_true_randomness((sc)->sc_acc_num ^= (sc)->sc_acc);  \
                    128: } while(0)
                    129:
                    130: int
                    131: harmony_match(parent, match, aux)
                    132:        struct device *parent;
                    133:        void *match, *aux;
                    134: {
                    135:        struct gsc_attach_args *ga = aux;
                    136:        bus_space_handle_t bh;
                    137:        u_int32_t cntl;
                    138:
                    139:        if (ga->ga_type.iodc_type == HPPA_TYPE_FIO) {
                    140:                if (ga->ga_type.iodc_sv_model == HPPA_FIO_A1 ||
                    141:                    ga->ga_type.iodc_sv_model == HPPA_FIO_A2NB ||
                    142:                    ga->ga_type.iodc_sv_model == HPPA_FIO_A1NB ||
                    143:                    ga->ga_type.iodc_sv_model == HPPA_FIO_A2) {
                    144:                        if (bus_space_map(ga->ga_iot, ga->ga_hpa,
                    145:                            HARMONY_NREGS, 0, &bh) != 0)
                    146:                                return (0);
                    147:                        cntl = bus_space_read_4(ga->ga_iot, bh, HARMONY_ID) &
                    148:                            ID_REV_MASK;
                    149:                        bus_space_unmap(ga->ga_iot, bh, HARMONY_NREGS);
                    150:                        if (cntl == ID_REV_TS || cntl == ID_REV_NOTS)
                    151:                                return (1);
                    152:                }
                    153:        }
                    154:        return (0);
                    155: }
                    156:
                    157: void
                    158: harmony_attach(parent, self, aux)
                    159:        struct device *parent, *self;
                    160:        void *aux;
                    161: {
                    162:        struct harmony_softc *sc = (struct harmony_softc *)self;
                    163:        struct gsc_attach_args *ga = aux;
                    164:        u_int8_t rev;
                    165:        u_int32_t cntl;
                    166:        int i;
                    167:
                    168:        sc->sc_bt = ga->ga_iot;
                    169:        sc->sc_dmat = ga->ga_dmatag;
                    170:
                    171:        if (bus_space_map(sc->sc_bt, ga->ga_hpa, HARMONY_NREGS, 0,
                    172:            &sc->sc_bh) != 0) {
                    173:                printf(": couldn't map registers\n");
                    174:                return;
                    175:        }
                    176:
                    177:        cntl = READ_REG(sc, HARMONY_ID);
                    178:        sc->sc_teleshare = (cntl & ID_REV_MASK) == ID_REV_TS;
                    179:
                    180:        if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct harmony_empty),
                    181:            PAGE_SIZE, 0, &sc->sc_empty_seg, 1, &sc->sc_empty_rseg,
                    182:            BUS_DMA_NOWAIT) != 0) {
                    183:                printf(": couldn't alloc DMA memory\n");
                    184:                bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
                    185:                return;
                    186:        }
                    187:        if (bus_dmamem_map(sc->sc_dmat, &sc->sc_empty_seg, 1,
                    188:            sizeof(struct harmony_empty), (caddr_t *)&sc->sc_empty_kva,
                    189:            BUS_DMA_NOWAIT) != 0) {
                    190:                printf(": couldn't map DMA memory\n");
                    191:                bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
                    192:                    sc->sc_empty_rseg);
                    193:                bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
                    194:                return;
                    195:        }
                    196:        if (bus_dmamap_create(sc->sc_dmat, sizeof(struct harmony_empty), 1,
                    197:            sizeof(struct harmony_empty), 0, BUS_DMA_NOWAIT,
                    198:            &sc->sc_empty_map) != 0) {
                    199:                printf(": can't create DMA map\n");
                    200:                bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
                    201:                    sizeof(struct harmony_empty));
                    202:                bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
                    203:                    sc->sc_empty_rseg);
                    204:                bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
                    205:                return;
                    206:        }
                    207:        if (bus_dmamap_load(sc->sc_dmat, sc->sc_empty_map, sc->sc_empty_kva,
                    208:            sizeof(struct harmony_empty), NULL, BUS_DMA_NOWAIT) != 0) {
                    209:                printf(": can't load DMA map\n");
                    210:                bus_dmamap_destroy(sc->sc_dmat, sc->sc_empty_map);
                    211:                bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_empty_kva,
                    212:                    sizeof(struct harmony_empty));
                    213:                bus_dmamem_free(sc->sc_dmat, &sc->sc_empty_seg,
                    214:                    sc->sc_empty_rseg);
                    215:                bus_space_unmap(sc->sc_bt, sc->sc_bh, HARMONY_NREGS);
                    216:                return;
                    217:        }
                    218:
                    219:        sc->sc_playback_empty = 0;
                    220:        for (i = 0; i < PLAYBACK_EMPTYS; i++)
                    221:                sc->sc_playback_paddrs[i] =
                    222:                    sc->sc_empty_map->dm_segs[0].ds_addr +
                    223:                    offsetof(struct harmony_empty, playback[i][0]);
                    224:
                    225:        sc->sc_capture_empty = 0;
                    226:        for (i = 0; i < CAPTURE_EMPTYS; i++)
                    227:                sc->sc_capture_paddrs[i] =
                    228:                    sc->sc_empty_map->dm_segs[0].ds_addr +
                    229:                    offsetof(struct harmony_empty, playback[i][0]);
                    230:
                    231:        bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
                    232:            offsetof(struct harmony_empty, playback[0][0]),
                    233:            PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
                    234:
                    235:        (void)gsc_intr_establish((struct gsc_softc *)parent, ga->ga_irq,
                    236:            IPL_AUDIO, harmony_intr, sc, sc->sc_dv.dv_xname);
                    237:
                    238:        /* set defaults */
                    239:        sc->sc_in_port = HARMONY_IN_LINE;
                    240:        sc->sc_out_port = HARMONY_OUT_SPEAKER;
                    241:        sc->sc_input_lvl.left = sc->sc_input_lvl.right = 240;
                    242:        sc->sc_output_lvl.left = sc->sc_output_lvl.right = 244;
                    243:        sc->sc_monitor_lvl.left = sc->sc_monitor_lvl.right = 208;
                    244:        sc->sc_outputgain = 0;
                    245:
                    246:        /* reset chip, and push default gain controls */
                    247:        harmony_reset_codec(sc);
                    248:
                    249:        cntl = READ_REG(sc, HARMONY_CNTL);
                    250:        rev = (cntl & CNTL_CODEC_REV_MASK) >> CNTL_CODEC_REV_SHIFT;
                    251:        printf(": rev %u", rev);
                    252:
                    253:        if (sc->sc_teleshare)
                    254:                printf(", teleshare");
                    255:        printf("\n");
                    256:
                    257:        if ((rev & CS4215_REV_VER) >= CS4215_REV_VER_E)
                    258:                sc->sc_hasulinear8 = 1;
                    259:
                    260:        strlcpy(sc->sc_audev.name, ga->ga_name, sizeof(sc->sc_audev.name));
                    261:        snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version,
                    262:            "%u.%u;%u", ga->ga_type.iodc_sv_rev,
                    263:            ga->ga_type.iodc_model, ga->ga_type.iodc_revision);
                    264:        strlcpy(sc->sc_audev.config, sc->sc_dv.dv_xname,
                    265:            sizeof(sc->sc_audev.config));
                    266:
                    267:        audio_attach_mi(&harmony_sa_hw_if, sc, &sc->sc_dv);
                    268:
                    269:        timeout_set(&sc->sc_acc_tmo, harmony_acc_tmo, sc);
                    270:        sc->sc_acc_num = 0xa5a5a5a5;
                    271: }
                    272:
                    273: void
                    274: harmony_reset_codec(struct harmony_softc *sc)
                    275: {
                    276:        /* silence */
                    277:        WRITE_REG(sc, HARMONY_GAINCTL, GAINCTL_OUTPUT_LEFT_M |
                    278:            GAINCTL_OUTPUT_RIGHT_M | GAINCTL_MONITOR_M);
                    279:
                    280:        /* start reset */
                    281:        WRITE_REG(sc, HARMONY_RESET, RESET_RST);
                    282:
                    283:        DELAY(100000);          /* wait at least 0.05 sec */
                    284:
                    285:        harmony_set_gainctl(sc);
                    286:        WRITE_REG(sc, HARMONY_RESET, 0);
                    287: }
                    288:
                    289: void
                    290: harmony_acc_tmo(void *v)
                    291: {
                    292:        struct harmony_softc *sc = v;
                    293:
                    294:        ADD_CLKALLICA(sc);
                    295:        timeout_add(&sc->sc_acc_tmo, 1);
                    296: }
                    297:
                    298: /*
                    299:  * interrupt handler
                    300:  */
                    301: int
                    302: harmony_intr(vsc)
                    303:        void *vsc;
                    304: {
                    305:        struct harmony_softc *sc = vsc;
                    306:        struct harmony_channel *c;
                    307:        u_int32_t dstatus;
                    308:        int r = 0;
                    309:
                    310:        ADD_CLKALLICA(sc);
                    311:
                    312:        harmony_intr_disable(sc);
                    313:
                    314:        dstatus = READ_REG(sc, HARMONY_DSTATUS);
                    315:
                    316:        if (dstatus & DSTATUS_PN) {
                    317:                struct harmony_dma *d;
                    318:                bus_addr_t nextaddr;
                    319:                bus_size_t togo;
                    320:
                    321:                r = 1;
                    322:                c = &sc->sc_playback;
                    323:                d = c->c_current;
                    324:                togo = c->c_segsz - c->c_cnt;
                    325:                if (togo == 0) {
                    326:                        nextaddr = d->d_map->dm_segs[0].ds_addr;
                    327:                        c->c_cnt = togo = c->c_blksz;
                    328:                } else {
                    329:                        nextaddr = c->c_lastaddr;
                    330:                        if (togo > c->c_blksz)
                    331:                                togo = c->c_blksz;
                    332:                        c->c_cnt += togo;
                    333:                }
                    334:
                    335:                bus_dmamap_sync(sc->sc_dmat, d->d_map,
                    336:                    nextaddr - d->d_map->dm_segs[0].ds_addr,
                    337:                    c->c_blksz, BUS_DMASYNC_PREWRITE);
                    338:
                    339:                WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
                    340:                SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
                    341:                c->c_lastaddr = nextaddr + togo;
                    342:                harmony_try_more(sc);
                    343:        }
                    344:
                    345:        dstatus = READ_REG(sc, HARMONY_DSTATUS);
                    346:
                    347:        if (dstatus & DSTATUS_RN) {
                    348:                c = &sc->sc_capture;
                    349:                r = 1;
                    350:                harmony_start_cp(sc);
                    351:                if (sc->sc_capturing && c->c_intr != NULL)
                    352:                        (*c->c_intr)(c->c_intrarg);
                    353:        }
                    354:
                    355:        if (READ_REG(sc, HARMONY_OV) & OV_OV) {
                    356:                sc->sc_ov = 1;
                    357:                WRITE_REG(sc, HARMONY_OV, 0);
                    358:        } else
                    359:                sc->sc_ov = 0;
                    360:
                    361:        harmony_intr_enable(sc);
                    362:
                    363:        return (r);
                    364: }
                    365:
                    366: void
                    367: harmony_intr_enable(struct harmony_softc *sc)
                    368: {
                    369:        WRITE_REG(sc, HARMONY_DSTATUS, DSTATUS_IE);
                    370:        SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
                    371: }
                    372:
                    373: void
                    374: harmony_intr_disable(struct harmony_softc *sc)
                    375: {
                    376:        WRITE_REG(sc, HARMONY_DSTATUS, 0);
                    377:        SYNC_REG(sc, HARMONY_DSTATUS, BUS_SPACE_BARRIER_WRITE);
                    378: }
                    379:
                    380: int
                    381: harmony_open(void *vsc, int flags)
                    382: {
                    383:        struct harmony_softc *sc = vsc;
                    384:
                    385:        if (sc->sc_open)
                    386:                return (EBUSY);
                    387:        sc->sc_open = 1;
                    388:        return (0);
                    389: }
                    390:
                    391: void
                    392: harmony_close(void *vsc)
                    393: {
                    394:        struct harmony_softc *sc = vsc;
                    395:
                    396:        harmony_halt_input(sc);
                    397:        harmony_halt_output(sc);
                    398:        harmony_intr_disable(sc);
                    399:        sc->sc_open = 0;
                    400: }
                    401:
                    402: int
                    403: harmony_query_encoding(void *vsc, struct audio_encoding *fp)
                    404: {
                    405:        struct harmony_softc *sc = vsc;
                    406:        int err = 0;
                    407:
                    408:        switch (fp->index) {
                    409:        case 0:
                    410:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
                    411:                fp->encoding = AUDIO_ENCODING_ULAW;
                    412:                fp->precision = 8;
                    413:                fp->flags = 0;
                    414:                break;
                    415:        case 1:
                    416:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
                    417:                fp->encoding = AUDIO_ENCODING_ALAW;
                    418:                fp->precision = 8;
                    419:                fp->flags = 0;
                    420:                break;
                    421:        case 2:
                    422:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
                    423:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    424:                fp->precision = 16;
                    425:                fp->flags = 0;
                    426:                break;
                    427:        case 3:
                    428:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
                    429:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    430:                fp->precision = 16;
                    431:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    432:                break;
                    433:        case 4:
                    434:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
                    435:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    436:                fp->precision = 16;
                    437:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    438:                break;
                    439:        case 5:
                    440:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
                    441:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    442:                fp->precision = 16;
                    443:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    444:                break;
                    445:        case 6:
                    446:                if (sc->sc_hasulinear8) {
                    447:                        strlcpy(fp->name, AudioEulinear, sizeof fp->name);
                    448:                        fp->encoding = AUDIO_ENCODING_ULINEAR;
                    449:                        fp->precision = 8;
                    450:                        fp->flags = 0;
                    451:                        break;
                    452:                }
                    453:                /*FALLTHROUGH*/
                    454:        case 7:
                    455:                if (sc->sc_hasulinear8) {
                    456:                        strlcpy(fp->name, AudioEslinear, sizeof fp->name);
                    457:                        fp->encoding = AUDIO_ENCODING_SLINEAR;
                    458:                        fp->precision = 8;
                    459:                        fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    460:                        break;
                    461:                }
                    462:                /*FALLTHROUGH*/
                    463:        default:
                    464:                err = EINVAL;
                    465:        }
                    466:        return (err);
                    467: }
                    468:
                    469: int
                    470: harmony_set_params(void *vsc, int setmode, int usemode,
                    471:     struct audio_params *p, struct audio_params *r)
                    472: {
                    473:        struct harmony_softc *sc = vsc;
                    474:        u_int32_t bits;
                    475:        void (*pswcode)(void *, u_char *, int cnt) = NULL;
                    476:        void (*rswcode)(void *, u_char *, int cnt) = NULL;
                    477:
                    478:        switch (p->encoding) {
                    479:        case AUDIO_ENCODING_ULAW:
                    480:                if (p->precision != 8)
                    481:                        return (EINVAL);
                    482:                bits = CNTL_FORMAT_ULAW;
                    483:                break;
                    484:        case AUDIO_ENCODING_ALAW:
                    485:                if (p->precision != 8)
                    486:                        return (EINVAL);
                    487:                bits = CNTL_FORMAT_ALAW;
                    488:                break;
                    489:        case AUDIO_ENCODING_SLINEAR_BE:
                    490:                if (p->precision == 8) {
                    491:                        bits = CNTL_FORMAT_ULINEAR8;
                    492:                        rswcode = pswcode = change_sign8;
                    493:                        break;
                    494:                }
                    495:                if (p->precision == 16) {
                    496:                        bits = CNTL_FORMAT_SLINEAR16BE;
                    497:                        break;
                    498:                }
                    499:                return (EINVAL);
                    500:        case AUDIO_ENCODING_ULINEAR:
                    501:                if (p->precision != 8)
                    502:                        return (EINVAL);
                    503:                bits = CNTL_FORMAT_ULINEAR8;
                    504:                break;
                    505:        case AUDIO_ENCODING_SLINEAR:
                    506:                if (p->precision != 8)
                    507:                        return (EINVAL);
                    508:                bits = CNTL_FORMAT_ULINEAR8;
                    509:                rswcode = pswcode = change_sign8;
                    510:                break;
                    511:        case AUDIO_ENCODING_SLINEAR_LE:
                    512:                if (p->precision == 8) {
                    513:                        bits = CNTL_FORMAT_ULINEAR8;
                    514:                        rswcode = pswcode = change_sign8;
                    515:                        break;
                    516:                }
                    517:                if (p->precision == 16) {
                    518:                        bits = CNTL_FORMAT_SLINEAR16BE;
                    519:                        rswcode = pswcode = swap_bytes;
                    520:                        break;
                    521:                }
                    522:                return (EINVAL);
                    523:        case AUDIO_ENCODING_ULINEAR_BE:
                    524:                if (p->precision == 8) {
                    525:                        bits = CNTL_FORMAT_ULINEAR8;
                    526:                        break;
                    527:                }
                    528:                if (p->precision == 16) {
                    529:                        bits = CNTL_FORMAT_SLINEAR16BE;
                    530:                        rswcode = pswcode = change_sign16_be;
                    531:                        break;
                    532:                }
                    533:                return (EINVAL);
                    534:        case AUDIO_ENCODING_ULINEAR_LE:
                    535:                if (p->precision == 8) {
                    536:                        bits = CNTL_FORMAT_ULINEAR8;
                    537:                        break;
                    538:                }
                    539:                if (p->precision == 16) {
                    540:                        bits = CNTL_FORMAT_SLINEAR16BE;
                    541:                        pswcode = change_sign16_swap_bytes_le;
                    542:                        rswcode = swap_bytes_change_sign16_le;
                    543:                        break;
                    544:                }
                    545:                return (EINVAL);
                    546:        default:
                    547:                return (EINVAL);
                    548:        }
                    549:
                    550:        if (sc->sc_outputgain)
                    551:                bits |= CNTL_OLB;
                    552:
                    553:        if (p->channels == 1)
                    554:                bits |= CNTL_CHANS_MONO;
                    555:        else if (p->channels == 2)
                    556:                bits |= CNTL_CHANS_STEREO;
                    557:        else
                    558:                return (EINVAL);
                    559:
                    560:        bits |= harmony_speed_bits(sc, &p->sample_rate);
                    561:        p->sw_code = pswcode;
                    562:        r->sw_code = rswcode;
                    563:        sc->sc_cntlbits = bits;
                    564:        sc->sc_need_commit = 1;
                    565:
                    566:        return (0);
                    567: }
                    568:
                    569: int
                    570: harmony_round_blocksize(void *vsc, int blk)
                    571: {
                    572:        return (HARMONY_BUFSIZE);
                    573: }
                    574:
                    575: int
                    576: harmony_commit_settings(void *vsc)
                    577: {
                    578:        struct harmony_softc *sc = vsc;
                    579:        u_int32_t reg;
                    580:        u_int8_t quietchar;
                    581:        int i;
                    582:
                    583:        if (sc->sc_need_commit == 0)
                    584:                return (0);
                    585:
                    586:        harmony_intr_disable(sc);
                    587:
                    588:        for (;;) {
                    589:                reg = READ_REG(sc, HARMONY_DSTATUS);
                    590:                if ((reg & (DSTATUS_PC | DSTATUS_RC)) == 0)
                    591:                        break;
                    592:        }
                    593:
                    594:        /* Setting some bits in gainctl requires a reset */
                    595:        harmony_reset_codec(sc);
                    596:
                    597:        /* set the silence character based on the encoding type */
                    598:        bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
                    599:            offsetof(struct harmony_empty, playback[0][0]),
                    600:            PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_POSTWRITE);
                    601:        switch (sc->sc_cntlbits & CNTL_FORMAT_MASK) {
                    602:        case CNTL_FORMAT_ULAW:
                    603:                quietchar = 0x7f;
                    604:                break;
                    605:        case CNTL_FORMAT_ALAW:
                    606:                quietchar = 0x55;
                    607:                break;
                    608:        case CNTL_FORMAT_SLINEAR16BE:
                    609:        case CNTL_FORMAT_ULINEAR8:
                    610:        default:
                    611:                quietchar = 0;
                    612:                break;
                    613:        }
                    614:        for (i = 0; i < PLAYBACK_EMPTYS; i++)
                    615:                memset(&sc->sc_empty_kva->playback[i][0],
                    616:                    quietchar, HARMONY_BUFSIZE);
                    617:        bus_dmamap_sync(sc->sc_dmat, sc->sc_empty_map,
                    618:            offsetof(struct harmony_empty, playback[0][0]),
                    619:            PLAYBACK_EMPTYS * HARMONY_BUFSIZE, BUS_DMASYNC_PREWRITE);
                    620:
                    621:        for (;;) {
                    622:                /* Wait for it to come out of control mode */
                    623:                reg = READ_REG(sc, HARMONY_CNTL);
                    624:                if ((reg & CNTL_C) == 0)
                    625:                        break;
                    626:        }
                    627:
                    628:        bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_CNTL,
                    629:            sc->sc_cntlbits | CNTL_C);
                    630:
                    631:        for (;;) {
                    632:                /* Wait for it to come out of control mode */
                    633:                reg = READ_REG(sc, HARMONY_CNTL);
                    634:                if ((reg & CNTL_C) == 0)
                    635:                        break;
                    636:        }
                    637:
                    638:        sc->sc_need_commit = 0;
                    639:
                    640:        if (sc->sc_playing || sc->sc_capturing)
                    641:                harmony_intr_enable(sc);
                    642:
                    643:        return (0);
                    644: }
                    645:
                    646: int
                    647: harmony_halt_output(void *vsc)
                    648: {
                    649:        struct harmony_softc *sc = vsc;
                    650:
                    651:        sc->sc_playing = 0;
                    652:        return (0);
                    653: }
                    654:
                    655: int
                    656: harmony_halt_input(void *vsc)
                    657: {
                    658:        struct harmony_softc *sc = vsc;
                    659:
                    660:        sc->sc_capturing = 0;
                    661:        return (0);
                    662: }
                    663:
                    664: int
                    665: harmony_getdev(void *vsc, struct audio_device *retp)
                    666: {
                    667:        struct harmony_softc *sc = vsc;
                    668:
                    669:        *retp = sc->sc_audev;
                    670:
                    671:        return (0);
                    672: }
                    673:
                    674: int
                    675: harmony_set_port(void *vsc, mixer_ctrl_t *cp)
                    676: {
                    677:        struct harmony_softc *sc = vsc;
                    678:        int err = EINVAL;
                    679:
                    680:        switch (cp->dev) {
                    681:        case HARMONY_PORT_INPUT_LVL:
                    682:                if (cp->type != AUDIO_MIXER_VALUE)
                    683:                        break;
                    684:                if (cp->un.value.num_channels == 1)
                    685:                        sc->sc_input_lvl.left = sc->sc_input_lvl.right =
                    686:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    687:                else if (cp->un.value.num_channels == 2) {
                    688:                        sc->sc_input_lvl.left =
                    689:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                    690:                        sc->sc_input_lvl.right =
                    691:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                    692:                } else
                    693:                        break;
                    694:                sc->sc_need_commit = 1;
                    695:                err = 0;
                    696:                break;
                    697:        case HARMONY_PORT_OUTPUT_LVL:
                    698:                if (cp->type != AUDIO_MIXER_VALUE)
                    699:                        break;
                    700:                if (cp->un.value.num_channels == 1)
                    701:                        sc->sc_output_lvl.left = sc->sc_output_lvl.right =
                    702:                            cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    703:                else if (cp->un.value.num_channels == 2) {
                    704:                        sc->sc_output_lvl.left =
                    705:                            cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
                    706:                        sc->sc_output_lvl.right =
                    707:                            cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
                    708:                } else
                    709:                        break;
                    710:                sc->sc_need_commit = 1;
                    711:                err = 0;
                    712:                break;
                    713:        case HARMONY_PORT_OUTPUT_GAIN:
                    714:                if (cp->type != AUDIO_MIXER_ENUM)
                    715:                        break;
                    716:                sc->sc_outputgain = cp->un.ord ? 1 : 0;
                    717:                err = 0;
                    718:                break;
                    719:        case HARMONY_PORT_MONITOR_LVL:
                    720:                if (cp->type != AUDIO_MIXER_VALUE)
                    721:                        break;
                    722:                if (cp->un.value.num_channels != 1)
                    723:                        break;
                    724:                sc->sc_monitor_lvl.left = sc->sc_input_lvl.right =
                    725:                    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
                    726:                sc->sc_need_commit = 1;
                    727:                err = 0;
                    728:                break;
                    729:        case HARMONY_PORT_RECORD_SOURCE:
                    730:                if (cp->type != AUDIO_MIXER_ENUM)
                    731:                        break;
                    732:                if (cp->un.ord != HARMONY_IN_LINE &&
                    733:                    cp->un.ord != HARMONY_IN_MIC)
                    734:                        break;
                    735:                sc->sc_in_port = cp->un.ord;
                    736:                err = 0;
                    737:                sc->sc_need_commit = 1;
                    738:                break;
                    739:        case HARMONY_PORT_OUTPUT_SOURCE:
                    740:                if (cp->type != AUDIO_MIXER_ENUM)
                    741:                        break;
                    742:                if (cp->un.ord != HARMONY_OUT_LINE &&
                    743:                    cp->un.ord != HARMONY_OUT_SPEAKER &&
                    744:                    cp->un.ord != HARMONY_OUT_HEADPHONE)
                    745:                        break;
                    746:                sc->sc_out_port = cp->un.ord;
                    747:                err = 0;
                    748:                sc->sc_need_commit = 1;
                    749:                break;
                    750:        }
                    751:
                    752:        return (err);
                    753: }
                    754:
                    755: int
                    756: harmony_get_port(void *vsc, mixer_ctrl_t *cp)
                    757: {
                    758:        struct harmony_softc *sc = vsc;
                    759:        int err = EINVAL;
                    760:
                    761:        switch (cp->dev) {
                    762:        case HARMONY_PORT_INPUT_LVL:
                    763:                if (cp->type != AUDIO_MIXER_VALUE)
                    764:                        break;
                    765:                if (cp->un.value.num_channels == 1) {
                    766:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
                    767:                            sc->sc_input_lvl.left;
                    768:                } else if (cp->un.value.num_channels == 2) {
                    769:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
                    770:                            sc->sc_input_lvl.left;
                    771:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
                    772:                            sc->sc_input_lvl.right;
                    773:                } else
                    774:                        break;
                    775:                err = 0;
                    776:                break;
                    777:        case HARMONY_PORT_INPUT_OV:
                    778:                if (cp->type != AUDIO_MIXER_ENUM)
                    779:                        break;
                    780:                cp->un.ord = sc->sc_ov ? 1 : 0;
                    781:                err = 0;
                    782:                break;
                    783:        case HARMONY_PORT_OUTPUT_LVL:
                    784:                if (cp->type != AUDIO_MIXER_VALUE)
                    785:                        break;
                    786:                if (cp->un.value.num_channels == 1) {
                    787:                        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
                    788:                            sc->sc_output_lvl.left;
                    789:                } else if (cp->un.value.num_channels == 2) {
                    790:                        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
                    791:                            sc->sc_output_lvl.left;
                    792:                        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
                    793:                            sc->sc_output_lvl.right;
                    794:                } else
                    795:                        break;
                    796:                err = 0;
                    797:                break;
                    798:        case HARMONY_PORT_OUTPUT_GAIN:
                    799:                if (cp->type != AUDIO_MIXER_ENUM)
                    800:                        break;
                    801:                cp->un.ord = sc->sc_outputgain ? 1 : 0;
                    802:                err = 0;
                    803:                break;
                    804:        case HARMONY_PORT_MONITOR_LVL:
                    805:                if (cp->type != AUDIO_MIXER_VALUE)
                    806:                        break;
                    807:                if (cp->un.value.num_channels != 1)
                    808:                        break;
                    809:                cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
                    810:                    sc->sc_monitor_lvl.left;
                    811:                err = 0;
                    812:                break;
                    813:        case HARMONY_PORT_RECORD_SOURCE:
                    814:                if (cp->type != AUDIO_MIXER_ENUM)
                    815:                        break;
                    816:                cp->un.ord = sc->sc_in_port;
                    817:                err = 0;
                    818:                break;
                    819:        case HARMONY_PORT_OUTPUT_SOURCE:
                    820:                if (cp->type != AUDIO_MIXER_ENUM)
                    821:                        break;
                    822:                cp->un.ord = sc->sc_out_port;
                    823:                err = 0;
                    824:                break;
                    825:        }
                    826:        return (0);
                    827: }
                    828:
                    829: int
                    830: harmony_query_devinfo(void *vsc, mixer_devinfo_t *dip)
                    831: {
                    832:        int err = 0;
                    833:
                    834:        switch (dip->index) {
                    835:        case HARMONY_PORT_INPUT_LVL:
                    836:                dip->type = AUDIO_MIXER_VALUE;
                    837:                dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
                    838:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    839:                strlcpy(dip->label.name, AudioNinput, sizeof dip->label.name);
                    840:                dip->un.v.num_channels = 2;
                    841:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    842:                    sizeof dip->un.v.units.name);
                    843:                break;
                    844:        case HARMONY_PORT_INPUT_OV:
                    845:                dip->type = AUDIO_MIXER_ENUM;
                    846:                dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
                    847:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    848:                strlcpy(dip->label.name, "overrange", sizeof dip->label.name);
                    849:                dip->un.e.num_mem = 2;
                    850:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
                    851:                    sizeof dip->un.e.member[0].label.name);
                    852:                dip->un.e.member[0].ord = 0;
                    853:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
                    854:                    sizeof dip->un.e.member[1].label.name);
                    855:                dip->un.e.member[1].ord = 1;
                    856:                break;
                    857:        case HARMONY_PORT_OUTPUT_LVL:
                    858:                dip->type = AUDIO_MIXER_VALUE;
                    859:                dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
                    860:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    861:                strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
                    862:                dip->un.v.num_channels = 2;
                    863:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    864:                    sizeof dip->un.v.units.name);
                    865:                break;
                    866:        case HARMONY_PORT_OUTPUT_GAIN:
                    867:                dip->type = AUDIO_MIXER_ENUM;
                    868:                dip->mixer_class = HARMONY_PORT_OUTPUT_CLASS;
                    869:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    870:                strlcpy(dip->label.name, "gain", sizeof dip->label.name);
                    871:                dip->un.e.num_mem = 2;
                    872:                strlcpy(dip->un.e.member[0].label.name, AudioNoff,
                    873:                    sizeof dip->un.e.member[0].label.name);
                    874:                dip->un.e.member[0].ord = 0;
                    875:                strlcpy(dip->un.e.member[1].label.name, AudioNon,
                    876:                    sizeof dip->un.e.member[1].label.name);
                    877:                dip->un.e.member[1].ord = 1;
                    878:                break;
                    879:        case HARMONY_PORT_MONITOR_LVL:
                    880:                dip->type = AUDIO_MIXER_VALUE;
                    881:                dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
                    882:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    883:                strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name);
                    884:                dip->un.v.num_channels = 1;
                    885:                strlcpy(dip->un.v.units.name, AudioNvolume,
                    886:                    sizeof dip->un.v.units.name);
                    887:                break;
                    888:        case HARMONY_PORT_RECORD_SOURCE:
                    889:                dip->type = AUDIO_MIXER_ENUM;
                    890:                dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
                    891:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    892:                strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
                    893:                dip->un.e.num_mem = 2;
                    894:                strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone,
                    895:                    sizeof dip->un.e.member[0].label.name);
                    896:                dip->un.e.member[0].ord = HARMONY_IN_MIC;
                    897:                strlcpy(dip->un.e.member[1].label.name, AudioNline,
                    898:                    sizeof dip->un.e.member[1].label.name);
                    899:                dip->un.e.member[1].ord = HARMONY_IN_LINE;
                    900:                break;
                    901:        case HARMONY_PORT_OUTPUT_SOURCE:
                    902:                dip->type = AUDIO_MIXER_ENUM;
                    903:                dip->mixer_class = HARMONY_PORT_MONITOR_CLASS;
                    904:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    905:                strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name);
                    906:                dip->un.e.num_mem = 3;
                    907:                strlcpy(dip->un.e.member[0].label.name, AudioNline,
                    908:                    sizeof dip->un.e.member[0].label.name);
                    909:                dip->un.e.member[0].ord = HARMONY_OUT_LINE;
                    910:                strlcpy(dip->un.e.member[1].label.name, AudioNspeaker,
                    911:                    sizeof dip->un.e.member[1].label.name);
                    912:                dip->un.e.member[1].ord = HARMONY_OUT_SPEAKER;
                    913:                strlcpy(dip->un.e.member[2].label.name, AudioNheadphone,
                    914:                    sizeof dip->un.e.member[2].label.name);
                    915:                dip->un.e.member[2].ord = HARMONY_OUT_HEADPHONE;
                    916:                break;
                    917:        case HARMONY_PORT_INPUT_CLASS:
                    918:                dip->type = AUDIO_MIXER_CLASS;
                    919:                dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
                    920:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    921:                strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name);
                    922:                break;
                    923:        case HARMONY_PORT_OUTPUT_CLASS:
                    924:                dip->type = AUDIO_MIXER_CLASS;
                    925:                dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
                    926:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    927:                strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name);
                    928:                break;
                    929:        case HARMONY_PORT_MONITOR_CLASS:
                    930:                dip->type = AUDIO_MIXER_CLASS;
                    931:                dip->mixer_class = HARMONY_PORT_INPUT_CLASS;
                    932:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    933:                strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name);
                    934:                break;
                    935:        case HARMONY_PORT_RECORD_CLASS:
                    936:                dip->type = AUDIO_MIXER_CLASS;
                    937:                dip->mixer_class = HARMONY_PORT_RECORD_CLASS;
                    938:                dip->prev = dip->next = AUDIO_MIXER_LAST;
                    939:                strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name);
                    940:                break;
                    941:        default:
                    942:                err = ENXIO;
                    943:                break;
                    944:        }
                    945:
                    946:        return (err);
                    947: }
                    948:
                    949: void *
                    950: harmony_allocm(void *vsc, int dir, size_t size, int pool, int flags)
                    951: {
                    952:        struct harmony_softc *sc = vsc;
                    953:        struct harmony_dma *d;
                    954:        int rseg;
                    955:
                    956:        d = (struct harmony_dma *)malloc(sizeof(struct harmony_dma), pool, flags);
                    957:        if (d == NULL)
                    958:                goto fail;
                    959:
                    960:        if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT,
                    961:            &d->d_map) != 0)
                    962:                goto fail1;
                    963:
                    964:        if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &d->d_seg, 1,
                    965:            &rseg, BUS_DMA_NOWAIT) != 0)
                    966:                goto fail2;
                    967:
                    968:        if (bus_dmamem_map(sc->sc_dmat, &d->d_seg, 1, size, &d->d_kva,
                    969:            BUS_DMA_NOWAIT) != 0)
                    970:                goto fail3;
                    971:
                    972:        if (bus_dmamap_load(sc->sc_dmat, d->d_map, d->d_kva, size, NULL,
                    973:            BUS_DMA_NOWAIT) != 0)
                    974:                goto fail4;
                    975:
                    976:        d->d_next = sc->sc_dmas;
                    977:        sc->sc_dmas = d;
                    978:        d->d_size = size;
                    979:        return (d->d_kva);
                    980:
                    981: fail4:
                    982:        bus_dmamem_unmap(sc->sc_dmat, d->d_kva, size);
                    983: fail3:
                    984:        bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
                    985: fail2:
                    986:        bus_dmamap_destroy(sc->sc_dmat, d->d_map);
                    987: fail1:
                    988:        free(d, pool);
                    989: fail:
                    990:        return (NULL);
                    991: }
                    992:
                    993: void
                    994: harmony_freem(void *vsc, void *ptr, int pool)
                    995: {
                    996:        struct harmony_softc *sc = vsc;
                    997:        struct harmony_dma *d, **dd;
                    998:
                    999:        for (dd = &sc->sc_dmas; (d = *dd) != NULL; dd = &(*dd)->d_next) {
                   1000:                if (d->d_kva != ptr)
                   1001:                        continue;
                   1002:                bus_dmamap_unload(sc->sc_dmat, d->d_map);
                   1003:                bus_dmamem_unmap(sc->sc_dmat, d->d_kva, d->d_size);
                   1004:                bus_dmamem_free(sc->sc_dmat, &d->d_seg, 1);
                   1005:                bus_dmamap_destroy(sc->sc_dmat, d->d_map);
                   1006:                free(d, pool);
                   1007:                return;
                   1008:        }
                   1009:        printf("%s: free rogue pointer\n", sc->sc_dv.dv_xname);
                   1010: }
                   1011:
                   1012: size_t
                   1013: harmony_round_buffersize(void *vsc, int direction, size_t size)
                   1014: {
                   1015:        return ((size + HARMONY_BUFSIZE - 1) & (size_t)(-HARMONY_BUFSIZE));
                   1016: }
                   1017:
                   1018: int
                   1019: harmony_get_props(void *vsc)
                   1020: {
                   1021:        return (AUDIO_PROP_FULLDUPLEX);
                   1022: }
                   1023:
                   1024: int
                   1025: harmony_trigger_output(void *vsc, void *start, void *end, int blksize,
                   1026:     void (*intr)(void *), void *intrarg, struct audio_params *param)
                   1027: {
                   1028:        struct harmony_softc *sc = vsc;
                   1029:        struct harmony_channel *c = &sc->sc_playback;
                   1030:        struct harmony_dma *d;
                   1031:        bus_addr_t nextaddr;
                   1032:        bus_size_t togo;
                   1033:
                   1034:        for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
                   1035:                /*EMPTY*/;
                   1036:        if (d == NULL) {
                   1037:                printf("%s: trigger_output: bad addr: %p\n",
                   1038:                    sc->sc_dv.dv_xname, start);
                   1039:                return (EINVAL);
                   1040:        }
                   1041:
                   1042:        c->c_intr = intr;
                   1043:        c->c_intrarg = intrarg;
                   1044:        c->c_blksz = blksize;
                   1045:        c->c_current = d;
                   1046:        c->c_segsz = (caddr_t)end - (caddr_t)start;
                   1047:        c->c_cnt = 0;
                   1048:        c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
                   1049:
                   1050:        sc->sc_playing = 1;
                   1051:
                   1052:        togo = c->c_segsz - c->c_cnt;
                   1053:        if (togo == 0) {
                   1054:                nextaddr = d->d_map->dm_segs[0].ds_addr;
                   1055:                c->c_cnt = togo = c->c_blksz;
                   1056:        } else {
                   1057:                nextaddr = c->c_lastaddr;
                   1058:                if (togo > c->c_blksz)
                   1059:                        togo = c->c_blksz;
                   1060:                c->c_cnt += togo;
                   1061:        }
                   1062:
                   1063:        bus_dmamap_sync(sc->sc_dmat, d->d_map,
                   1064:            nextaddr - d->d_map->dm_segs[0].ds_addr,
                   1065:            c->c_blksz, BUS_DMASYNC_PREWRITE);
                   1066:
                   1067:        WRITE_REG(sc, HARMONY_PNXTADD, nextaddr);
                   1068:        c->c_theaddr = nextaddr;
                   1069:        SYNC_REG(sc, HARMONY_PNXTADD, BUS_SPACE_BARRIER_WRITE);
                   1070:        c->c_lastaddr = nextaddr + togo;
                   1071:
                   1072:        harmony_start_cp(sc);
                   1073:        harmony_intr_enable(sc);
                   1074:
                   1075:        return (0);
                   1076: }
                   1077:
                   1078: void
                   1079: harmony_start_cp(struct harmony_softc *sc)
                   1080: {
                   1081:        struct harmony_channel *c = &sc->sc_capture;
                   1082:        struct harmony_dma *d;
                   1083:        bus_addr_t nextaddr;
                   1084:        bus_size_t togo;
                   1085:
                   1086:        if (sc->sc_capturing == 0) {
                   1087:                WRITE_REG(sc, HARMONY_RNXTADD,
                   1088:                    sc->sc_capture_paddrs[sc->sc_capture_empty]);
                   1089:                if (++sc->sc_capture_empty == CAPTURE_EMPTYS)
                   1090:                        sc->sc_capture_empty = 0;
                   1091:        } else {
                   1092:                d = c->c_current;
                   1093:                togo = c->c_segsz - c->c_cnt;
                   1094:                if (togo == 0) {
                   1095:                        nextaddr = d->d_map->dm_segs[0].ds_addr;
                   1096:                        c->c_cnt = togo = c->c_blksz;
                   1097:                } else {
                   1098:                        nextaddr = c->c_lastaddr;
                   1099:                        if (togo > c->c_blksz)
                   1100:                                togo = c->c_blksz;
                   1101:                        c->c_cnt += togo;
                   1102:                }
                   1103:
                   1104:                bus_dmamap_sync(sc->sc_dmat, d->d_map,
                   1105:                    nextaddr - d->d_map->dm_segs[0].ds_addr,
                   1106:                    c->c_blksz, BUS_DMASYNC_PREWRITE);
                   1107:
                   1108:                WRITE_REG(sc, HARMONY_RNXTADD, nextaddr);
                   1109:                SYNC_REG(sc, HARMONY_RNXTADD, BUS_SPACE_BARRIER_WRITE);
                   1110:                c->c_lastaddr = nextaddr + togo;
                   1111:        }
                   1112:
                   1113:        timeout_add(&sc->sc_acc_tmo, 1);
                   1114: }
                   1115:
                   1116: int
                   1117: harmony_trigger_input(void *vsc, void *start, void *end, int blksize,
                   1118:     void (*intr)(void *), void *intrarg, struct audio_params *param)
                   1119: {
                   1120:        struct harmony_softc *sc = vsc;
                   1121:        struct harmony_channel *c = &sc->sc_capture;
                   1122:        struct harmony_dma *d;
                   1123:
                   1124:        for (d = sc->sc_dmas; d->d_kva != start; d = d->d_next)
                   1125:                /*EMPTY*/;
                   1126:        if (d == NULL) {
                   1127:                printf("%s: trigger_input: bad addr: %p\n",
                   1128:                    sc->sc_dv.dv_xname, start);
                   1129:                return (EINVAL);
                   1130:        }
                   1131:
                   1132:        c->c_intr = intr;
                   1133:        c->c_intrarg = intrarg;
                   1134:        c->c_blksz = blksize;
                   1135:        c->c_current = d;
                   1136:        c->c_segsz = (caddr_t)end - (caddr_t)start;
                   1137:        c->c_cnt = 0;
                   1138:        c->c_lastaddr = d->d_map->dm_segs[0].ds_addr;
                   1139:
                   1140:        sc->sc_capturing = 1;
                   1141:        harmony_start_cp(sc);
                   1142:        harmony_intr_enable(sc);
                   1143:        return (0);
                   1144: }
                   1145:
                   1146: static const struct speed_struct {
                   1147:        u_int32_t speed;
                   1148:        u_int32_t bits;
                   1149: } harmony_speeds[] = {
                   1150:        { 5125, CNTL_RATE_5125 },
                   1151:        { 6615, CNTL_RATE_6615 },
                   1152:        { 8000, CNTL_RATE_8000 },
                   1153:        { 9600, CNTL_RATE_9600 },
                   1154:        { 11025, CNTL_RATE_11025 },
                   1155:        { 16000, CNTL_RATE_16000 },
                   1156:        { 18900, CNTL_RATE_18900 },
                   1157:        { 22050, CNTL_RATE_22050 },
                   1158:        { 27428, CNTL_RATE_27428 },
                   1159:        { 32000, CNTL_RATE_32000 },
                   1160:        { 33075, CNTL_RATE_33075 },
                   1161:        { 37800, CNTL_RATE_37800 },
                   1162:        { 44100, CNTL_RATE_44100 },
                   1163:        { 48000, CNTL_RATE_48000 },
                   1164: };
                   1165:
                   1166: u_int32_t
                   1167: harmony_speed_bits(struct harmony_softc *sc, u_long *speedp)
                   1168: {
                   1169:        int i, n, selected = -1;
                   1170:
                   1171:        n = sizeof(harmony_speeds) / sizeof(harmony_speeds[0]);
                   1172:
                   1173:        if ((*speedp) <= harmony_speeds[0].speed)
                   1174:                selected = 0;
                   1175:        else if ((*speedp) >= harmony_speeds[n - 1].speed)
                   1176:                selected = n - 1;
                   1177:        else {
                   1178:                for (i = 1; selected == -1 && i < n; i++) {
                   1179:                        if ((*speedp) == harmony_speeds[i].speed)
                   1180:                                selected = i;
                   1181:                        else if ((*speedp) < harmony_speeds[i].speed) {
                   1182:                                int diff1, diff2;
                   1183:
                   1184:                                diff1 = (*speedp) - harmony_speeds[i - 1].speed;
                   1185:                                diff2 = harmony_speeds[i].speed - (*speedp);
                   1186:                                if (diff1 < diff2)
                   1187:                                        selected = i - 1;
                   1188:                                else
                   1189:                                        selected = i;
                   1190:                        }
                   1191:                }
                   1192:        }
                   1193:
                   1194:        if (selected == -1)
                   1195:                selected = 2;
                   1196:
                   1197:        *speedp = harmony_speeds[selected].speed;
                   1198:        return (harmony_speeds[selected].bits);
                   1199: }
                   1200:
                   1201: int
                   1202: harmony_set_gainctl(struct harmony_softc *sc)
                   1203: {
                   1204:        u_int32_t bits, mask, val, old;
                   1205:
                   1206:        /* XXX leave these bits alone or the chip will not come out of CNTL */
                   1207:        bits = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
                   1208:
                   1209:        /* input level */
                   1210:        bits |= ((sc->sc_input_lvl.left >> (8 - GAINCTL_INPUT_BITS)) <<
                   1211:            GAINCTL_INPUT_LEFT_S) & GAINCTL_INPUT_LEFT_M;
                   1212:        bits |= ((sc->sc_input_lvl.right >> (8 - GAINCTL_INPUT_BITS)) <<
                   1213:            GAINCTL_INPUT_RIGHT_S) & GAINCTL_INPUT_RIGHT_M;
                   1214:
                   1215:        /* output level (inverted) */
                   1216:        mask = (1 << GAINCTL_OUTPUT_BITS) - 1;
                   1217:        val = mask - (sc->sc_output_lvl.left >> (8 - GAINCTL_OUTPUT_BITS));
                   1218:        bits |= (val << GAINCTL_OUTPUT_LEFT_S) & GAINCTL_OUTPUT_LEFT_M;
                   1219:        val = mask - (sc->sc_output_lvl.right >> (8 - GAINCTL_OUTPUT_BITS));
                   1220:        bits |= (val << GAINCTL_OUTPUT_RIGHT_S) & GAINCTL_OUTPUT_RIGHT_M;
                   1221:
                   1222:        /* monitor level (inverted) */
                   1223:        mask = (1 << GAINCTL_MONITOR_BITS) - 1;
                   1224:        val = mask - (sc->sc_monitor_lvl.left >> (8 - GAINCTL_MONITOR_BITS));
                   1225:        bits |= (val << GAINCTL_MONITOR_S) & GAINCTL_MONITOR_M;
                   1226:
                   1227:        /* XXX messing with these causes CNTL_C to get stuck... grr. */
                   1228:        bits &= ~GAINCTL_IS_MASK;
                   1229:        if (sc->sc_in_port == HARMONY_IN_MIC)
                   1230:                bits |= GAINCTL_IS_LINE;
                   1231:        else
                   1232:                bits |= GAINCTL_IS_MICROPHONE;
                   1233:
                   1234:        /* XXX messing with these causes CNTL_C to get stuck... grr. */
                   1235:        bits &= ~(GAINCTL_LE | GAINCTL_HE | GAINCTL_SE);
                   1236:        if (sc->sc_out_port == HARMONY_OUT_LINE)
                   1237:                bits |= GAINCTL_LE;
                   1238:        else if (sc->sc_out_port == HARMONY_OUT_SPEAKER)
                   1239:                bits |= GAINCTL_SE;
                   1240:        else
                   1241:                bits |= GAINCTL_HE;
                   1242:
                   1243:        mask = GAINCTL_LE | GAINCTL_HE | GAINCTL_SE | GAINCTL_IS_MASK;
                   1244:        old = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL);
                   1245:        bus_space_write_4(sc->sc_bt, sc->sc_bh, HARMONY_GAINCTL, bits);
                   1246:        if ((old & mask) != (bits & mask))
                   1247:                return (1);
                   1248:        return (0);
                   1249: }
                   1250:
                   1251: void
                   1252: harmony_try_more(struct harmony_softc *sc)
                   1253: {
                   1254:        struct harmony_channel *c = &sc->sc_playback;
                   1255:        struct harmony_dma *d = c->c_current;
                   1256:        u_int32_t cur;
                   1257:        int i, nsegs;
                   1258:
                   1259:        cur = bus_space_read_4(sc->sc_bt, sc->sc_bh, HARMONY_PCURADD);
                   1260:        cur &= PCURADD_BUFMASK;
                   1261:        nsegs = 0;
                   1262:
                   1263: #ifdef DIAGNOSTIC
                   1264:        if (cur < d->d_map->dm_segs[0].ds_addr ||
                   1265:            cur >= (d->d_map->dm_segs[0].ds_addr + c->c_segsz))
                   1266:                panic("%s: bad current %x < %lx || %x > %lx",
                   1267:                    sc->sc_dv.dv_xname, cur, d->d_map->dm_segs[0].ds_addr, cur,
                   1268:                    d->d_map->dm_segs[0].ds_addr + c->c_segsz);
                   1269: #endif /* DIAGNOSTIC */
                   1270:
                   1271:        if (cur > c->c_theaddr) {
                   1272:                nsegs = (cur - c->c_theaddr) / HARMONY_BUFSIZE;
                   1273:        } else if (cur < c->c_theaddr) {
                   1274:                nsegs = (d->d_map->dm_segs[0].ds_addr + c->c_segsz -
                   1275:                    c->c_theaddr) / HARMONY_BUFSIZE;
                   1276:                nsegs += (cur - d->d_map->dm_segs[0].ds_addr) /
                   1277:                    HARMONY_BUFSIZE;
                   1278:        }
                   1279:
                   1280:        if (nsegs != 0 && c->c_intr != NULL) {
                   1281:                for (i = 0; i < nsegs; i++)
                   1282:                        (*c->c_intr)(c->c_intrarg);
                   1283:                c->c_theaddr = cur;
                   1284:        }
                   1285: }
                   1286:
                   1287: struct cfdriver harmony_cd = {
                   1288:        NULL, "harmony", DV_DULL
                   1289: };
                   1290:
                   1291: struct cfattach harmony_ca = {
                   1292:        sizeof(struct harmony_softc), harmony_match, harmony_attach
                   1293: };

CVSweb