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

Annotation of sys/dev/pci/sv.c, Revision 1.1

1.1     ! nbrk        1: /*      $OpenBSD: sv.c,v 1.21 2005/09/11 18:17:08 mickey Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1998 Constantine Paul Sapuntzakis
        !             5:  * All rights reserved
        !             6:  *
        !             7:  * Author: Constantine Paul Sapuntzakis (csapuntz@cvs.openbsd.org)
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. The author's name or those of the contributors may be used to
        !            18:  *    endorse or promote products derived from this software without
        !            19:  *    specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS
        !            22:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            23:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            24:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            25:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            26:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            27:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            28:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            31:  * POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: /*
        !            35:  * S3 SonicVibes driver
        !            36:  *   Heavily based on the eap driver by Lennart Augustsson
        !            37:  */
        !            38:
        !            39: #include <sys/param.h>
        !            40: #include <sys/systm.h>
        !            41: #include <sys/kernel.h>
        !            42: #include <sys/malloc.h>
        !            43: #include <sys/device.h>
        !            44:
        !            45: #include <dev/pci/pcireg.h>
        !            46: #include <dev/pci/pcivar.h>
        !            47: #include <dev/pci/pcidevs.h>
        !            48:
        !            49: #include <sys/audioio.h>
        !            50: #include <dev/audio_if.h>
        !            51: #include <dev/mulaw.h>
        !            52: #include <dev/auconv.h>
        !            53:
        !            54: #include <dev/ic/i8237reg.h>
        !            55: #include <dev/ic/s3_617.h>
        !            56:
        !            57:
        !            58: #include <machine/bus.h>
        !            59:
        !            60: #ifdef __OpenBSD__
        !            61: struct        cfdriver sv_cd = {
        !            62:       NULL, "sv", DV_DULL
        !            63: };
        !            64: #endif
        !            65:
        !            66: #ifdef AUDIO_DEBUG
        !            67: #define DPRINTF(x)     if (svdebug) printf x
        !            68: #define DPRINTFN(n,x)  if (svdebug>(n)) printf x
        !            69: static int     svdebug = 100;
        !            70: #else
        !            71: #define DPRINTF(x)
        !            72: #define DPRINTFN(n,x)
        !            73: #endif
        !            74:
        !            75: int    sv_match(struct device *, void *, void *);
        !            76: static void    sv_attach(struct device *, struct device *, void *);
        !            77: int    sv_intr(void *);
        !            78:
        !            79: struct sv_dma {
        !            80:        bus_dmamap_t map;
        !            81:         caddr_t addr;
        !            82:         bus_dma_segment_t segs[1];
        !            83:         int nsegs;
        !            84:         size_t size;
        !            85:         struct sv_dma *next;
        !            86: };
        !            87: #define DMAADDR(map) ((map)->segs[0].ds_addr)
        !            88: #define KERNADDR(map) ((void *)((map)->addr))
        !            89:
        !            90: enum {
        !            91:   SV_DMAA_CONFIGURED = 1,
        !            92:   SV_DMAC_CONFIGURED = 2,
        !            93:   SV_DMAA_TRIED_CONFIGURE = 4,
        !            94:   SV_DMAC_TRIED_CONFIGURE = 8
        !            95: };
        !            96:
        !            97: struct sv_softc {
        !            98:        struct device sc_dev;           /* base device */
        !            99:        void *sc_ih;                    /* interrupt vectoring */
        !           100:
        !           101:         pci_chipset_tag_t sc_pci_chipset_tag;
        !           102:         pcitag_t  sc_pci_tag;
        !           103:
        !           104:        bus_space_tag_t sc_iot;
        !           105:        bus_space_handle_t sc_ioh;
        !           106:        bus_space_handle_t sc_dmaa_ioh;
        !           107:        bus_space_handle_t sc_dmac_ioh;
        !           108:        bus_dma_tag_t sc_dmatag;        /* DMA tag */
        !           109:
        !           110:         struct sv_dma *sc_dmas;
        !           111:
        !           112:        void    (*sc_pintr)(void *);    /* dma completion intr handler */
        !           113:        void    *sc_parg;               /* arg for sc_intr() */
        !           114:
        !           115:        void    (*sc_rintr)(void *);    /* dma completion intr handler */
        !           116:        void    *sc_rarg;               /* arg for sc_intr() */
        !           117:        char    sc_enable;
        !           118:         char    sc_trd;
        !           119:
        !           120:         char    sc_dma_configured;
        !           121:         u_int  sc_record_source;       /* recording source mask */
        !           122: };
        !           123:
        !           124:
        !           125: struct cfattach sv_ca = {
        !           126:        sizeof(struct sv_softc), sv_match, sv_attach
        !           127: };
        !           128:
        !           129: struct audio_device sv_device = {
        !           130:        "S3 SonicVibes",
        !           131:        "",
        !           132:        "sv"
        !           133: };
        !           134:
        !           135: #define ARRAY_SIZE(foo)  ((sizeof(foo)) / sizeof(foo[0]))
        !           136:
        !           137: int    sv_allocmem(struct sv_softc *, size_t, size_t, struct sv_dma *);
        !           138: int    sv_freemem(struct sv_softc *, struct sv_dma *);
        !           139:
        !           140: int    sv_open(void *, int);
        !           141: void   sv_close(void *);
        !           142: int    sv_query_encoding(void *, struct audio_encoding *);
        !           143: int    sv_set_params(void *, int, int, struct audio_params *, struct audio_params *);
        !           144: int    sv_round_blocksize(void *, int);
        !           145: int    sv_dma_init_output(void *, void *, int);
        !           146: int    sv_dma_init_input(void *, void *, int);
        !           147: int    sv_dma_output(void *, void *, int, void (*)(void *), void *);
        !           148: int    sv_dma_input(void *, void *, int, void (*)(void *), void *);
        !           149: int    sv_halt_in_dma(void *);
        !           150: int    sv_halt_out_dma(void *);
        !           151: int    sv_getdev(void *, struct audio_device *);
        !           152: int    sv_mixer_set_port(void *, mixer_ctrl_t *);
        !           153: int    sv_mixer_get_port(void *, mixer_ctrl_t *);
        !           154: int    sv_query_devinfo(void *, mixer_devinfo_t *);
        !           155: void   *sv_malloc(void *, int, size_t, int, int);
        !           156: void   sv_free(void *, void *, int);
        !           157: paddr_t        sv_mappage(void *, void *, off_t, int);
        !           158: int    sv_get_props(void *);
        !           159:
        !           160: void    sv_dumpregs(struct sv_softc *sc);
        !           161:
        !           162: struct audio_hw_if sv_hw_if = {
        !           163:        sv_open,
        !           164:        sv_close,
        !           165:        NULL,
        !           166:        sv_query_encoding,
        !           167:        sv_set_params,
        !           168:        sv_round_blocksize,
        !           169:        NULL,
        !           170:        sv_dma_init_output,
        !           171:        sv_dma_init_input,
        !           172:        sv_dma_output,
        !           173:        sv_dma_input,
        !           174:        sv_halt_out_dma,
        !           175:        sv_halt_in_dma,
        !           176:        NULL,
        !           177:        sv_getdev,
        !           178:        NULL,
        !           179:        sv_mixer_set_port,
        !           180:        sv_mixer_get_port,
        !           181:        sv_query_devinfo,
        !           182:        sv_malloc,
        !           183:        sv_free,
        !           184:        NULL,
        !           185:        sv_mappage,
        !           186:        sv_get_props,
        !           187:        NULL,
        !           188:        NULL
        !           189: };
        !           190:
        !           191:
        !           192: static __inline__ u_int8_t sv_read(struct sv_softc *, u_int8_t);
        !           193: static __inline__ u_int8_t sv_read_indirect(struct sv_softc *, u_int8_t);
        !           194: static __inline__ void sv_write(struct sv_softc *, u_int8_t, u_int8_t );
        !           195: static __inline__ void sv_write_indirect(struct sv_softc *, u_int8_t, u_int8_t );
        !           196: static void sv_init_mixer(struct sv_softc *);
        !           197:
        !           198: static __inline__ void
        !           199: sv_write (sc, reg, val)
        !           200:      struct sv_softc *sc;
        !           201:      u_int8_t reg, val;
        !           202:
        !           203: {
        !           204:   bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
        !           205: }
        !           206:
        !           207: static __inline__ u_int8_t
        !           208: sv_read (sc, reg)
        !           209:      struct sv_softc *sc;
        !           210:      u_int8_t reg;
        !           211:
        !           212: {
        !           213:   return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg));
        !           214: }
        !           215:
        !           216: static __inline__ u_int8_t
        !           217: sv_read_indirect (sc, reg)
        !           218:      struct sv_softc *sc;
        !           219:      u_int8_t reg;
        !           220: {
        !           221:     u_int8_t iaddr = 0;
        !           222:
        !           223:     if (sc->sc_trd > 0)
        !           224:       iaddr |= SV_IADDR_TRD;
        !           225:
        !           226:     iaddr |= (reg & SV_IADDR_MASK);
        !           227:     sv_write (sc, SV_CODEC_IADDR, iaddr);
        !           228:
        !           229:     return (sv_read(sc, SV_CODEC_IDATA));
        !           230: }
        !           231:
        !           232: static __inline__ void
        !           233: sv_write_indirect (sc, reg, val)
        !           234:      struct sv_softc *sc;
        !           235:      u_int8_t reg, val;
        !           236: {
        !           237:     u_int8_t iaddr = 0;
        !           238: #ifdef DIAGNOSTIC
        !           239:     if (reg > 0x3f) {
        !           240:       printf ("Invalid register\n");
        !           241:       return;
        !           242:     }
        !           243: #endif
        !           244:
        !           245:     if (reg == SV_DMA_DATA_FORMAT)
        !           246:       iaddr |= SV_IADDR_MCE;
        !           247:
        !           248:     if (sc->sc_trd > 0)
        !           249:       iaddr |= SV_IADDR_TRD;
        !           250:
        !           251:     iaddr |= (reg & SV_IADDR_MASK);
        !           252:     sv_write (sc, SV_CODEC_IADDR, iaddr);
        !           253:     sv_write (sc, SV_CODEC_IDATA, val);
        !           254: }
        !           255:
        !           256: int
        !           257: sv_match(parent, match, aux)
        !           258:      struct device *parent;
        !           259:      void *match, *aux;
        !           260: {
        !           261:        struct pci_attach_args *pa = aux;
        !           262:
        !           263:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_S3 &&
        !           264:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_S3_SONICVIBES)
        !           265:          return (1);
        !           266:
        !           267:        return (0);
        !           268: }
        !           269:
        !           270: static void
        !           271: sv_attach(parent, self, aux)
        !           272:      struct device *parent, *self;
        !           273:      void *aux;
        !           274:
        !           275: {
        !           276:   struct sv_softc *sc = (struct sv_softc *)self;
        !           277:   struct pci_attach_args *pa = aux;
        !           278:   pci_chipset_tag_t pc = pa->pa_pc;
        !           279:   pci_intr_handle_t ih;
        !           280:   bus_size_t iosize;
        !           281:   char const *intrstr;
        !           282:   u_int32_t  dmareg, dmaio;
        !           283:   u_int8_t   reg;
        !           284:
        !           285:   sc->sc_pci_chipset_tag = pc;
        !           286:   sc->sc_pci_tag = pa->pa_tag;
        !           287:
        !           288:   /* Map the enhanced port only */
        !           289:   if (pci_mapreg_map(pa, SV_ENHANCED_PORTBASE_SLOT, PCI_MAPREG_TYPE_IO, 0,
        !           290:       &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
        !           291:     printf (": Couldn't map enhanced synth I/O range\n");
        !           292:     return;
        !           293:   }
        !           294:
        !           295:   sc->sc_dmatag = pa->pa_dmat;
        !           296:
        !           297:   dmareg = pci_conf_read(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF);
        !           298:   iosize = 0x10;
        !           299:   dmaio =  dmareg & ~(iosize - 1);
        !           300:
        !           301:   if (dmaio) {
        !           302:     dmareg &= 0xF;
        !           303:
        !           304:     if (bus_space_map(sc->sc_iot, dmaio, iosize, 0, &sc->sc_dmaa_ioh)) {
        !           305:       /* The BIOS assigned us some bad I/O address! Make sure to clear
        !           306:          and disable this DMA before we enable the device */
        !           307:       pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF, 0);
        !           308:
        !           309:       printf (": can't map DMA i/o space\n");
        !           310:       goto enable;
        !           311:     }
        !           312:
        !           313:     pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF,
        !           314:                   dmaio | dmareg |
        !           315:                   SV_DMA_CHANNEL_ENABLE | SV_DMAA_EXTENDED_ADDR);
        !           316:     sc->sc_dma_configured |= SV_DMAA_CONFIGURED;
        !           317:   }
        !           318:
        !           319:   dmareg = pci_conf_read(pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF);
        !           320:   dmaio = dmareg & ~(iosize - 1);
        !           321:   if (dmaio) {
        !           322:     dmareg &= 0xF;
        !           323:
        !           324:     if (bus_space_map(sc->sc_iot, dmaio, iosize, 0, &sc->sc_dmac_ioh)) {
        !           325:       /* The BIOS assigned us some bad I/O address! Make sure to clear
        !           326:          and disable this DMA before we enable the device */
        !           327:       pci_conf_write (pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF,
        !           328:                      dmareg & ~SV_DMA_CHANNEL_ENABLE);
        !           329:       printf (": can't map DMA i/o space\n");
        !           330:       goto enable;
        !           331:     }
        !           332:
        !           333:     pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF,
        !           334:                   dmaio | dmareg | SV_DMA_CHANNEL_ENABLE);
        !           335:     sc->sc_dma_configured |= SV_DMAC_CONFIGURED;
        !           336:   }
        !           337:
        !           338:   /* Enable the device. */
        !           339:  enable:
        !           340:   sv_write_indirect(sc, SV_ANALOG_POWER_DOWN_CONTROL, 0);
        !           341:   sv_write_indirect(sc, SV_DIGITAL_POWER_DOWN_CONTROL, 0);
        !           342:
        !           343:   /* initialize codec registers */
        !           344:   reg = sv_read(sc, SV_CODEC_CONTROL);
        !           345:   reg |= SV_CTL_RESET;
        !           346:   sv_write(sc, SV_CODEC_CONTROL, reg);
        !           347:   delay(50);
        !           348:
        !           349:   reg = sv_read(sc, SV_CODEC_CONTROL);
        !           350:   reg &= ~SV_CTL_RESET;
        !           351:   reg |= SV_CTL_INTA | SV_CTL_ENHANCED;
        !           352:
        !           353:   /* This write clears the reset */
        !           354:   sv_write(sc, SV_CODEC_CONTROL, reg);
        !           355:   delay(50);
        !           356:
        !           357:   /* This write actually shoves the new values in */
        !           358:   sv_write(sc, SV_CODEC_CONTROL, reg);
        !           359:
        !           360:   DPRINTF (("reg: %x\n", sv_read(sc, SV_CODEC_CONTROL)));
        !           361:
        !           362:   /* Enable DMA interrupts */
        !           363:   reg = sv_read(sc, SV_CODEC_INTMASK);
        !           364:   reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
        !           365:   reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
        !           366:   sv_write(sc, SV_CODEC_INTMASK, reg);
        !           367:
        !           368:   sv_read(sc, SV_CODEC_STATUS);
        !           369:
        !           370:   sc->sc_trd = 0;
        !           371:   sc->sc_enable = 0;
        !           372:
        !           373:   /* Map and establish the interrupt. */
        !           374:   if (pci_intr_map(pa, &ih)) {
        !           375:     printf(": couldn't map interrupt\n");
        !           376:     return;
        !           377:   }
        !           378:   intrstr = pci_intr_string(pc, ih);
        !           379:   sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, sv_intr, sc,
        !           380:                                 sc->sc_dev.dv_xname);
        !           381:   if (sc->sc_ih == NULL) {
        !           382:     printf(": couldn't establish interrupt");
        !           383:     if (intrstr != NULL)
        !           384:       printf(" at %s", intrstr);
        !           385:     printf("\n");
        !           386:     return;
        !           387:   }
        !           388:   printf(": %s\n", intrstr);
        !           389:
        !           390:   sv_init_mixer(sc);
        !           391:
        !           392:   audio_attach_mi(&sv_hw_if, sc, &sc->sc_dev);
        !           393: }
        !           394:
        !           395: #ifdef AUDIO_DEBUG
        !           396: void
        !           397: sv_dumpregs(sc)
        !           398:      struct sv_softc *sc;
        !           399: {
        !           400:   int idx;
        !           401:
        !           402:   { int idx;
        !           403:   for (idx = 0; idx < 0x50; idx += 4) {
        !           404:     printf ("%02x = %x\n", idx, pci_conf_read(sc->sc_pci_chipset_tag,
        !           405:             sc->sc_pci_tag, idx));
        !           406:   }
        !           407:   }
        !           408:
        !           409:   for (idx = 0; idx < 6; idx++) {
        !           410:     printf ("REG %02x = %02x\n", idx, sv_read(sc, idx));
        !           411:   }
        !           412:
        !           413:   for (idx = 0; idx < 0x32; idx++) {
        !           414:     printf ("IREG %02x = %02x\n", idx, sv_read_indirect(sc, idx));
        !           415:   }
        !           416:
        !           417:   for (idx = 0; idx < 0x10; idx++) {
        !           418:     printf ("DMA %02x = %02x\n", idx,
        !           419:            bus_space_read_1(sc->sc_iot, sc->sc_dmaa_ioh, idx));
        !           420:   }
        !           421:
        !           422:   return;
        !           423: }
        !           424: #endif
        !           425:
        !           426: int
        !           427: sv_intr(p)
        !           428:        void *p;
        !           429: {
        !           430:   struct sv_softc *sc = p;
        !           431:   u_int8_t intr;
        !           432:
        !           433:   intr = sv_read(sc, SV_CODEC_STATUS);
        !           434:
        !           435:   if (!(intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC)))
        !           436:     return (0);
        !           437:
        !           438:   if (intr & SV_INTSTATUS_DMAA) {
        !           439:     if (sc->sc_pintr)
        !           440:       sc->sc_pintr(sc->sc_parg);
        !           441:   }
        !           442:
        !           443:   if (intr & SV_INTSTATUS_DMAC) {
        !           444:     if (sc->sc_rintr)
        !           445:       sc->sc_rintr(sc->sc_rarg);
        !           446:   }
        !           447:
        !           448:   return (1);
        !           449: }
        !           450:
        !           451: int
        !           452: sv_allocmem(sc, size, align, p)
        !           453:        struct sv_softc *sc;
        !           454:        size_t size;
        !           455:        size_t align;
        !           456:         struct sv_dma *p;
        !           457: {
        !           458:        int error;
        !           459:
        !           460:        p->size = size;
        !           461:        error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
        !           462:                                 p->segs, ARRAY_SIZE(p->segs),
        !           463:                                 &p->nsegs, BUS_DMA_NOWAIT);
        !           464:        if (error)
        !           465:                return (error);
        !           466:
        !           467:        error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
        !           468:                               &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
        !           469:        if (error)
        !           470:                goto free;
        !           471:
        !           472:        error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
        !           473:                                  0, BUS_DMA_NOWAIT, &p->map);
        !           474:        if (error)
        !           475:                goto unmap;
        !           476:
        !           477:        error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
        !           478:                                BUS_DMA_NOWAIT);
        !           479:        if (error)
        !           480:                goto destroy;
        !           481:        return (0);
        !           482:
        !           483: destroy:
        !           484:        bus_dmamap_destroy(sc->sc_dmatag, p->map);
        !           485: unmap:
        !           486:        bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
        !           487: free:
        !           488:        bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
        !           489:        return (error);
        !           490: }
        !           491:
        !           492: int
        !           493: sv_freemem(sc, p)
        !           494:        struct sv_softc *sc;
        !           495:         struct sv_dma *p;
        !           496: {
        !           497:        bus_dmamap_unload(sc->sc_dmatag, p->map);
        !           498:        bus_dmamap_destroy(sc->sc_dmatag, p->map);
        !           499:        bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
        !           500:        bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
        !           501:        return (0);
        !           502: }
        !           503:
        !           504: int
        !           505: sv_open(addr, flags)
        !           506:        void *addr;
        !           507:        int flags;
        !           508: {
        !           509:
        !           510:     struct sv_softc *sc = addr;
        !           511:     int  intr_mask = 0;
        !           512:     u_int8_t reg;
        !           513:
        !           514:     /* Map the DMA channels, if necessary */
        !           515:     if (!(sc->sc_dma_configured & SV_DMAA_CONFIGURED)) {
        !           516:        /* XXX - there seems to be no general way to find an
        !           517:           I/O range */
        !           518:        int dmaio;
        !           519:        int iosize = 0x10;
        !           520:
        !           521:        if (sc->sc_dma_configured & SV_DMAA_TRIED_CONFIGURE)
        !           522:            return (ENXIO);
        !           523:
        !           524:        for (dmaio = 0xa000; dmaio < 0xb000; dmaio += iosize) {
        !           525:            if (!bus_space_map(sc->sc_iot, dmaio, iosize, 0,
        !           526:                              &sc->sc_dmaa_ioh)) {
        !           527:                goto found_dmaa;
        !           528:            }
        !           529:        }
        !           530:
        !           531:        sc->sc_dma_configured |= SV_DMAA_TRIED_CONFIGURE;
        !           532:        return (ENXIO);
        !           533:     found_dmaa:
        !           534:
        !           535:        pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
        !           536:                       SV_DMAA_CONFIG_OFF,
        !           537:                       dmaio | SV_DMA_CHANNEL_ENABLE
        !           538:                       | SV_DMAA_EXTENDED_ADDR);
        !           539:
        !           540:        sc->sc_dma_configured |= SV_DMAA_CONFIGURED;
        !           541:        intr_mask = 1;
        !           542:     }
        !           543:
        !           544:     if (!(sc->sc_dma_configured & SV_DMAC_CONFIGURED)) {
        !           545:        /* XXX - there seems to be no general way to find an
        !           546:           I/O range */
        !           547:        int dmaio;
        !           548:        int iosize = 0x10;
        !           549:
        !           550:        if (sc->sc_dma_configured & SV_DMAC_TRIED_CONFIGURE)
        !           551:            return (ENXIO);
        !           552:
        !           553:        for (dmaio = 0xa000; dmaio < 0xb000; dmaio += iosize) {
        !           554:            if (!bus_space_map(sc->sc_iot, dmaio, iosize, 0,
        !           555:                              &sc->sc_dmac_ioh)) {
        !           556:                goto found_dmac;
        !           557:            }
        !           558:        }
        !           559:
        !           560:        sc->sc_dma_configured |= SV_DMAC_TRIED_CONFIGURE;
        !           561:        return (ENXIO);
        !           562:     found_dmac:
        !           563:
        !           564:        pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
        !           565:                       SV_DMAC_CONFIG_OFF,
        !           566:                       dmaio | SV_DMA_CHANNEL_ENABLE);
        !           567:
        !           568:        sc->sc_dma_configured |= SV_DMAC_CONFIGURED;
        !           569:        intr_mask = 1;
        !           570:     }
        !           571:
        !           572:     /* Make sure DMA interrupts are enabled */
        !           573:     if (intr_mask) {
        !           574:        reg = sv_read(sc, SV_CODEC_INTMASK);
        !           575:        reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
        !           576:        reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
        !           577:        sv_write(sc, SV_CODEC_INTMASK, reg);
        !           578:     }
        !           579:
        !           580:     sc->sc_pintr = 0;
        !           581:     sc->sc_rintr = 0;
        !           582:
        !           583:     return (0);
        !           584: }
        !           585:
        !           586: /*
        !           587:  * Close function is called at splaudio().
        !           588:  */
        !           589: void
        !           590: sv_close(addr)
        !           591:        void *addr;
        !           592: {
        !           593:        struct sv_softc *sc = addr;
        !           594:
        !           595:         sv_halt_in_dma(sc);
        !           596:         sv_halt_out_dma(sc);
        !           597:
        !           598:         sc->sc_pintr = 0;
        !           599:         sc->sc_rintr = 0;
        !           600: }
        !           601:
        !           602: int
        !           603: sv_query_encoding(addr, fp)
        !           604:        void *addr;
        !           605:        struct audio_encoding *fp;
        !           606: {
        !           607:        switch (fp->index) {
        !           608:        case 0:
        !           609:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
        !           610:                fp->encoding = AUDIO_ENCODING_ULINEAR;
        !           611:                fp->precision = 8;
        !           612:                fp->flags = 0;
        !           613:                return (0);
        !           614:        case 1:
        !           615:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
        !           616:                fp->encoding = AUDIO_ENCODING_ULAW;
        !           617:                fp->precision = 8;
        !           618:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           619:                return (0);
        !           620:        case 2:
        !           621:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
        !           622:                fp->encoding = AUDIO_ENCODING_ALAW;
        !           623:                fp->precision = 8;
        !           624:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           625:                return (0);
        !           626:        case 3:
        !           627:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
        !           628:                fp->encoding = AUDIO_ENCODING_SLINEAR;
        !           629:                fp->precision = 8;
        !           630:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           631:                return (0);
        !           632:         case 4:
        !           633:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
        !           634:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !           635:                fp->precision = 16;
        !           636:                fp->flags = 0;
        !           637:                return (0);
        !           638:        case 5:
        !           639:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
        !           640:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !           641:                fp->precision = 16;
        !           642:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           643:                return (0);
        !           644:        case 6:
        !           645:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
        !           646:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !           647:                fp->precision = 16;
        !           648:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           649:                return (0);
        !           650:        case 7:
        !           651:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
        !           652:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !           653:                fp->precision = 16;
        !           654:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           655:                return (0);
        !           656:        default:
        !           657:                return (EINVAL);
        !           658:        }
        !           659: }
        !           660:
        !           661: int
        !           662: sv_set_params(addr, setmode, usemode, p, r)
        !           663:        void *addr;
        !           664:        int setmode, usemode;
        !           665:        struct audio_params *p, *r;
        !           666: {
        !           667:        struct sv_softc *sc = addr;
        !           668:        void (*pswcode)(void *, u_char *buf, int cnt);
        !           669:        void (*rswcode)(void *, u_char *buf, int cnt);
        !           670:         u_int32_t mode, val;
        !           671:         u_int8_t reg;
        !           672:
        !           673:         pswcode = rswcode = 0;
        !           674:         switch (p->encoding) {
        !           675:         case AUDIO_ENCODING_SLINEAR_BE:
        !           676:                if (p->precision == 16)
        !           677:                        rswcode = pswcode = swap_bytes;
        !           678:                else
        !           679:                        pswcode = rswcode = change_sign8;
        !           680:                break;
        !           681:         case AUDIO_ENCODING_SLINEAR_LE:
        !           682:                if (p->precision != 16)
        !           683:                        pswcode = rswcode = change_sign8;
        !           684:                break;
        !           685:         case AUDIO_ENCODING_ULINEAR_BE:
        !           686:                if (p->precision == 16) {
        !           687:                        pswcode = swap_bytes_change_sign16;
        !           688:                        rswcode = change_sign16_swap_bytes;
        !           689:                }
        !           690:                break;
        !           691:         case AUDIO_ENCODING_ULINEAR_LE:
        !           692:                if (p->precision == 16)
        !           693:                        pswcode = rswcode = change_sign16;
        !           694:                break;
        !           695:         case AUDIO_ENCODING_ULAW:
        !           696:                pswcode = mulaw_to_ulinear8;
        !           697:                 rswcode = ulinear8_to_mulaw;
        !           698:                 break;
        !           699:         case AUDIO_ENCODING_ALAW:
        !           700:                 pswcode = alaw_to_ulinear8;
        !           701:                 rswcode = ulinear8_to_alaw;
        !           702:                 break;
        !           703:         default:
        !           704:                return (EINVAL);
        !           705:         }
        !           706:
        !           707:        if (p->precision == 16)
        !           708:                mode = SV_DMAA_FORMAT16 | SV_DMAC_FORMAT16;
        !           709:        else
        !           710:                mode = 0;
        !           711:         if (p->channels == 2)
        !           712:                mode |= SV_DMAA_STEREO | SV_DMAC_STEREO;
        !           713:        else if (p->channels != 1)
        !           714:                return (EINVAL);
        !           715:         if (p->sample_rate < 2000 || p->sample_rate > 48000)
        !           716:                return (EINVAL);
        !           717:
        !           718:         p->sw_code = pswcode;
        !           719:         r->sw_code = rswcode;
        !           720:
        !           721:         /* Set the encoding */
        !           722:        reg = sv_read_indirect(sc, SV_DMA_DATA_FORMAT);
        !           723:        reg &= ~(SV_DMAA_FORMAT16 | SV_DMAC_FORMAT16 | SV_DMAA_STEREO |
        !           724:                 SV_DMAC_STEREO);
        !           725:        reg |= (mode);
        !           726:        sv_write_indirect(sc, SV_DMA_DATA_FORMAT, reg);
        !           727:
        !           728:        val = p->sample_rate * 65536 / 48000;
        !           729:
        !           730:        sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_0, (val & 0xff));
        !           731:        sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_1, (val >> 8));
        !           732:
        !           733: #define F_REF 24576000
        !           734:
        !           735:        if (setmode & AUMODE_RECORD)
        !           736:        {
        !           737:          /* The ADC reference frequency (f_out) is 512 * the sample rate */
        !           738:
        !           739:          /* f_out is dervied from the 24.576MHZ crystal by three values:
        !           740:             M & N & R. The equation is as follows:
        !           741:
        !           742:             f_out = (m + 2) * f_ref / ((n + 2) * (2 ^ a))
        !           743:
        !           744:             with the constraint that:
        !           745:
        !           746:             80 MhZ < (m + 2) / (n + 2) * f_ref <= 150MHz
        !           747:             and n, m >= 1
        !           748:          */
        !           749:
        !           750:          int  goal_f_out = 512 * r->sample_rate;
        !           751:          int  a, n, m, best_n, best_m, best_error = 10000000;
        !           752:          int  pll_sample;
        !           753:
        !           754:          for (a = 0; a < 8; a++) {
        !           755:            if ((goal_f_out * (1 << a)) >= 80000000)
        !           756:              break;
        !           757:          }
        !           758:
        !           759:          /* a != 8 because sample_rate >= 2000 */
        !           760:
        !           761:          for (n = 33; n > 2; n--) {
        !           762:            int error;
        !           763:
        !           764:            m = (goal_f_out * n * (1 << a)) / F_REF;
        !           765:
        !           766:            if ((m > 257) || (m < 3)) continue;
        !           767:
        !           768:            pll_sample = (m * F_REF) / (n * (1 << a));
        !           769:            pll_sample /= 512;
        !           770:
        !           771:            /* Threshold might be good here */
        !           772:            error = pll_sample - r->sample_rate;
        !           773:            error = abs(error);
        !           774:
        !           775:            if (error < best_error) {
        !           776:              best_error = error;
        !           777:              best_n = n;
        !           778:              best_m = m;
        !           779:              if (error == 0) break;
        !           780:            }
        !           781:          }
        !           782:
        !           783:
        !           784:          best_n -= 2;
        !           785:          best_m -= 2;
        !           786:
        !           787:          sv_write_indirect(sc, SV_ADC_PLL_M, best_m);
        !           788:          sv_write_indirect(sc, SV_ADC_PLL_N, best_n | (a << SV_PLL_R_SHIFT));
        !           789:        }
        !           790:         return (0);
        !           791: }
        !           792:
        !           793: int
        !           794: sv_round_blocksize(addr, blk)
        !           795:        void *addr;
        !           796:        int blk;
        !           797: {
        !           798:        return ((blk + 31) & -32);      /* keep good alignment */
        !           799: }
        !           800:
        !           801: int
        !           802: sv_dma_init_input(addr, buf, cc)
        !           803:        void *addr;
        !           804:        void *buf;
        !           805:        int cc;
        !           806: {
        !           807:        struct sv_softc *sc = addr;
        !           808:        struct sv_dma *p;
        !           809:        int dma_count;
        !           810:
        !           811:        DPRINTF(("sv_dma_init_input: dma start loop input addr=%p cc=%d\n",
        !           812:                 buf, cc));
        !           813:         for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
        !           814:                ;
        !           815:        if (!p) {
        !           816:                printf("sv_dma_init_input: bad addr %p\n", buf);
        !           817:                return (EINVAL);
        !           818:        }
        !           819:
        !           820:        dma_count = (cc >> 1) - 1;
        !           821:
        !           822:        bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0,
        !           823:                          DMAADDR(p));
        !           824:        bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_COUNT0,
        !           825:                          dma_count);
        !           826:        bus_space_write_1(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_MODE,
        !           827:                          DMA37MD_WRITE | DMA37MD_LOOP);
        !           828:
        !           829:        return (0);
        !           830: }
        !           831:
        !           832: int
        !           833: sv_dma_init_output(addr, buf, cc)
        !           834:        void *addr;
        !           835:        void *buf;
        !           836:        int cc;
        !           837: {
        !           838:        struct sv_softc *sc = addr;
        !           839:        struct sv_dma *p;
        !           840:        int dma_count;
        !           841:
        !           842:        DPRINTF(("eap: dma start loop output buf=%p cc=%d\n", buf, cc));
        !           843:         for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
        !           844:                ;
        !           845:        if (!p) {
        !           846:                printf("sv_dma_init_output: bad addr %p\n", buf);
        !           847:                return (EINVAL);
        !           848:        }
        !           849:
        !           850:        dma_count = cc - 1;
        !           851:
        !           852:        bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0,
        !           853:                          DMAADDR(p));
        !           854:        bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_COUNT0,
        !           855:                          dma_count);
        !           856:        bus_space_write_1(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_MODE,
        !           857:                          DMA37MD_READ | DMA37MD_LOOP);
        !           858:
        !           859:        return (0);
        !           860: }
        !           861:
        !           862: int
        !           863: sv_dma_output(addr, p, cc, intr, arg)
        !           864:        void *addr;
        !           865:        void *p;
        !           866:        int cc;
        !           867:        void (*intr)(void *);
        !           868:        void *arg;
        !           869: {
        !           870:        struct sv_softc *sc = addr;
        !           871:        u_int8_t mode;
        !           872:
        !           873:        DPRINTFN(1,
        !           874:                  ("sv_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n",
        !           875:                   addr, p, cc, intr, arg));
        !           876:
        !           877:        sc->sc_pintr = intr;
        !           878:        sc->sc_parg = arg;
        !           879:        if (!(sc->sc_enable & SV_PLAY_ENABLE)) {
        !           880:                int dma_count = cc - 1;
        !           881:
        !           882:                sv_write_indirect(sc, SV_DMAA_COUNT1, dma_count >> 8);
        !           883:                sv_write_indirect(sc, SV_DMAA_COUNT0, (dma_count & 0xFF));
        !           884:
        !           885:                mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
        !           886:                mode |= SV_PLAY_ENABLE;
        !           887:                sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
        !           888:                sc->sc_enable |= SV_PLAY_ENABLE;
        !           889:        }
        !           890:         return (0);
        !           891: }
        !           892:
        !           893: int
        !           894: sv_dma_input(addr, p, cc, intr, arg)
        !           895:        void *addr;
        !           896:        void *p;
        !           897:        int cc;
        !           898:        void (*intr)(void *);
        !           899:        void *arg;
        !           900: {
        !           901:        struct sv_softc *sc = addr;
        !           902:        u_int8_t mode;
        !           903:
        !           904:        DPRINTFN(1, ("sv_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n",
        !           905:                     addr, p, cc, intr, arg));
        !           906:        sc->sc_rintr = intr;
        !           907:        sc->sc_rarg = arg;
        !           908:        if (!(sc->sc_enable & SV_RECORD_ENABLE)) {
        !           909:                int dma_count = (cc >> 1) - 1;
        !           910:
        !           911:                sv_write_indirect(sc, SV_DMAC_COUNT1, dma_count >> 8);
        !           912:                sv_write_indirect(sc, SV_DMAC_COUNT0, (dma_count & 0xFF));
        !           913:
        !           914:                mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
        !           915:                mode |= SV_RECORD_ENABLE;
        !           916:                sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
        !           917:                sc->sc_enable |= SV_RECORD_ENABLE;
        !           918:        }
        !           919:         return (0);
        !           920: }
        !           921:
        !           922: int
        !           923: sv_halt_out_dma(addr)
        !           924:        void *addr;
        !           925: {
        !           926:        struct sv_softc *sc = addr;
        !           927:        u_int8_t mode;
        !           928:
        !           929:         DPRINTF(("eap: sv_halt_out_dma\n"));
        !           930:        mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
        !           931:        mode &= ~SV_PLAY_ENABLE;
        !           932:        sc->sc_enable &= ~SV_PLAY_ENABLE;
        !           933:        sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
        !           934:
        !           935:         return (0);
        !           936: }
        !           937:
        !           938: int
        !           939: sv_halt_in_dma(addr)
        !           940:        void *addr;
        !           941: {
        !           942:        struct sv_softc *sc = addr;
        !           943:        u_int8_t mode;
        !           944:
        !           945:         DPRINTF(("eap: sv_halt_in_dma\n"));
        !           946:        mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
        !           947:        mode &= ~SV_RECORD_ENABLE;
        !           948:        sc->sc_enable &= ~SV_RECORD_ENABLE;
        !           949:        sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
        !           950:
        !           951:         return (0);
        !           952: }
        !           953:
        !           954: int
        !           955: sv_getdev(addr, retp)
        !           956:        void *addr;
        !           957:         struct audio_device *retp;
        !           958: {
        !           959:        *retp = sv_device;
        !           960:         return (0);
        !           961: }
        !           962:
        !           963:
        !           964: /*
        !           965:  * Mixer related code is here
        !           966:  *
        !           967:  */
        !           968:
        !           969: #define SV_INPUT_CLASS 0
        !           970: #define SV_OUTPUT_CLASS 1
        !           971: #define SV_RECORD_CLASS 2
        !           972:
        !           973: #define SV_LAST_CLASS 2
        !           974:
        !           975: static const char *mixer_classes[] = { AudioCinputs, AudioCoutputs, AudioCrecord };
        !           976:
        !           977: static const struct {
        !           978:   u_int8_t   l_port;
        !           979:   u_int8_t   r_port;
        !           980:   u_int8_t   mask;
        !           981:   u_int8_t   class;
        !           982:   const char *audio;
        !           983: } ports[] = {
        !           984:   { SV_LEFT_AUX1_INPUT_CONTROL, SV_RIGHT_AUX1_INPUT_CONTROL, SV_AUX1_MASK,
        !           985:     SV_INPUT_CLASS, "aux1" },
        !           986:   { SV_LEFT_CD_INPUT_CONTROL, SV_RIGHT_CD_INPUT_CONTROL, SV_CD_MASK,
        !           987:     SV_INPUT_CLASS, AudioNcd },
        !           988:   { SV_LEFT_LINE_IN_INPUT_CONTROL, SV_RIGHT_LINE_IN_INPUT_CONTROL, SV_LINE_IN_MASK,
        !           989:     SV_INPUT_CLASS, AudioNline },
        !           990:   { SV_MIC_INPUT_CONTROL, 0, SV_MIC_MASK, SV_INPUT_CLASS, AudioNmicrophone },
        !           991:   { SV_LEFT_SYNTH_INPUT_CONTROL, SV_RIGHT_SYNTH_INPUT_CONTROL,
        !           992:     SV_SYNTH_MASK, SV_INPUT_CLASS, AudioNfmsynth },
        !           993:   { SV_LEFT_AUX2_INPUT_CONTROL, SV_RIGHT_AUX2_INPUT_CONTROL, SV_AUX2_MASK,
        !           994:     SV_INPUT_CLASS, "aux2" },
        !           995:   { SV_LEFT_PCM_INPUT_CONTROL, SV_RIGHT_PCM_INPUT_CONTROL, SV_PCM_MASK,
        !           996:     SV_INPUT_CLASS, AudioNdac },
        !           997:   { SV_LEFT_MIXER_OUTPUT_CONTROL, SV_RIGHT_MIXER_OUTPUT_CONTROL,
        !           998:     SV_MIXER_OUT_MASK, SV_OUTPUT_CLASS, AudioNmaster }
        !           999: };
        !          1000:
        !          1001:
        !          1002: static const struct {
        !          1003:   int idx;
        !          1004:   const char *name;
        !          1005: } record_sources[] = {
        !          1006:   { SV_REC_CD, AudioNcd },
        !          1007:   { SV_REC_DAC, AudioNdac },
        !          1008:   { SV_REC_AUX2, "aux2" },
        !          1009:   { SV_REC_LINE, AudioNline },
        !          1010:   { SV_REC_AUX1, "aux1" },
        !          1011:   { SV_REC_MIC, AudioNmicrophone },
        !          1012:   { SV_REC_MIXER, AudioNmixerout }
        !          1013: };
        !          1014:
        !          1015:
        !          1016: #define SV_DEVICES_PER_PORT 2
        !          1017: #define SV_FIRST_MIXER (SV_LAST_CLASS + 1)
        !          1018: #define SV_LAST_MIXER (SV_DEVICES_PER_PORT * (ARRAY_SIZE(ports)) + SV_LAST_CLASS)
        !          1019: #define SV_RECORD_SOURCE (SV_LAST_MIXER + 1)
        !          1020: #define SV_MIC_BOOST (SV_LAST_MIXER + 2)
        !          1021: #define SV_RECORD_GAIN (SV_LAST_MIXER + 3)
        !          1022: #define SV_SRS_MODE (SV_LAST_MIXER + 4)
        !          1023:
        !          1024: int
        !          1025: sv_query_devinfo(addr, dip)
        !          1026:        void *addr;
        !          1027:        mixer_devinfo_t *dip;
        !          1028: {
        !          1029:
        !          1030:   /* It's a class */
        !          1031:   if (dip->index <= SV_LAST_CLASS) {
        !          1032:     dip->type = AUDIO_MIXER_CLASS;
        !          1033:     dip->mixer_class = dip->index;
        !          1034:     dip->next = dip->prev = AUDIO_MIXER_LAST;
        !          1035:     strlcpy(dip->label.name, mixer_classes[dip->index],
        !          1036:            sizeof dip->label.name);
        !          1037:     return (0);
        !          1038:   }
        !          1039:
        !          1040:   if (dip->index >= SV_FIRST_MIXER &&
        !          1041:       dip->index <= SV_LAST_MIXER) {
        !          1042:     int off = dip->index - SV_FIRST_MIXER;
        !          1043:     int mute = (off % SV_DEVICES_PER_PORT);
        !          1044:     int idx = off / SV_DEVICES_PER_PORT;
        !          1045:
        !          1046:     dip->mixer_class = ports[idx].class;
        !          1047:     strlcpy(dip->label.name, ports[idx].audio, sizeof dip->label.name);
        !          1048:
        !          1049:     if (!mute) {
        !          1050:       dip->type = AUDIO_MIXER_VALUE;
        !          1051:       dip->prev = AUDIO_MIXER_LAST;
        !          1052:       dip->next = dip->index + 1;
        !          1053:
        !          1054:       if (ports[idx].r_port != 0)
        !          1055:        dip->un.v.num_channels = 2;
        !          1056:       else
        !          1057:        dip->un.v.num_channels = 1;
        !          1058:
        !          1059:       strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
        !          1060:
        !          1061:     } else {
        !          1062:       dip->type = AUDIO_MIXER_ENUM;
        !          1063:       dip->prev = dip->index - 1;
        !          1064:       dip->next = AUDIO_MIXER_LAST;
        !          1065:
        !          1066:       strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
        !          1067:       dip->un.e.num_mem = 2;
        !          1068:       strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1069:          sizeof dip->un.e.member[0].label.name);
        !          1070:       dip->un.e.member[0].ord = 0;
        !          1071:       strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1072:          sizeof dip->un.e.member[1].label.name);
        !          1073:       dip->un.e.member[1].ord = 1;
        !          1074:
        !          1075:     }
        !          1076:
        !          1077:     return (0);
        !          1078:   }
        !          1079:
        !          1080:   switch (dip->index) {
        !          1081:   case SV_RECORD_SOURCE:
        !          1082:     dip->mixer_class = SV_RECORD_CLASS;
        !          1083:     dip->prev = AUDIO_MIXER_LAST;
        !          1084:     dip->next = SV_RECORD_GAIN;
        !          1085:     strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
        !          1086:     dip->type = AUDIO_MIXER_ENUM;
        !          1087:
        !          1088:     dip->un.e.num_mem = ARRAY_SIZE(record_sources);
        !          1089:
        !          1090:     {
        !          1091:       int idx;
        !          1092:       for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) {
        !          1093:        strlcpy(dip->un.e.member[idx].label.name, record_sources[idx].name,
        !          1094:            sizeof dip->un.e.member[idx].label.name);
        !          1095:        dip->un.e.member[idx].ord = record_sources[idx].idx;
        !          1096:       }
        !          1097:     }
        !          1098:     return (0);
        !          1099:
        !          1100:   case SV_RECORD_GAIN:
        !          1101:     dip->mixer_class = SV_RECORD_CLASS;
        !          1102:     dip->prev = SV_RECORD_SOURCE;
        !          1103:     dip->next = AUDIO_MIXER_LAST;
        !          1104:     strlcpy(dip->label.name, "gain", sizeof dip->label.name);
        !          1105:     dip->type = AUDIO_MIXER_VALUE;
        !          1106:     dip->un.v.num_channels = 1;
        !          1107:     strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
        !          1108:     return (0);
        !          1109:
        !          1110:   case SV_MIC_BOOST:
        !          1111:     dip->mixer_class = SV_RECORD_CLASS;
        !          1112:     dip->prev = AUDIO_MIXER_LAST;
        !          1113:     dip->next = AUDIO_MIXER_LAST;
        !          1114:     strlcpy(dip->label.name, "micboost", sizeof dip->label.name);
        !          1115:     goto on_off;
        !          1116:
        !          1117:   case SV_SRS_MODE:
        !          1118:     dip->mixer_class = SV_OUTPUT_CLASS;
        !          1119:     dip->prev = dip->next = AUDIO_MIXER_LAST;
        !          1120:     strlcpy(dip->label.name, AudioNspatial, sizeof dip->label.name);
        !          1121:
        !          1122: on_off:
        !          1123:     dip->type = AUDIO_MIXER_ENUM;
        !          1124:     dip->un.e.num_mem = 2;
        !          1125:     strlcpy(dip->un.e.member[0].label.name, AudioNoff,
        !          1126:        sizeof dip->un.e.member[0].label.name);
        !          1127:     dip->un.e.member[0].ord = 0;
        !          1128:     strlcpy(dip->un.e.member[1].label.name, AudioNon,
        !          1129:        sizeof dip->un.e.member[1].label.name);
        !          1130:     dip->un.e.member[1].ord = 1;
        !          1131:     return (0);
        !          1132:   }
        !          1133:
        !          1134:   return (ENXIO);
        !          1135: }
        !          1136:
        !          1137: int
        !          1138: sv_mixer_set_port(addr, cp)
        !          1139:        void *addr;
        !          1140:        mixer_ctrl_t *cp;
        !          1141: {
        !          1142:   struct sv_softc *sc = addr;
        !          1143:   u_int8_t reg;
        !          1144:   int idx;
        !          1145:
        !          1146:   if (cp->dev >= SV_FIRST_MIXER &&
        !          1147:       cp->dev <= SV_LAST_MIXER) {
        !          1148:     int off = cp->dev - SV_FIRST_MIXER;
        !          1149:     int mute = (off % SV_DEVICES_PER_PORT);
        !          1150:     idx = off / SV_DEVICES_PER_PORT;
        !          1151:
        !          1152:     if (mute) {
        !          1153:       if (cp->type != AUDIO_MIXER_ENUM)
        !          1154:        return (EINVAL);
        !          1155:
        !          1156:       reg = sv_read_indirect(sc, ports[idx].l_port);
        !          1157:       if (cp->un.ord)
        !          1158:        reg |= SV_MUTE_BIT;
        !          1159:       else
        !          1160:        reg &= ~SV_MUTE_BIT;
        !          1161:       sv_write_indirect(sc, ports[idx].l_port, reg);
        !          1162:
        !          1163:       if (ports[idx].r_port) {
        !          1164:        reg = sv_read_indirect(sc, ports[idx].r_port);
        !          1165:        if (cp->un.ord)
        !          1166:          reg |= SV_MUTE_BIT;
        !          1167:        else
        !          1168:          reg &= ~SV_MUTE_BIT;
        !          1169:        sv_write_indirect(sc, ports[idx].r_port, reg);
        !          1170:       }
        !          1171:     } else {
        !          1172:       int  lval, rval;
        !          1173:
        !          1174:       if (cp->type != AUDIO_MIXER_VALUE)
        !          1175:        return (EINVAL);
        !          1176:
        !          1177:       if (cp->un.value.num_channels != 1 &&
        !          1178:          cp->un.value.num_channels != 2)
        !          1179:        return (EINVAL);
        !          1180:
        !          1181:       if (ports[idx].r_port == 0) {
        !          1182:        if (cp->un.value.num_channels != 1)
        !          1183:          return (EINVAL);
        !          1184:        lval = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
        !          1185:       } else {
        !          1186:        if (cp->un.value.num_channels != 2)
        !          1187:          return (EINVAL);
        !          1188:
        !          1189:        lval = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
        !          1190:        rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
        !          1191:       }
        !          1192:
        !          1193:       sc->sc_trd = 1;
        !          1194:
        !          1195:       reg = sv_read_indirect(sc, ports[idx].l_port);
        !          1196:       reg &= ~(ports[idx].mask);
        !          1197:       lval = ((AUDIO_MAX_GAIN - lval) * ports[idx].mask) / AUDIO_MAX_GAIN;
        !          1198:       reg |= lval;
        !          1199:       sv_write_indirect(sc, ports[idx].l_port, reg);
        !          1200:
        !          1201:       if (ports[idx].r_port != 0) {
        !          1202:        reg = sv_read_indirect(sc, ports[idx].r_port);
        !          1203:        reg &= ~(ports[idx].mask);
        !          1204:
        !          1205:        rval = ((AUDIO_MAX_GAIN - rval) * ports[idx].mask) / AUDIO_MAX_GAIN;
        !          1206:        reg |= rval;
        !          1207:
        !          1208:        sv_write_indirect(sc, ports[idx].r_port, reg);
        !          1209:       }
        !          1210:
        !          1211:       sc->sc_trd = 0;
        !          1212:       sv_read_indirect(sc, ports[idx].l_port);
        !          1213:     }
        !          1214:
        !          1215:     return (0);
        !          1216:   }
        !          1217:
        !          1218:
        !          1219:   switch (cp->dev) {
        !          1220:   case SV_RECORD_SOURCE:
        !          1221:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1222:       return (EINVAL);
        !          1223:
        !          1224:     for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) {
        !          1225:       if (record_sources[idx].idx == cp->un.ord)
        !          1226:        goto found;
        !          1227:     }
        !          1228:
        !          1229:     return (EINVAL);
        !          1230:
        !          1231:   found:
        !          1232:     reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
        !          1233:     reg &= ~SV_REC_SOURCE_MASK;
        !          1234:     reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
        !          1235:     sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
        !          1236:
        !          1237:     reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
        !          1238:     reg &= ~SV_REC_SOURCE_MASK;
        !          1239:     reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
        !          1240:     sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
        !          1241:     return (0);
        !          1242:
        !          1243:   case SV_RECORD_GAIN:
        !          1244:     {
        !          1245:       int val;
        !          1246:
        !          1247:       if (cp->type != AUDIO_MIXER_VALUE)
        !          1248:        return (EINVAL);
        !          1249:
        !          1250:       if (cp->un.value.num_channels != 1)
        !          1251:        return (EINVAL);
        !          1252:
        !          1253:       val = (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] * SV_REC_GAIN_MASK)
        !          1254:        / AUDIO_MAX_GAIN;
        !          1255:
        !          1256:       reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
        !          1257:       reg &= ~SV_REC_GAIN_MASK;
        !          1258:       reg |= val;
        !          1259:       sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
        !          1260:
        !          1261:       reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
        !          1262:       reg &= ~SV_REC_GAIN_MASK;
        !          1263:       reg |= val;
        !          1264:       sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
        !          1265:
        !          1266:     }
        !          1267:
        !          1268:     return (0);
        !          1269:
        !          1270:   case SV_MIC_BOOST:
        !          1271:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1272:       return (EINVAL);
        !          1273:
        !          1274:     reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
        !          1275:     if (cp->un.ord) {
        !          1276:       reg |= SV_MIC_BOOST_BIT;
        !          1277:     } else {
        !          1278:       reg &= ~SV_MIC_BOOST_BIT;
        !          1279:     }
        !          1280:
        !          1281:     sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
        !          1282:     return (0);
        !          1283:
        !          1284:   case SV_SRS_MODE:
        !          1285:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1286:       return (EINVAL);
        !          1287:
        !          1288:     reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
        !          1289:     if (cp->un.ord) {
        !          1290:       reg &= ~SV_SRS_SPACE_ONOFF;
        !          1291:     } else {
        !          1292:       reg |= SV_SRS_SPACE_ONOFF;
        !          1293:     }
        !          1294:
        !          1295:     sv_write_indirect(sc, SV_SRS_SPACE_CONTROL, reg);
        !          1296:     return (0);
        !          1297:   }
        !          1298:
        !          1299:   return (EINVAL);
        !          1300: }
        !          1301:
        !          1302: int
        !          1303: sv_mixer_get_port(addr, cp)
        !          1304:        void *addr;
        !          1305:        mixer_ctrl_t *cp;
        !          1306: {
        !          1307:   struct sv_softc *sc = addr;
        !          1308:   int val;
        !          1309:   u_int8_t reg;
        !          1310:
        !          1311:   if (cp->dev >= SV_FIRST_MIXER &&
        !          1312:       cp->dev <= SV_LAST_MIXER) {
        !          1313:     int off = cp->dev - SV_FIRST_MIXER;
        !          1314:     int mute = (off % 2);
        !          1315:     int idx = off / 2;
        !          1316:
        !          1317:     if (mute) {
        !          1318:       if (cp->type != AUDIO_MIXER_ENUM)
        !          1319:        return (EINVAL);
        !          1320:
        !          1321:       reg = sv_read_indirect(sc, ports[idx].l_port);
        !          1322:       cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0);
        !          1323:     } else {
        !          1324:       if (cp->type != AUDIO_MIXER_VALUE)
        !          1325:        return (EINVAL);
        !          1326:
        !          1327:       if (cp->un.value.num_channels != 1 &&
        !          1328:          cp->un.value.num_channels != 2)
        !          1329:        return (EINVAL);
        !          1330:
        !          1331:       if ((ports[idx].r_port == 0 &&
        !          1332:           cp->un.value.num_channels != 1) ||
        !          1333:          (ports[idx].r_port != 0 &&
        !          1334:           cp->un.value.num_channels != 2))
        !          1335:        return (EINVAL);
        !          1336:
        !          1337:       reg = sv_read_indirect(sc, ports[idx].l_port);
        !          1338:       reg &= ports[idx].mask;
        !          1339:
        !          1340:       val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
        !          1341:
        !          1342:       if (ports[idx].r_port != 0) {
        !          1343:        cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = val;
        !          1344:
        !          1345:        reg = sv_read_indirect(sc, ports[idx].r_port);
        !          1346:        reg &= ports[idx].mask;
        !          1347:
        !          1348:        val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
        !          1349:        cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = val;
        !          1350:       } else
        !          1351:        cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = val;
        !          1352:     }
        !          1353:
        !          1354:     return (0);
        !          1355:   }
        !          1356:
        !          1357:   switch (cp->dev) {
        !          1358:   case SV_RECORD_SOURCE:
        !          1359:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1360:       return (EINVAL);
        !          1361:
        !          1362:     reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
        !          1363:     cp->un.ord = ((reg & SV_REC_SOURCE_MASK) >> SV_REC_SOURCE_SHIFT);
        !          1364:
        !          1365:     return (0);
        !          1366:
        !          1367:   case SV_RECORD_GAIN:
        !          1368:     if (cp->type != AUDIO_MIXER_VALUE)
        !          1369:       return (EINVAL);
        !          1370:
        !          1371:     if (cp->un.value.num_channels != 1)
        !          1372:       return (EINVAL);
        !          1373:
        !          1374:     reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL) & SV_REC_GAIN_MASK;
        !          1375:     cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
        !          1376:       (((unsigned int)reg) * AUDIO_MAX_GAIN) / SV_REC_GAIN_MASK;
        !          1377:
        !          1378:     return (0);
        !          1379:
        !          1380:   case SV_MIC_BOOST:
        !          1381:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1382:       return (EINVAL);
        !          1383:
        !          1384:     reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
        !          1385:     cp->un.ord = ((reg & SV_MIC_BOOST_BIT) ? 1 : 0);
        !          1386:
        !          1387:     return (0);
        !          1388:
        !          1389:
        !          1390:   case SV_SRS_MODE:
        !          1391:     if (cp->type != AUDIO_MIXER_ENUM)
        !          1392:       return (EINVAL);
        !          1393:
        !          1394:     reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
        !          1395:
        !          1396:     cp->un.ord = ((reg & SV_SRS_SPACE_ONOFF) ? 0 : 1);
        !          1397:     return (0);
        !          1398:   }
        !          1399:
        !          1400:   return (EINVAL);
        !          1401: }
        !          1402:
        !          1403:
        !          1404: static void
        !          1405: sv_init_mixer(sc)
        !          1406:      struct sv_softc *sc;
        !          1407: {
        !          1408:   mixer_ctrl_t cp;
        !          1409:   int idx;
        !          1410:
        !          1411:   cp.type = AUDIO_MIXER_ENUM;
        !          1412:   cp.dev = SV_SRS_MODE;
        !          1413:   cp.un.ord = 0;
        !          1414:
        !          1415:   sv_mixer_set_port(sc, &cp);
        !          1416:
        !          1417:   for (idx = 0; idx < ARRAY_SIZE(ports); idx++) {
        !          1418:     if (ports[idx].audio == AudioNdac) {
        !          1419:       cp.type = AUDIO_MIXER_ENUM;
        !          1420:       cp.dev = SV_FIRST_MIXER + idx * SV_DEVICES_PER_PORT + 1;
        !          1421:       cp.un.ord = 0;
        !          1422:       sv_mixer_set_port(sc, &cp);
        !          1423:       break;
        !          1424:     }
        !          1425:   }
        !          1426: }
        !          1427:
        !          1428: void *
        !          1429: sv_malloc(addr, direction, size, pool, flags)
        !          1430:        void *addr;
        !          1431:        int direction;
        !          1432:        size_t size;
        !          1433:        int pool;
        !          1434:        int flags;
        !          1435: {
        !          1436:        struct sv_softc *sc = addr;
        !          1437:         struct sv_dma *p;
        !          1438:         int error;
        !          1439:
        !          1440:         p = malloc(sizeof(*p), pool, flags);
        !          1441:         if (!p)
        !          1442:                 return (0);
        !          1443:         error = sv_allocmem(sc, size, 16, p);
        !          1444:         if (error) {
        !          1445:                 free(p, pool);
        !          1446:                return (0);
        !          1447:         }
        !          1448:         p->next = sc->sc_dmas;
        !          1449:         sc->sc_dmas = p;
        !          1450:        return (KERNADDR(p));
        !          1451: }
        !          1452:
        !          1453: void
        !          1454: sv_free(addr, ptr, pool)
        !          1455:        void *addr;
        !          1456:        void *ptr;
        !          1457:        int pool;
        !          1458: {
        !          1459:        struct sv_softc *sc = addr;
        !          1460:         struct sv_dma **p;
        !          1461:
        !          1462:         for (p = &sc->sc_dmas; *p; p = &(*p)->next) {
        !          1463:                 if (KERNADDR(*p) == ptr) {
        !          1464:                         sv_freemem(sc, *p);
        !          1465:                         *p = (*p)->next;
        !          1466:                         free(*p, pool);
        !          1467:                         return;
        !          1468:                 }
        !          1469:         }
        !          1470: }
        !          1471:
        !          1472: paddr_t
        !          1473: sv_mappage(addr, mem, off, prot)
        !          1474:        void *addr;
        !          1475:         void *mem;
        !          1476:         off_t off;
        !          1477:        int prot;
        !          1478: {
        !          1479:        struct sv_softc *sc = addr;
        !          1480:         struct sv_dma *p;
        !          1481:
        !          1482:         for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
        !          1483:                ;
        !          1484:        if (!p)
        !          1485:                return (-1);
        !          1486:        return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs,
        !          1487:                                off, prot, BUS_DMA_WAITOK));
        !          1488: }
        !          1489:
        !          1490: int
        !          1491: sv_get_props(addr)
        !          1492:        void *addr;
        !          1493: {
        !          1494:        return (AUDIO_PROP_MMAP | AUDIO_PROP_FULLDUPLEX);
        !          1495: }

CVSweb