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

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

1.1       nbrk        1: /*     $OpenBSD: fms.c,v 1.17 2005/04/16 21:57:23 mickey Exp $ */
                      2: /*     $NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $       */
                      3:
                      4: /*-
                      5:  * Copyright (c) 1999 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Witold J. Wnuk.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the NetBSD
                     22:  *     Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: /*
                     41:  * Forte Media FM801 Audio Device Driver
                     42:  */
                     43:
                     44: #include "radio.h"
                     45:
                     46: #include <sys/param.h>
                     47: #include <sys/systm.h>
                     48: #include <sys/kernel.h>
                     49: #include <sys/malloc.h>
                     50: #include <sys/device.h>
                     51: #include <sys/audioio.h>
                     52:
                     53: #include <machine/bus.h>
                     54: #include <machine/cpu.h>
                     55:
                     56: #include <dev/pci/pcidevs.h>
                     57: #include <dev/pci/pcivar.h>
                     58:
                     59: #include <dev/audio_if.h>
                     60: #include <dev/mulaw.h>
                     61: #include <dev/auconv.h>
                     62:
                     63: #include <dev/ic/ac97.h>
                     64: #if 0
                     65: #include <dev/ic/mpuvar.h>
                     66: #endif
                     67:
                     68: #include <dev/pci/fmsreg.h>
                     69: #include <dev/pci/fmsvar.h>
                     70:
                     71:
                     72: struct fms_dma {
                     73:        struct fms_dma *next;
                     74:        caddr_t addr;
                     75:        size_t size;
                     76:        bus_dmamap_t map;
                     77:        bus_dma_segment_t seg;
                     78: };
                     79:
                     80:
                     81:
                     82: int    fms_match(struct device *, void *, void *);
                     83: void   fms_attach(struct device *, struct device *, void *);
                     84: int    fms_intr(void *);
                     85:
                     86: int    fms_open(void *, int);
                     87: void   fms_close(void *);
                     88: int    fms_query_encoding(void *, struct audio_encoding *);
                     89: int    fms_set_params(void *, int, int, struct audio_params *,
                     90:                            struct audio_params *);
                     91: int    fms_round_blocksize(void *, int);
                     92: int    fms_halt_output(void *);
                     93: int    fms_halt_input(void *);
                     94: int    fms_getdev(void *, struct audio_device *);
                     95: int    fms_set_port(void *, mixer_ctrl_t *);
                     96: int    fms_get_port(void *, mixer_ctrl_t *);
                     97: int    fms_query_devinfo(void *, mixer_devinfo_t *);
                     98: void   *fms_malloc(void *, int, size_t, int, int);
                     99: void   fms_free(void *, void *, int);
                    100: paddr_t        fms_mappage(void *, void *, off_t, int);
                    101: int    fms_get_props(void *);
                    102: int    fms_trigger_output(void *, void *, void *, int, void (*)(void *),
                    103:                           void *, struct audio_params *);
                    104: int    fms_trigger_input(void *, void *, void *, int, void (*)(void *),
                    105:                          void *, struct audio_params *);
                    106:
                    107: struct  cfdriver fms_cd = {
                    108:        NULL, "fms", DV_DULL
                    109: };
                    110:
                    111: struct cfattach fms_ca = {
                    112:        sizeof (struct fms_softc), fms_match, fms_attach
                    113: };
                    114:
                    115: struct audio_device fms_device = {
                    116:        "Forte Media 801",
                    117:        "1.0",
                    118:        "fms"
                    119: };
                    120:
                    121:
                    122: struct audio_hw_if fms_hw_if = {
                    123:        fms_open,
                    124:        fms_close,
                    125:        NULL,
                    126:        fms_query_encoding,
                    127:        fms_set_params,
                    128:        fms_round_blocksize,
                    129:        NULL,
                    130:        NULL,
                    131:        NULL,
                    132:        NULL,
                    133:        NULL,
                    134:        fms_halt_output,
                    135:        fms_halt_input,
                    136:        NULL,
                    137:        fms_getdev,
                    138:        NULL,
                    139:        fms_set_port,
                    140:        fms_get_port,
                    141:        fms_query_devinfo,
                    142:        fms_malloc,
                    143:        fms_free,
                    144:        NULL,
                    145:        fms_mappage,
                    146:        fms_get_props,
                    147:        fms_trigger_output,
                    148:        fms_trigger_input
                    149: };
                    150:
                    151: int    fms_attach_codec(void *, struct ac97_codec_if *);
                    152: int    fms_read_codec(void *, u_int8_t, u_int16_t *);
                    153: int    fms_write_codec(void *, u_int8_t, u_int16_t);
                    154: void   fms_reset_codec(void *);
                    155:
                    156: int    fms_allocmem(struct fms_softc *, size_t, size_t,
                    157:                          struct fms_dma *);
                    158: int    fms_freemem(struct fms_softc *, struct fms_dma *);
                    159:
                    160: int
                    161: fms_match(parent, match, aux)
                    162:        struct device *parent;
                    163:        void *match;
                    164:        void *aux;
                    165: {
                    166:        struct pci_attach_args *pa = (struct pci_attach_args *) aux;
                    167:
                    168:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA &&
                    169:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801)
                    170:                return (1);
                    171:        return (0);
                    172: }
                    173:
                    174: void
                    175: fms_attach(parent, self, aux)
                    176:        struct device *parent;
                    177:        struct device *self;
                    178:        void *aux;
                    179: {
                    180:        struct pci_attach_args *pa = aux;
                    181:        struct fms_softc *sc = (struct fms_softc *) self;
                    182:        struct audio_attach_args aa;
                    183:        pci_chipset_tag_t pc = pa->pa_pc;
                    184:        pcitag_t pt = pa->pa_tag;
                    185:        pci_intr_handle_t ih;
                    186:        bus_size_t iosize;
                    187:        const char *intrstr;
                    188:        u_int16_t k1;
                    189:        int i;
                    190:
                    191:        if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
                    192:            &sc->sc_ioh, NULL, &iosize, 0)) {
                    193:                printf(": can't map i/o space\n");
                    194:                return;
                    195:        }
                    196:
                    197:        if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
                    198:            &sc->sc_mpu_ioh)) {
                    199:                printf(": can't get mpu subregion handle\n");
                    200:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    201:                return;
                    202:        }
                    203:
                    204:        if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
                    205:            &sc->sc_opl_ioh)) {
                    206:                printf(": can't get opl subregion handle\n");
                    207:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    208:                return;
                    209:        }
                    210:
                    211:        if (pci_intr_map(pa, &ih)) {
                    212:                printf(": couldn't map interrupt\n");
                    213:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    214:                return;
                    215:        }
                    216:        intrstr = pci_intr_string(pc, ih);
                    217:
                    218:        sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc,
                    219:            sc->sc_dev.dv_xname);
                    220:        if (sc->sc_ih == NULL) {
                    221:                printf(": couldn't establish interrupt");
                    222:                if (intrstr != NULL)
                    223:                        printf(" at %s", intrstr);
                    224:                printf("\n");
                    225:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
                    226:                return;
                    227:        }
                    228:
                    229:        printf(": %s\n", intrstr);
                    230:
                    231:        sc->sc_dmat = pa->pa_dmat;
                    232:
                    233:        /* Disable legacy audio (SBPro compatibility) */
                    234:        pci_conf_write(pc, pt, 0x40, 0);
                    235:
                    236:        /* Reset codec and AC'97 */
                    237:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
                    238:        delay(2);               /* > 1us according to AC'97 documentation */
                    239:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
                    240:        delay(1);               /* > 168.2ns according to AC'97 documentation */
                    241:
                    242:        /* Set up volume */
                    243:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
                    244:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
                    245:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
                    246:
                    247:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
                    248:
                    249:        /* Unmask playback, record and mpu interrupts, mask the rest */
                    250:        k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
                    251:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK,
                    252:            (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
                    253:             FM_INTMASK_VOL);
                    254:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
                    255:            FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
                    256:            FM_INTSTATUS_VOL);
                    257:
                    258: #if NRADIO > 0
                    259:        fmsradio_attach(sc);
                    260: #endif /* NRADIO > 0 */
                    261:
                    262:        sc->host_if.arg = sc;
                    263:        sc->host_if.attach = fms_attach_codec;
                    264:        sc->host_if.read = fms_read_codec;
                    265:        sc->host_if.write = fms_write_codec;
                    266:        sc->host_if.reset = fms_reset_codec;
                    267:
                    268:        if (ac97_attach(&sc->host_if) != 0)
                    269:                return;
                    270:
                    271:        /* Turn mute off */
                    272:        for (i = 0; i < 3; i++) {
                    273:                static struct {
                    274:                        char *class, *device;
                    275:                } d[] = {
                    276:                        { AudioCoutputs, AudioNmaster },
                    277:                        { AudioCinputs, AudioNdac },
                    278:                        { AudioCrecord, AudioNvolume }
                    279:                };
                    280:                struct mixer_ctrl ctl;
                    281:
                    282:                ctl.type = AUDIO_MIXER_ENUM;
                    283:                ctl.un.ord = 0;
                    284:                ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
                    285:                        d[i].class, d[i].device, AudioNmute);
                    286:                fms_set_port(sc, &ctl);
                    287:        }
                    288:
                    289:        audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
                    290:
                    291:        aa.type = AUDIODEV_TYPE_OPL;
                    292:        aa.hwif = NULL;
                    293:        aa.hdl = NULL;
                    294:        config_found(&sc->sc_dev, &aa, audioprint);
                    295:
                    296:        aa.type = AUDIODEV_TYPE_MPU;
                    297:        aa.hwif = NULL;
                    298:        aa.hdl = NULL;
                    299:        sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
                    300: }
                    301:
                    302: /*
                    303:  * Each AC-link frame takes 20.8us, data should be ready in next frame,
                    304:  * we allow more than two.
                    305:  */
                    306: #define TIMO 50
                    307: int
                    308: fms_read_codec(addr, reg, val)
                    309:        void *addr;
                    310:        u_int8_t reg;
                    311:        u_int16_t *val;
                    312: {
                    313:        struct fms_softc *sc = addr;
                    314:        int i;
                    315:
                    316:        /* Poll until codec is ready */
                    317:        for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
                    318:                 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
                    319:                delay(1);
                    320:        if (i >= TIMO) {
                    321:                printf("fms: codec busy\n");
                    322:                return 1;
                    323:        }
                    324:
                    325:        /* Write register index, read access */
                    326:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
                    327:                          reg | FM_CODEC_CMD_READ);
                    328:
                    329:        /* Poll until we have valid data */
                    330:        for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
                    331:                 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
                    332:                delay(1);
                    333:        if (i >= TIMO) {
                    334:                printf("fms: no data from codec\n");
                    335:                return 1;
                    336:        }
                    337:
                    338:        /* Read data */
                    339:        *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
                    340:        return 0;
                    341: }
                    342:
                    343: int
                    344: fms_write_codec(addr, reg, val)
                    345:        void *addr;
                    346:        u_int8_t reg;
                    347:        u_int16_t val;
                    348: {
                    349:        struct fms_softc *sc = addr;
                    350:        int i;
                    351:
                    352:        /* Poll until codec is ready */
                    353:        for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
                    354:                 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
                    355:                delay(1);
                    356:        if (i >= TIMO) {
                    357:                printf("fms: codec busy\n");
                    358:                return 1;
                    359:        }
                    360:
                    361:        /* Write data */
                    362:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
                    363:        /* Write index register, write access */
                    364:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
                    365:        return 0;
                    366: }
                    367: #undef TIMO
                    368:
                    369: int
                    370: fms_attach_codec(addr, cif)
                    371:        void *addr;
                    372:        struct ac97_codec_if *cif;
                    373: {
                    374:        struct fms_softc *sc = addr;
                    375:
                    376:        sc->codec_if = cif;
                    377:        return 0;
                    378: }
                    379:
                    380: /* Cold Reset */
                    381: void
                    382: fms_reset_codec(addr)
                    383:        void *addr;
                    384: {
                    385:        struct fms_softc *sc = addr;
                    386:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
                    387:        delay(2);
                    388:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
                    389:        delay(1);
                    390: }
                    391:
                    392: int
                    393: fms_intr(arg)
                    394:        void *arg;
                    395: {
                    396:        struct fms_softc *sc = arg;
                    397:        u_int16_t istat;
                    398:
                    399:        istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
                    400:
                    401:        if (istat & FM_INTSTATUS_PLAY) {
                    402:                if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
                    403:                     sc->sc_play_end)
                    404:                        sc->sc_play_nextblk = sc->sc_play_start;
                    405:
                    406:                bus_space_write_4(sc->sc_iot, sc->sc_ioh,
                    407:                    sc->sc_play_flip++ & 1 ?
                    408:                    FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
                    409:
                    410:                if (sc->sc_pintr)
                    411:                        sc->sc_pintr(sc->sc_parg);
                    412:                else
                    413:                        printf("unexpected play intr\n");
                    414:        }
                    415:
                    416:        if (istat & FM_INTSTATUS_REC) {
                    417:                if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
                    418:                     sc->sc_rec_end)
                    419:                        sc->sc_rec_nextblk = sc->sc_rec_start;
                    420:
                    421:                bus_space_write_4(sc->sc_iot, sc->sc_ioh,
                    422:                    sc->sc_rec_flip++ & 1 ?
                    423:                    FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
                    424:
                    425:                if (sc->sc_rintr)
                    426:                        sc->sc_rintr(sc->sc_rarg);
                    427:                else
                    428:                        printf("unexpected rec intr\n");
                    429:        }
                    430:
                    431: #if 0
                    432:        if (istat & FM_INTSTATUS_MPU)
                    433:                mpu_intr(sc->sc_mpu_dev);
                    434: #endif
                    435:
                    436:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
                    437:                          istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
                    438:
                    439:        return 1;
                    440: }
                    441:
                    442: int
                    443: fms_open(addr, flags)
                    444:        void *addr;
                    445:        int flags;
                    446: {
                    447:        /* UNUSED struct fms_softc *sc = addr;*/
                    448:
                    449:        return 0;
                    450: }
                    451:
                    452: void
                    453: fms_close(addr)
                    454:        void *addr;
                    455: {
                    456:        /* UNUSED struct fms_softc *sc = addr;*/
                    457: }
                    458:
                    459: int
                    460: fms_query_encoding(addr, fp)
                    461:        void *addr;
                    462:        struct audio_encoding *fp;
                    463: {
                    464:
                    465:        switch (fp->index) {
                    466:        case 0:
                    467:                strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
                    468:                fp->encoding = AUDIO_ENCODING_ULAW;
                    469:                fp->precision = 8;
                    470:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    471:                return 0;
                    472:        case 1:
                    473:                strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
                    474:                fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    475:                fp->precision = 16;
                    476:                fp->flags = 0;
                    477:                return 0;
                    478:        case 2:
                    479:                strlcpy(fp->name, AudioEulinear, sizeof fp->name);
                    480:                fp->encoding = AUDIO_ENCODING_ULINEAR;
                    481:                fp->precision = 8;
                    482:                fp->flags = 0;
                    483:                return 0;
                    484:        case 3:
                    485:                strlcpy(fp->name, AudioEalaw, sizeof fp->name);
                    486:                fp->encoding = AUDIO_ENCODING_ALAW;
                    487:                fp->precision = 8;
                    488:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    489:                return 0;
                    490:        case 4:
                    491:                strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
                    492:                fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    493:                fp->precision = 16;
                    494:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    495:                return 0;
                    496:        case 5:
                    497:                strlcpy(fp->name, AudioEslinear, sizeof fp->name);
                    498:                fp->encoding = AUDIO_ENCODING_SLINEAR;
                    499:                fp->precision = 8;
                    500:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    501:                return 0;
                    502:        case 6:
                    503:                strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
                    504:                fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    505:                fp->precision = 16;
                    506:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    507:                return 0;
                    508:        case 7:
                    509:                strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
                    510:                fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    511:                fp->precision = 16;
                    512:                fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    513:                return 0;
                    514:        default:
                    515:                return EINVAL;
                    516:        }
                    517: }
                    518:
                    519: /*
                    520:  * Range below -limit- is set to -rate-
                    521:  * What a pity FM801 does not have 24000
                    522:  * 24000 -> 22050 sounds rather poor
                    523:  */
                    524: struct {
                    525:        int limit;
                    526:        int rate;
                    527: } fms_rates[11] = {
                    528:        {  6600,  5500 },
                    529:        {  8750,  8000 },
                    530:        { 10250,  9600 },
                    531:        { 13200, 11025 },
                    532:        { 17500, 16000 },
                    533:        { 20500, 19200 },
                    534:        { 26500, 22050 },
                    535:        { 35000, 32000 },
                    536:        { 41000, 38400 },
                    537:        { 46000, 44100 },
                    538:        { 48000, 48000 },
                    539:        /* anything above -> 48000 */
                    540: };
                    541:
                    542: int
                    543: fms_set_params(addr, setmode, usemode, play, rec)
                    544:        void *addr;
                    545:        int setmode, usemode;
                    546:        struct audio_params *play, *rec;
                    547: {
                    548:        struct fms_softc *sc = addr;
                    549:        int i;
                    550:
                    551:        if (setmode & AUMODE_PLAY) {
                    552:                play->factor = 1;
                    553:                play->sw_code = 0;
                    554:                switch(play->encoding) {
                    555:                case AUDIO_ENCODING_ULAW:
                    556:                        play->factor = 2;
                    557:                        play->sw_code = mulaw_to_slinear16_le;
                    558:                        break;
                    559:                case AUDIO_ENCODING_SLINEAR_LE:
                    560:                        if (play->precision == 8)
                    561:                                play->sw_code = change_sign8;
                    562:                        break;
                    563:                case AUDIO_ENCODING_ULINEAR_LE:
                    564:                        if (play->precision == 16)
                    565:                                play->sw_code = change_sign16_le;
                    566:                        break;
                    567:                case AUDIO_ENCODING_ALAW:
                    568:                        play->factor = 2;
                    569:                        play->sw_code = alaw_to_slinear16_le;
                    570:                        break;
                    571:                case AUDIO_ENCODING_SLINEAR_BE:
                    572:                        if (play->precision == 16)
                    573:                                play->sw_code = swap_bytes;
                    574:                        else
                    575:                                play->sw_code = change_sign8;
                    576:                        break;
                    577:                case AUDIO_ENCODING_ULINEAR_BE:
                    578:                        if (play->precision == 16)
                    579:                                play->sw_code = change_sign16_swap_bytes_le;
                    580:                        break;
                    581:                default:
                    582:                        return EINVAL;
                    583:                }
                    584:                for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
                    585:                     i++)
                    586:                        ;
                    587:                play->sample_rate = fms_rates[i].rate;
                    588:                sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
                    589:                    (play->precision * play->factor == 16 ? FM_PLAY_16BIT : 0) |
                    590:                    (i << 8);
                    591:        }
                    592:
                    593:        if (setmode & AUMODE_RECORD) {
                    594:
                    595:                rec->factor = 1;
                    596:                rec->sw_code = 0;
                    597:                switch(rec->encoding) {
                    598:                case AUDIO_ENCODING_ULAW:
                    599:                        rec->sw_code = ulinear8_to_mulaw;
                    600:                        break;
                    601:                case AUDIO_ENCODING_SLINEAR_LE:
                    602:                        if (rec->precision == 8)
                    603:                                rec->sw_code = change_sign8;
                    604:                        break;
                    605:                case AUDIO_ENCODING_ULINEAR_LE:
                    606:                        if (rec->precision == 16)
                    607:                                rec->sw_code = change_sign16_le;
                    608:                        break;
                    609:                case AUDIO_ENCODING_ALAW:
                    610:                        rec->sw_code = ulinear8_to_alaw;
                    611:                        break;
                    612:                case AUDIO_ENCODING_SLINEAR_BE:
                    613:                        if (play->precision == 16)
                    614:                                play->sw_code = swap_bytes;
                    615:                        else
                    616:                                play->sw_code = change_sign8;
                    617:                        break;
                    618:                case AUDIO_ENCODING_ULINEAR_BE:
                    619:                        if (play->precision == 16)
                    620:                                play->sw_code = swap_bytes_change_sign16_le;
                    621:                        break;
                    622:                default:
                    623:                        return EINVAL;
                    624:                }
                    625:                for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
                    626:                     i++)
                    627:                        ;
                    628:                rec->sample_rate = fms_rates[i].rate;
                    629:                sc->sc_rec_reg =
                    630:                    (rec->channels == 2 ? FM_REC_STEREO : 0) |
                    631:                    (rec->precision * rec->factor == 16 ? FM_REC_16BIT : 0) |
                    632:                    (i << 8);
                    633:        }
                    634:
                    635:        return 0;
                    636: }
                    637:
                    638: int
                    639: fms_round_blocksize(addr, blk)
                    640:        void *addr;
                    641:        int blk;
                    642: {
                    643:        return (blk + 0xf) & ~0xf;
                    644: }
                    645:
                    646: int
                    647: fms_halt_output(addr)
                    648:        void *addr;
                    649: {
                    650:        struct fms_softc *sc = addr;
                    651:        u_int16_t k1;
                    652:
                    653:        k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
                    654:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
                    655:                          (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
                    656:                          FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
                    657:
                    658:        return 0;
                    659: }
                    660:
                    661: int
                    662: fms_halt_input(addr)
                    663:        void *addr;
                    664: {
                    665:        struct fms_softc *sc = addr;
                    666:        u_int16_t k1;
                    667:
                    668:        k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
                    669:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
                    670:                          (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
                    671:                          FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
                    672:
                    673:        return 0;
                    674: }
                    675:
                    676: int
                    677: fms_getdev(addr, retp)
                    678:        void *addr;
                    679:        struct audio_device *retp;
                    680: {
                    681:        *retp = fms_device;
                    682:        return 0;
                    683: }
                    684:
                    685: int
                    686: fms_set_port(addr, cp)
                    687:        void *addr;
                    688:        mixer_ctrl_t *cp;
                    689: {
                    690:        struct fms_softc *sc = addr;
                    691:
                    692:        return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
                    693: }
                    694:
                    695: int
                    696: fms_get_port(addr, cp)
                    697:        void *addr;
                    698:        mixer_ctrl_t *cp;
                    699: {
                    700:        struct fms_softc *sc = addr;
                    701:
                    702:        return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
                    703: }
                    704:
                    705: void *
                    706: fms_malloc(addr, direction, size, pool, flags)
                    707:        void *addr;
                    708:        int direction;
                    709:        size_t size;
                    710:        int pool, flags;
                    711: {
                    712:        struct fms_softc *sc = addr;
                    713:        struct fms_dma *p;
                    714:        int error;
                    715:        int rseg;
                    716:
                    717:        p = malloc(sizeof(*p), pool, flags);
                    718:        if (!p)
                    719:                return 0;
                    720:
                    721:        p->size = size;
                    722:        if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1,
                    723:                                      &rseg, BUS_DMA_NOWAIT)) != 0) {
                    724:                printf("%s: unable to allocate dma, error = %d\n",
                    725:                       sc->sc_dev.dv_xname, error);
                    726:                goto fail_alloc;
                    727:        }
                    728:
                    729:        if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
                    730:                                    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
                    731:                printf("%s: unable to map dma, error = %d\n",
                    732:                       sc->sc_dev.dv_xname, error);
                    733:                goto fail_map;
                    734:        }
                    735:
                    736:        if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
                    737:                                       BUS_DMA_NOWAIT, &p->map)) != 0) {
                    738:                printf("%s: unable to create dma map, error = %d\n",
                    739:                       sc->sc_dev.dv_xname, error);
                    740:                goto fail_create;
                    741:        }
                    742:
                    743:        if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
                    744:                                     BUS_DMA_NOWAIT)) != 0) {
                    745:                printf("%s: unable to load dma map, error = %d\n",
                    746:                       sc->sc_dev.dv_xname, error);
                    747:                goto fail_load;
                    748:        }
                    749:
                    750:        p->next = sc->sc_dmas;
                    751:        sc->sc_dmas = p;
                    752:
                    753:        return p->addr;
                    754:
                    755:
                    756: fail_load:
                    757:        bus_dmamap_destroy(sc->sc_dmat, p->map);
                    758: fail_create:
                    759:        bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
                    760: fail_map:
                    761:        bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
                    762: fail_alloc:
                    763:        free(p, pool);
                    764:        return 0;
                    765: }
                    766:
                    767: void
                    768: fms_free(addr, ptr, pool)
                    769:        void *addr;
                    770:        void *ptr;
                    771:        int pool;
                    772: {
                    773:        struct fms_softc *sc = addr;
                    774:        struct fms_dma **pp, *p;
                    775:
                    776:        for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
                    777:                if (p->addr == ptr) {
                    778:                        bus_dmamap_unload(sc->sc_dmat, p->map);
                    779:                        bus_dmamap_destroy(sc->sc_dmat, p->map);
                    780:                        bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
                    781:                        bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
                    782:
                    783:                        *pp = p->next;
                    784:                        free(p, pool);
                    785:                        return;
                    786:                }
                    787:
                    788:        panic("fms_free: trying to free unallocated memory");
                    789: }
                    790:
                    791: paddr_t
                    792: fms_mappage(addr, mem, off, prot)
                    793:        void *addr;
                    794:        void *mem;
                    795:        off_t off;
                    796:        int prot;
                    797: {
                    798:        struct fms_softc *sc = addr;
                    799:        struct fms_dma *p;
                    800:
                    801:        if (off < 0)
                    802:                return -1;
                    803:
                    804:        for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
                    805:                ;
                    806:        if (!p)
                    807:                return -1;
                    808:
                    809:        return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
                    810:                               BUS_DMA_WAITOK);
                    811: }
                    812:
                    813: int
                    814: fms_get_props(addr)
                    815:        void *addr;
                    816: {
                    817:        return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
                    818:               AUDIO_PROP_FULLDUPLEX;
                    819: }
                    820:
                    821: int
                    822: fms_query_devinfo(addr, dip)
                    823:        void *addr;
                    824:        mixer_devinfo_t *dip;
                    825: {
                    826:        struct fms_softc *sc = addr;
                    827:
                    828:        return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
                    829: }
                    830:
                    831: int
                    832: fms_trigger_output(addr, start, end, blksize, intr, arg, param)
                    833:        void *addr;
                    834:        void *start, *end;
                    835:        int blksize;
                    836:        void (*intr)(void *);
                    837:        void *arg;
                    838:        struct audio_params *param;
                    839: {
                    840:        struct fms_softc *sc = addr;
                    841:        struct fms_dma *p;
                    842:
                    843:        sc->sc_pintr = intr;
                    844:        sc->sc_parg = arg;
                    845:
                    846:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
                    847:                ;
                    848:
                    849:        if (!p)
                    850:                panic("fms_trigger_output: request with bad start "
                    851:                      "address (%p)", start);
                    852:
                    853:        sc->sc_play_start = p->map->dm_segs[0].ds_addr;
                    854:        sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
                    855:        sc->sc_play_blksize = blksize;
                    856:        sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
                    857:        sc->sc_play_flip = 0;
                    858:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
                    859:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
                    860:                          sc->sc_play_start);
                    861:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
                    862:                          sc->sc_play_nextblk);
                    863:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
                    864:                          FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
                    865:        return 0;
                    866: }
                    867:
                    868:
                    869: int
                    870: fms_trigger_input(addr, start, end, blksize, intr, arg, param)
                    871:        void *addr;
                    872:        void *start, *end;
                    873:        int blksize;
                    874:        void (*intr)(void *);
                    875:        void *arg;
                    876:        struct audio_params *param;
                    877: {
                    878:        struct fms_softc *sc = addr;
                    879:        struct fms_dma *p;
                    880:
                    881:        sc->sc_rintr = intr;
                    882:        sc->sc_rarg = arg;
                    883:
                    884:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
                    885:                ;
                    886:
                    887:        if (!p)
                    888:                panic("fms_trigger_input: request with bad start "
                    889:                      "address (%p)", start);
                    890:
                    891:        sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
                    892:        sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
                    893:        sc->sc_rec_blksize = blksize;
                    894:        sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
                    895:        sc->sc_rec_flip = 0;
                    896:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
                    897:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
                    898:                          sc->sc_rec_start);
                    899:        bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
                    900:                          sc->sc_rec_nextblk);
                    901:        bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
                    902:                          FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
                    903:        return 0;
                    904: }
                    905:
                    906:

CVSweb