[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

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