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

Annotation of sys/dev/pci/auvia.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: auvia.c,v 1.33 2005/05/06 01:45:22 miod Exp $ */
                      2: /*     $NetBSD: auvia.c,v 1.7 2000/11/15 21:06:33 jdolecek Exp $       */
                      3:
                      4: /*-
                      5:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Tyler C. Sarna
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the NetBSD
                     22:  *     Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * VIA Technologies VT82C686A Southbridge Audio Driver
                     42:  *
                     43:  * Documentation links:
                     44:  *
                     45:  * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf
                     46:  */
                     47:
                     48: #include <sys/param.h>
                     49: #include <sys/systm.h>
                     50: #include <sys/malloc.h>
                     51: #include <sys/device.h>
                     52: #include <sys/audioio.h>
                     53:
                     54: #include <dev/pci/pcidevs.h>
                     55: #include <dev/pci/pcivar.h>
                     56:
                     57: #include <dev/audio_if.h>
                     58: #include <dev/mulaw.h>
                     59: #include <dev/auconv.h>
                     60:
                     61: #include <dev/ic/ac97.h>
                     62:
                     63: #include <dev/pci/auviavar.h>
                     64:
                     65: struct auvia_dma {
                     66:        struct auvia_dma *next;
                     67:        caddr_t addr;
                     68:        size_t size;
                     69:        bus_dmamap_t map;
                     70:        bus_dma_segment_t seg;
                     71: };
                     72:
                     73: struct auvia_dma_op {
                     74:        u_int32_t ptr;
                     75:        u_int32_t flags;
                     76: #define AUVIA_DMAOP_EOL                0x80000000
                     77: #define AUVIA_DMAOP_FLAG       0x40000000
                     78: #define AUVIA_DMAOP_STOP       0x20000000
                     79: #define AUVIA_DMAOP_COUNT(x)   ((x)&0x00FFFFFF)
                     80: };
                     81:
                     82: /* rev. H and later seem to support only fixed rate 44.1 kHz */
                     83: #define        AUVIA_FIXED_RATE        44100
                     84:
                     85: int    auvia_match(struct device *, void *, void *);
                     86: void   auvia_attach(struct device *, struct device *, void *);
                     87: int    auvia_open(void *, int);
                     88: void   auvia_close(void *);
                     89: int    auvia_query_encoding(void *addr, struct audio_encoding *fp);
                     90: int    auvia_set_params(void *, int, int, struct audio_params *,
                     91:        struct audio_params *);
                     92: int    auvia_round_blocksize(void *, int);
                     93: int    auvia_halt_output(void *);
                     94: int    auvia_halt_input(void *);
                     95: int    auvia_getdev(void *, struct audio_device *);
                     96: int    auvia_set_port(void *, mixer_ctrl_t *);
                     97: int    auvia_get_port(void *, mixer_ctrl_t *);
                     98: int    auvia_query_devinfo(void *, mixer_devinfo_t *);
                     99: void * auvia_malloc(void *, int, size_t, int, int);
                    100: void   auvia_free(void *, void *, int);
                    101: paddr_t        auvia_mappage(void *, void *, off_t, int);
                    102: int    auvia_get_props(void *);
                    103: int    auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *,
                    104:        struct auvia_dma *, void *, void *, int);
                    105: int    auvia_trigger_output(void *, void *, void *, int, void (*)(void *),
                    106:        void *, struct audio_params *);
                    107: int    auvia_trigger_input(void *, void *, void *, int, void (*)(void *),
                    108:        void *, struct audio_params *);
                    109:
                    110: int    auvia_intr(void *);
                    111:
                    112: struct  cfdriver auvia_cd = {
                    113:        NULL, "auvia", DV_DULL
                    114: };
                    115:
                    116: struct cfattach auvia_ca = {
                    117:        sizeof (struct auvia_softc), auvia_match, auvia_attach
                    118: };
                    119:
                    120: #define AUVIA_PCICONF_JUNK     0x40
                    121: #define                AUVIA_PCICONF_ENABLES    0x00FF0000     /* reg 42 mask */
                    122: #define                AUVIA_PCICONF_ACLINKENAB 0x00008000     /* ac link enab */
                    123: #define                AUVIA_PCICONF_ACNOTRST   0x00004000     /* ~(ac reset) */
                    124: #define                AUVIA_PCICONF_ACSYNC     0x00002000     /* ac sync */
                    125: #define                AUVIA_PCICONF_ACVSR      0x00000800     /* var. samp. rate */
                    126: #define                AUVIA_PCICONF_ACSGD      0x00000400     /* SGD enab */
                    127: #define                AUVIA_PCICONF_ACFM       0x00000200     /* FM enab */
                    128: #define                AUVIA_PCICONF_ACSB       0x00000100     /* SB enab */
                    129: #define                AUVIA_PCICONF_PRIVALID   0x00000001     /* primary codec rdy */
                    130:
                    131: #define AUVIA_PLAY_BASE                        0x00
                    132: #define AUVIA_RECORD_BASE              0x10
                    133:
                    134: #define        AUVIA_RP_STAT                   0x00
                    135: #define                AUVIA_RPSTAT_INTR               0x03
                    136: #define AUVIA_RP_CONTROL               0x01
                    137: #define                AUVIA_RPCTRL_START              0x80
                    138: #define                AUVIA_RPCTRL_TERMINATE          0x40
                    139: #define                AUVIA_RPCTRL_AUTOSTART          0x20
                    140: /* The following are 8233 specific */
                    141: #define                AUVIA_RPCTRL_STOP               0x04
                    142: #define                AUVIA_RPCTRL_EOL                0x02
                    143: #define                AUVIA_RPCTRL_FLAG               0x01
                    144: #define AUVIA_RP_MODE                  0x02
                    145: #define                AUVIA_RPMODE_INTR_FLAG          0x01
                    146: #define                AUVIA_RPMODE_INTR_EOL           0x02
                    147: #define                AUVIA_RPMODE_STEREO             0x10
                    148: #define                AUVIA_RPMODE_16BIT              0x20
                    149: #define                AUVIA_RPMODE_AUTOSTART          0x80
                    150: #define        AUVIA_RP_DMAOPS_BASE            0x04
                    151:
                    152: #define        VIA8233_RP_DXS_LVOL             0x02
                    153: #define        VIA8233_RP_DXS_RVOL             0x03
                    154: #define        VIA8233_RP_RATEFMT              0x08
                    155: #define                VIA8233_RATEFMT_48K     0xfffff
                    156: #define                VIA8233_RATEFMT_STEREO  0x00100000
                    157: #define                VIA8233_RATEFMT_16BIT   0x00200000
                    158:
                    159: #define VIA_RP_DMAOPS_COUNT            0x0C
                    160:
                    161: #define        AUVIA_CODEC_CTL                 0x80
                    162: #define                AUVIA_CODEC_READ                0x00800000
                    163: #define                AUVIA_CODEC_BUSY                0x01000000
                    164: #define                AUVIA_CODEC_PRIVALID            0x02000000
                    165: #define                AUVIA_CODEC_INDEX(x)            ((x)<<16)
                    166:
                    167: #define TIMEOUT        50
                    168:
                    169: struct audio_hw_if auvia_hw_if = {
                    170:        auvia_open,
                    171:        auvia_close,
                    172:        NULL, /* drain */
                    173:        auvia_query_encoding,
                    174:        auvia_set_params,
                    175:        auvia_round_blocksize,
                    176:        NULL, /* commit_settings */
                    177:        NULL, /* init_output */
                    178:        NULL, /* init_input */
                    179:        NULL, /* start_output */
                    180:        NULL, /* start_input */
                    181:        auvia_halt_output,
                    182:        auvia_halt_input,
                    183:        NULL, /* speaker_ctl */
                    184:        auvia_getdev,
                    185:        NULL, /* setfd */
                    186:        auvia_set_port,
                    187:        auvia_get_port,
                    188:        auvia_query_devinfo,
                    189:        auvia_malloc,
                    190:        auvia_free,
                    191:        NULL, /* auvia_round_buffersize */
                    192:        auvia_mappage,
                    193:        auvia_get_props,
                    194:        auvia_trigger_output,
                    195:        auvia_trigger_input
                    196: };
                    197:
                    198: int    auvia_attach_codec(void *, struct ac97_codec_if *);
                    199: int    auvia_write_codec(void *, u_int8_t, u_int16_t);
                    200: int    auvia_read_codec(void *, u_int8_t, u_int16_t *);
                    201: void   auvia_reset_codec(void *);
                    202: int    auvia_waitready_codec(struct auvia_softc *sc);
                    203: int    auvia_waitvalid_codec(struct auvia_softc *sc);
                    204:
                    205: const struct pci_matchid auvia_devices[] = {
                    206:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT82C686A_AC97 },
                    207:        { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_AC97 },
                    208: };
                    209:
                    210: int
                    211: auvia_match(struct device *parent, void *match, void *aux)
                    212: {
                    213:        return (pci_matchbyid((struct pci_attach_args *)aux, auvia_devices,
                    214:            sizeof(auvia_devices)/sizeof(auvia_devices[0])));
                    215: }
                    216:
                    217:
                    218: void
                    219: auvia_attach(struct device *parent, struct device *self, void *aux)
                    220: {
                    221:        struct pci_attach_args *pa = aux;
                    222:        struct auvia_softc *sc = (struct auvia_softc *) self;
                    223:        const char *intrstr = NULL;
                    224:        struct mixer_ctrl ctl;
                    225:        pci_chipset_tag_t pc = pa->pa_pc;
                    226:        pcitag_t pt = pa->pa_tag;
                    227:        pci_intr_handle_t ih;
                    228:        bus_size_t iosize;
                    229:        pcireg_t pr;
                    230:        int r, i;
                    231:
                    232:        if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97)
                    233:                sc->sc_flags |= AUVIA_FLAGS_VT8233;
                    234:
                    235:        if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
                    236:            &sc->sc_ioh, NULL, &iosize, 0)) {
                    237:                printf(": can't map i/o space\n");
                    238:                return;
                    239:        }
                    240:
                    241:        sc->sc_dmat = pa->pa_dmat;
                    242:        sc->sc_pc = pc;
                    243:        sc->sc_pt = pt;
                    244:
                    245:        if (pci_intr_map(pa, &ih)) {
                    246:                printf(": couldn't map interrupt\n");
                    247:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    248:                return;
                    249:        }
                    250:        intrstr = pci_intr_string(pc, ih);
                    251:
                    252:        sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc,
                    253:            sc->sc_dev.dv_xname);
                    254:        if (sc->sc_ih == NULL) {
                    255:                printf(": couldn't establish interrupt");
                    256:                if (intrstr != NULL)
                    257:                        printf(" at %s", intrstr);
                    258:                printf("\n");
                    259:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    260:                return;
                    261:        }
                    262:
                    263:        printf(": %s\n", intrstr);
                    264:
                    265:        /* disable SBPro compat & others */
                    266:        pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
                    267:
                    268:        pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
                    269:        /* XXX what to do about MIDI, FM, joystick? */
                    270:
                    271:        pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST |
                    272:            AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
                    273:
                    274:        pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
                    275:
                    276:        pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
                    277:
                    278:        sc->host_if.arg = sc;
                    279:        sc->host_if.attach = auvia_attach_codec;
                    280:        sc->host_if.read = auvia_read_codec;
                    281:        sc->host_if.write = auvia_write_codec;
                    282:        sc->host_if.reset = auvia_reset_codec;
                    283:
                    284:        if ((r = ac97_attach(&sc->host_if)) != 0) {
                    285:                printf("%s: can't attach codec (error 0x%X)\n",
                    286:                    sc->sc_dev.dv_xname, r);
                    287:                pci_intr_disestablish(pc, sc->sc_ih);
                    288:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    289:                return;
                    290:        }
                    291:
                    292:        /* disable mutes */
                    293:        for (i = 0; i < 4; i++) {
                    294:                static struct {
                    295:                        char *class, *device;
                    296:                } d[] = {
                    297:                        { AudioCoutputs, AudioNmaster},
                    298:                        { AudioCinputs, AudioNdac},
                    299:                        { AudioCinputs, AudioNcd},
                    300:                        { AudioCrecord, AudioNvolume},
                    301:                };
                    302:
                    303:                ctl.type = AUDIO_MIXER_ENUM;
                    304:                ctl.un.ord = 0;
                    305:
                    306:                ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
                    307:                    d[i].class, d[i].device, AudioNmute);
                    308:                auvia_set_port(sc, &ctl);
                    309:        }
                    310:
                    311:        /* set a reasonable default volume */
                    312:
                    313:        ctl.type = AUDIO_MIXER_VALUE;
                    314:        ctl.un.value.num_channels = 2;
                    315:        ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = \
                    316:        ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 199;
                    317:
                    318:        ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
                    319:            AudioCoutputs, AudioNmaster, NULL);
                    320:        auvia_set_port(sc, &ctl);
                    321:
                    322:        audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
                    323: }
                    324:
                    325:
                    326: int
                    327: auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
                    328: {
                    329:        struct auvia_softc *sc = addr;
                    330:
                    331:        sc->codec_if = cif;
                    332:
                    333:        return 0;
                    334: }
                    335:
                    336:
                    337: void
                    338: auvia_reset_codec(void *addr)
                    339: {
                    340:        int i;
                    341:        struct auvia_softc *sc = addr;
                    342:        pcireg_t r;
                    343:
                    344:        /* perform a codec cold reset */
                    345:
                    346:        r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
                    347:
                    348:        r &= ~AUVIA_PCICONF_ACNOTRST;   /* enable RESET (active low) */
                    349:        pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
                    350:        delay(2);
                    351:
                    352:        r |= AUVIA_PCICONF_ACNOTRST;    /* disable RESET (inactive high) */
                    353:        pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
                    354:        delay(200);
                    355:
                    356:        for (i = 500000; i != 0 && !(pci_conf_read(sc->sc_pc, sc->sc_pt,
                    357:                AUVIA_PCICONF_JUNK) & AUVIA_PCICONF_PRIVALID); i--)
                    358:                DELAY(1);
                    359:        if (i == 0)
                    360:                printf("%s: codec reset timed out\n", sc->sc_dev.dv_xname);
                    361: }
                    362:
                    363:
                    364: int
                    365: auvia_waitready_codec(struct auvia_softc *sc)
                    366: {
                    367:        int i;
                    368:
                    369:        /* poll until codec not busy */
                    370:        for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
                    371:             AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
                    372:                delay(1);
                    373:
                    374:        if (i >= TIMEOUT) {
                    375:                printf("%s: codec busy\n", sc->sc_dev.dv_xname);
                    376:                return 1;
                    377:        }
                    378:
                    379:        return 0;
                    380: }
                    381:
                    382:
                    383: int
                    384: auvia_waitvalid_codec(struct auvia_softc *sc)
                    385: {
                    386:        int i;
                    387:
                    388:        /* poll until codec valid */
                    389:        for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
                    390:             AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
                    391:                delay(1);
                    392:
                    393:        if (i >= TIMEOUT) {
                    394:                printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
                    395:                return 1;
                    396:        }
                    397:
                    398:        return 0;
                    399: }
                    400:
                    401:
                    402: int
                    403: auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
                    404: {
                    405:        struct auvia_softc *sc = addr;
                    406:
                    407:        if (auvia_waitready_codec(sc))
                    408:                return 1;
                    409:
                    410:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
                    411:            AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
                    412:
                    413:        return 0;
                    414: }
                    415:
                    416:
                    417: int
                    418: auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
                    419: {
                    420:        struct auvia_softc *sc = addr;
                    421:
                    422:        if (auvia_waitready_codec(sc))
                    423:                return 1;
                    424:
                    425:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
                    426:            AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
                    427:
                    428:        if (auvia_waitready_codec(sc))
                    429:                return 1;
                    430:
                    431:        if (auvia_waitvalid_codec(sc))
                    432:                return 1;
                    433:
                    434:        *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
                    435:
                    436:        return 0;
                    437: }
                    438:
                    439:
                    440: int
                    441: auvia_open(void *addr, int flags)
                    442: {
                    443:        return 0;
                    444: }
                    445:
                    446:
                    447: void
                    448: auvia_close(void *addr)
                    449: {
                    450:        struct auvia_softc *sc = addr;
                    451:
                    452:        auvia_halt_output(sc);
                    453:        auvia_halt_input(sc);
                    454:
                    455:        sc->sc_play.sc_intr = NULL;
                    456:        sc->sc_record.sc_intr = NULL;
                    457: }
                    458:
                    459:
                    460: int
                    461: auvia_query_encoding(void *addr, struct audio_encoding *fp)
                    462: {
                    463:        switch (fp->index) {
                    464:        case 0:
                    465:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
                    466:                fp->encoding = AUDIO_ENCODING_ULINEAR;
                    467:                fp->precision = 8;
                    468:                fp->flags = 0;
                    469:                return (0);
                    470:        case 1:
                    471:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
                    472:                fp->encoding = AUDIO_ENCODING_ULAW;
                    473:                fp->precision = 8;
                    474:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    475:                return (0);
                    476:        case 2:
                    477:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
                    478:                fp->encoding = AUDIO_ENCODING_ALAW;
                    479:                fp->precision = 8;
                    480:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    481:                return (0);
                    482:        case 3:
                    483:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
                    484:                fp->encoding = AUDIO_ENCODING_SLINEAR;
                    485:                fp->precision = 8;
                    486:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    487:                return (0);
                    488:        case 4:
                    489:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
                    490:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    491:                fp->precision = 16;
                    492:                fp->flags = 0;
                    493:                return (0);
                    494:        case 5:
                    495:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
                    496:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    497:                fp->precision = 16;
                    498:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    499:                return (0);
                    500:        case 6:
                    501:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
                    502:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    503:                fp->precision = 16;
                    504:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    505:                return (0);
                    506:        case 7:
                    507:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
                    508:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    509:                fp->precision = 16;
                    510:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    511:                return (0);
                    512:        default:
                    513:                return (EINVAL);
                    514:        }
                    515: }
                    516:
                    517:
                    518: int
                    519: auvia_set_params(void *addr, int setmode, int usemode,
                    520:     struct audio_params *play, struct audio_params *rec)
                    521: {
                    522:        struct auvia_softc *sc = addr;
                    523:        struct audio_params *p;
                    524:        u_int16_t regval;
                    525:        int mode, base;
                    526:
                    527:        /* for mode in (RECORD, PLAY) */
                    528:        for (mode = AUMODE_RECORD; mode != -1;
                    529:             mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
                    530:                if ((setmode & mode) == 0)
                    531:                        continue;
                    532:
                    533:                if (mode == AUMODE_PLAY) {
                    534:                        p = play;
                    535:                        base = AUVIA_PLAY_BASE;
                    536:                } else {
                    537:                        p = rec;
                    538:                        base = AUVIA_RECORD_BASE;
                    539:                }
                    540:
                    541:                if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
                    542:                        u_int32_t v = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
                    543:                            base + VIA8233_RP_RATEFMT) & ~(VIA8233_RATEFMT_48K
                    544:                            | VIA8233_RATEFMT_STEREO | VIA8233_RATEFMT_16BIT);
                    545:
                    546:                        v |= VIA8233_RATEFMT_48K *
                    547:                            (p->sample_rate / 20) / (48000 / 20);
                    548:
                    549:                        if (p->channels == 2)
                    550:                                v |= VIA8233_RATEFMT_STEREO;
                    551:                        if (p->precision == 16)
                    552:                                v |= VIA8233_RATEFMT_16BIT;
                    553:
                    554:                        bus_space_write_4(sc->sc_iot, sc->sc_ioh,
                    555:                            base + VIA8233_RP_RATEFMT, v);
                    556:                }
                    557:
                    558:                if (ac97_set_rate(sc->codec_if, p, mode))
                    559:                        return (EINVAL);
                    560:
                    561:                if ((p->precision != 8 && p->precision != 16) ||
                    562:                    (p->channels != 1 && p->channels != 2))
                    563:                        return (EINVAL);
                    564:
                    565:                p->factor = 1;
                    566:                p->sw_code = 0;
                    567:                switch (p->encoding) {
                    568:                case AUDIO_ENCODING_SLINEAR_BE:
                    569:                        if (p->precision == 16)
                    570:                                p->sw_code = swap_bytes;
                    571:                        else
                    572:                                p->sw_code = change_sign8;
                    573:                        break;
                    574:                case AUDIO_ENCODING_SLINEAR_LE:
                    575:                        if (p->precision != 16)
                    576:                                p->sw_code = change_sign8;
                    577:                        break;
                    578:                case AUDIO_ENCODING_ULINEAR_BE:
                    579:                        if (p->precision == 16)
                    580:                                p->sw_code = mode == AUMODE_PLAY?
                    581:                                    swap_bytes_change_sign16_le :
                    582:                                    change_sign16_swap_bytes_le;
                    583:                        break;
                    584:                case AUDIO_ENCODING_ULINEAR_LE:
                    585:                        if (p->precision == 16)
                    586:                                p->sw_code = change_sign16_le;
                    587:                        break;
                    588:                case AUDIO_ENCODING_ULAW:
                    589:                        if (mode == AUMODE_PLAY) {
                    590:                                p->factor = 2;
                    591:                                p->sw_code = mulaw_to_slinear16_le;
                    592:                        } else
                    593:                                p->sw_code = ulinear8_to_mulaw;
                    594:                        break;
                    595:                case AUDIO_ENCODING_ALAW:
                    596:                        if (mode == AUMODE_PLAY) {
                    597:                                p->factor = 2;
                    598:                                p->sw_code = alaw_to_slinear16_le;
                    599:                        } else
                    600:                                p->sw_code = ulinear8_to_alaw;
                    601:                        break;
                    602:                case AUDIO_ENCODING_SLINEAR:
                    603:                case AUDIO_ENCODING_ULINEAR:
                    604:                        break;
                    605:                default:
                    606:                        return (EINVAL);
                    607:                }
                    608:
                    609:                regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
                    610:                        | (p->precision * p->factor == 16 ?
                    611:                                AUVIA_RPMODE_16BIT : 0)
                    612:                        | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
                    613:                        | AUVIA_RPMODE_AUTOSTART;
                    614:
                    615:                if (mode == AUMODE_PLAY)
                    616:                        sc->sc_play.sc_reg = regval;
                    617:                else
                    618:                        sc->sc_record.sc_reg = regval;
                    619:        }
                    620:
                    621:        return 0;
                    622: }
                    623:
                    624:
                    625: int
                    626: auvia_round_blocksize(void *addr, int blk)
                    627: {
                    628:        return ((blk + 31) & -32);
                    629: }
                    630:
                    631:
                    632: int
                    633: auvia_halt_output(void *addr)
                    634: {
                    635:        struct auvia_softc *sc = addr;
                    636:
                    637:        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    638:            AUVIA_PLAY_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
                    639:
                    640:        return 0;
                    641: }
                    642:
                    643:
                    644: int
                    645: auvia_halt_input(void *addr)
                    646: {
                    647:        struct auvia_softc *sc = addr;
                    648:
                    649:        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    650:            AUVIA_RECORD_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
                    651:
                    652:        return 0;
                    653: }
                    654:
                    655:
                    656: int
                    657: auvia_getdev(void *addr, struct audio_device *retp)
                    658: {
                    659:        struct auvia_softc *sc = addr;
                    660:
                    661:        if (retp) {
                    662:                strncpy(retp->name,
                    663:                    sc->sc_flags & AUVIA_FLAGS_VT8233? "VIA VT8233" :
                    664:                    "VIA VT82C686A", sizeof(retp->name));
                    665:                strncpy(retp->version, sc->sc_revision, sizeof(retp->version));
                    666:                strncpy(retp->config, "auvia", sizeof(retp->config));
                    667:        }
                    668:
                    669:        return 0;
                    670: }
                    671:
                    672:
                    673: int
                    674: auvia_set_port(void *addr, mixer_ctrl_t *cp)
                    675: {
                    676:        struct auvia_softc *sc = addr;
                    677:
                    678:        return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
                    679: }
                    680:
                    681:
                    682: int
                    683: auvia_get_port(void *addr, mixer_ctrl_t *cp)
                    684: {
                    685:        struct auvia_softc *sc = addr;
                    686:
                    687:        return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
                    688: }
                    689:
                    690:
                    691: int
                    692: auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
                    693: {
                    694:        struct auvia_softc *sc = addr;
                    695:
                    696:        return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
                    697: }
                    698:
                    699:
                    700: void *
                    701: auvia_malloc(void *addr, int direction, size_t size, int pool, int flags)
                    702: {
                    703:        struct auvia_softc *sc = addr;
                    704:        struct auvia_dma *p;
                    705:        int error;
                    706:        int rseg;
                    707:
                    708:        p = malloc(sizeof(*p), pool, flags);
                    709:        if (!p)
                    710:                return 0;
                    711:
                    712:        p->size = size;
                    713:        if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
                    714:            1, &rseg, BUS_DMA_NOWAIT)) != 0) {
                    715:                printf("%s: unable to allocate dma, error = %d\n",
                    716:                    sc->sc_dev.dv_xname, error);
                    717:                goto fail_alloc;
                    718:        }
                    719:
                    720:        if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
                    721:            BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
                    722:                printf("%s: unable to map dma, error = %d\n",
                    723:                    sc->sc_dev.dv_xname, error);
                    724:                goto fail_map;
                    725:        }
                    726:
                    727:        if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
                    728:            BUS_DMA_NOWAIT, &p->map)) != 0) {
                    729:                printf("%s: unable to create dma map, error = %d\n",
                    730:                    sc->sc_dev.dv_xname, error);
                    731:                goto fail_create;
                    732:        }
                    733:
                    734:        if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
                    735:            BUS_DMA_NOWAIT)) != 0) {
                    736:                printf("%s: unable to load dma map, error = %d\n",
                    737:                    sc->sc_dev.dv_xname, error);
                    738:                goto fail_load;
                    739:        }
                    740:
                    741:        p->next = sc->sc_dmas;
                    742:        sc->sc_dmas = p;
                    743:
                    744:        return p->addr;
                    745:
                    746:
                    747: fail_load:
                    748:        bus_dmamap_destroy(sc->sc_dmat, p->map);
                    749: fail_create:
                    750:        bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
                    751: fail_map:
                    752:        bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
                    753: fail_alloc:
                    754:        free(p, pool);
                    755:        return 0;
                    756: }
                    757:
                    758:
                    759: void
                    760: auvia_free(void *addr, void *ptr, int pool)
                    761: {
                    762:        struct auvia_softc *sc = addr;
                    763:        struct auvia_dma **pp, *p;
                    764:
                    765:        for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
                    766:                if (p->addr == ptr) {
                    767:                        bus_dmamap_unload(sc->sc_dmat, p->map);
                    768:                        bus_dmamap_destroy(sc->sc_dmat, p->map);
                    769:                        bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
                    770:                        bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
                    771:
                    772:                        *pp = p->next;
                    773:                        free(p, pool);
                    774:                        return;
                    775:                }
                    776:
                    777:        panic("auvia_free: trying to free unallocated memory");
                    778: }
                    779:
                    780: paddr_t
                    781: auvia_mappage(void *addr, void *mem, off_t off, int prot)
                    782: {
                    783:        struct auvia_softc *sc = addr;
                    784:        struct auvia_dma *p;
                    785:
                    786:        if (off < 0)
                    787:                return -1;
                    788:
                    789:        for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
                    790:                ;
                    791:
                    792:        if (!p)
                    793:                return -1;
                    794:
                    795:        return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
                    796:            BUS_DMA_WAITOK);
                    797: }
                    798:
                    799:
                    800: int
                    801: auvia_get_props(void *addr)
                    802: {
                    803:        return (AUDIO_PROP_MMAP |  AUDIO_PROP_INDEPENDENT |
                    804:            AUDIO_PROP_FULLDUPLEX);
                    805: }
                    806:
                    807:
                    808: int
                    809: auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
                    810:     struct auvia_dma *p, void *start, void *end, int blksize)
                    811: {
                    812:        struct auvia_dma_op *op;
                    813:        struct auvia_dma *dp;
                    814:        bus_addr_t s;
                    815:        size_t l;
                    816:        int segs;
                    817:
                    818:        s = p->map->dm_segs[0].ds_addr;
                    819:        l = (vaddr_t)end - (vaddr_t)start;
                    820:        segs = howmany(l, blksize);
                    821:
                    822:        if (segs > ch->sc_dma_op_count) {
                    823:                /* if old list was too small, free it */
                    824:                if (ch->sc_dma_ops)
                    825:                        auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
                    826:
                    827:                ch->sc_dma_ops = auvia_malloc(sc, 0,
                    828:                    sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
                    829:
                    830:                for (dp = sc->sc_dmas; dp &&
                    831:                     dp->addr != (void *)(ch->sc_dma_ops); dp = dp->next)
                    832:                        ;
                    833:
                    834:                if (!dp)
                    835:                        panic("%s: build_dma_ops: where'd my memory go??? "
                    836:                            "address (%p)", sc->sc_dev.dv_xname,
                    837:                            ch->sc_dma_ops);
                    838:
                    839:                ch->sc_dma_op_count = segs;
                    840:                ch->sc_dma_ops_dma = dp;
                    841:        }
                    842:
                    843:        dp = ch->sc_dma_ops_dma;
                    844:        op = ch->sc_dma_ops;
                    845:
                    846:        while (l) {
                    847:                op->ptr = htole32(s);
                    848:                l = l - min(l, blksize);
                    849:                /* if last block */
                    850:                op->flags = htole32((l? AUVIA_DMAOP_FLAG : AUVIA_DMAOP_EOL) | blksize);
                    851:                s += blksize;
                    852:                op++;
                    853:        }
                    854:
                    855:        return 0;
                    856: }
                    857:
                    858:
                    859: int
                    860: auvia_trigger_output(void *addr, void *start, void *end, int blksize,
                    861:     void (*intr)(void *), void *arg, struct audio_params *param)
                    862: {
                    863:        struct auvia_softc *sc = addr;
                    864:        struct auvia_softc_chan *ch = &(sc->sc_play);
                    865:        struct auvia_dma *p;
                    866:
                    867:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
                    868:                ;
                    869:
                    870:        if (!p)
                    871:                panic("auvia_trigger_output: request with bad start "
                    872:                    "address (%p)", start);
                    873:
                    874:        if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
                    875:                return 1;
                    876:        }
                    877:
                    878:        ch->sc_intr = intr;
                    879:        ch->sc_arg = arg;
                    880:
                    881:        bus_space_write_4(sc->sc_iot, sc->sc_ioh,
                    882:            AUVIA_PLAY_BASE + AUVIA_RP_DMAOPS_BASE,
                    883:            ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
                    884:
                    885:        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    886:            AUVIA_PLAY_BASE + AUVIA_RP_MODE, ch->sc_reg);
                    887:
                    888:        if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
                    889:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    890:                    AUVIA_PLAY_BASE + VIA8233_RP_DXS_LVOL, 0);
                    891:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    892:                    AUVIA_PLAY_BASE + VIA8233_RP_DXS_RVOL, 0);
                    893:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    894:                    AUVIA_PLAY_BASE + AUVIA_RP_CONTROL,
                    895:                    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
                    896:                    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
                    897:        } else
                    898:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    899:                    AUVIA_PLAY_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
                    900:
                    901:        return 0;
                    902: }
                    903:
                    904:
                    905: int
                    906: auvia_trigger_input(void *addr, void *start, void *end, int blksize,
                    907:     void (*intr)(void *), void *arg, struct audio_params *param)
                    908: {
                    909:        struct auvia_softc *sc = addr;
                    910:        struct auvia_softc_chan *ch = &(sc->sc_record);
                    911:        struct auvia_dma *p;
                    912:
                    913:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
                    914:                ;
                    915:
                    916:        if (!p)
                    917:                panic("auvia_trigger_input: request with bad start "
                    918:                    "address (%p)", start);
                    919:
                    920:        if (auvia_build_dma_ops(sc, ch, p, start, end, blksize))
                    921:                return 1;
                    922:
                    923:        ch->sc_intr = intr;
                    924:        ch->sc_arg = arg;
                    925:
                    926:        bus_space_write_4(sc->sc_iot, sc->sc_ioh,
                    927:            AUVIA_RECORD_BASE + AUVIA_RP_DMAOPS_BASE,
                    928:            ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
                    929:        bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    930:            AUVIA_RECORD_BASE + AUVIA_RP_MODE, ch->sc_reg);
                    931:
                    932:        if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
                    933:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    934:                    AUVIA_RECORD_BASE + VIA8233_RP_DXS_LVOL, 0);
                    935:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    936:                    AUVIA_RECORD_BASE + VIA8233_RP_DXS_RVOL, 0);
                    937:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    938:                    AUVIA_RECORD_BASE + AUVIA_RP_CONTROL,
                    939:                    AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
                    940:                    AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
                    941:        } else
                    942:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    943:                    AUVIA_RECORD_BASE + AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
                    944:
                    945:        return 0;
                    946: }
                    947:
                    948:
                    949: int
                    950: auvia_intr(void *arg)
                    951: {
                    952:        struct auvia_softc *sc = arg;
                    953:        u_int8_t r;
                    954:        int i = 0;
                    955:
                    956:        r = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
                    957:            AUVIA_RECORD_BASE + AUVIA_RP_STAT);
                    958:        if (r & AUVIA_RPSTAT_INTR) {
                    959:                if (sc->sc_record.sc_intr)
                    960:                        sc->sc_record.sc_intr(sc->sc_record.sc_arg);
                    961:
                    962:                /* clear interrupts */
                    963:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    964:                    AUVIA_RECORD_BASE + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
                    965:
                    966:                i++;
                    967:        }
                    968:        r = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
                    969:            AUVIA_PLAY_BASE + AUVIA_RP_STAT);
                    970:        if (r & AUVIA_RPSTAT_INTR) {
                    971:                if (sc->sc_play.sc_intr)
                    972:                        sc->sc_play.sc_intr(sc->sc_play.sc_arg);
                    973:
                    974:                /* clear interrupts */
                    975:                bus_space_write_1(sc->sc_iot, sc->sc_ioh,
                    976:                    AUVIA_PLAY_BASE + AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
                    977:
                    978:                i++;
                    979:        }
                    980:
                    981:        return (i? 1 : 0);
                    982: }

CVSweb