[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     ! 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