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

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

1.1     ! nbrk        1: /*     $OpenBSD: auich.c,v 1.64 2007/08/02 07:43:41 jakemsr Exp $      */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2000,2001 Michael Shalayeff
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            19:  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
        !            20:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            22:  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            24:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
        !            25:  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
        !            26:  * THE POSSIBILITY OF SUCH DAMAGE.
        !            27:  */
        !            28:
        !            29: /* #define     AUICH_DEBUG */
        !            30: /*
        !            31:  * AC'97 audio found on Intel 810/815/820/440MX chipsets.
        !            32:  *     http://developer.intel.com/design/chipsets/datashts/290655.htm
        !            33:  *     http://developer.intel.com/design/chipsets/manuals/298028.htm
        !            34:  *     http://www.intel.com/design/chipsets/datashts/290716.htm
        !            35:  *     http://www.intel.com/design/chipsets/datashts/290744.htm
        !            36:  */
        !            37:
        !            38: #include <sys/param.h>
        !            39: #include <sys/systm.h>
        !            40: #include <sys/kernel.h>
        !            41: #include <sys/malloc.h>
        !            42: #include <sys/device.h>
        !            43:
        !            44: #include <dev/pci/pcidevs.h>
        !            45: #include <dev/pci/pcivar.h>
        !            46:
        !            47: #include <sys/audioio.h>
        !            48: #include <dev/audio_if.h>
        !            49: #include <dev/mulaw.h>
        !            50: #include <dev/auconv.h>
        !            51:
        !            52: #include <machine/bus.h>
        !            53:
        !            54: #include <dev/ic/ac97.h>
        !            55:
        !            56: /* 12.1.10 NAMBAR - native audio mixer base address register */
        !            57: #define        AUICH_NAMBAR    0x10
        !            58: /* 12.1.11 NABMBAR - native audio bus mastering base address register */
        !            59: #define        AUICH_NABMBAR   0x14
        !            60: #define        AUICH_CFG       0x41
        !            61: #define        AUICH_CFG_IOSE  0x01
        !            62: /* ICH4/ICH5/ICH6/ICH7 native audio mixer BAR */
        !            63: #define        AUICH_MMBAR     0x18
        !            64: /* ICH4/ICH5/ICH6/ICH7 native bus mastering BAR */
        !            65: #define        AUICH_MBBAR     0x1c
        !            66: #define        AUICH_S2CR      0x10000000      /* tertiary codec ready */
        !            67:
        !            68: /* table 12-3. native audio bus master control registers */
        !            69: #define        AUICH_BDBAR     0x00    /* 8-byte aligned address */
        !            70: #define        AUICH_CIV               0x04    /* 5 bits current index value */
        !            71: #define        AUICH_LVI               0x05    /* 5 bits last valid index value */
        !            72: #define                AUICH_LVI_MASK  0x1f
        !            73: #define        AUICH_STS               0x06    /* 16 bits status */
        !            74: #define                AUICH_FIFOE     0x10    /* fifo error */
        !            75: #define                AUICH_BCIS      0x08    /* r- buf cmplt int sts; wr ack */
        !            76: #define                AUICH_LVBCI     0x04    /* r- last valid bci, wr ack */
        !            77: #define                AUICH_CELV      0x02    /* current equals last valid */
        !            78: #define                AUICH_DCH               0x01    /* dma halted */
        !            79: #define                AUICH_ISTS_BITS "\020\01dch\02celv\03lvbci\04bcis\05fifoe"
        !            80: #define        AUICH_PICB      0x08    /* 16 bits */
        !            81: #define        AUICH_PIV               0x0a    /* 5 bits prefetched index value */
        !            82: #define        AUICH_CTRL      0x0b    /* control */
        !            83: #define                AUICH_IOCE      0x10    /* int on completion enable */
        !            84: #define                AUICH_FEIE      0x08    /* fifo error int enable */
        !            85: #define                AUICH_LVBIE     0x04    /* last valid buf int enable */
        !            86: #define                AUICH_RR                0x02    /* 1 - reset regs */
        !            87: #define                AUICH_RPBM      0x01    /* 1 - run, 0 - pause */
        !            88:
        !            89: #define        AUICH_PCMI      0x00
        !            90: #define        AUICH_PCMO      0x10
        !            91: #define        AUICH_MICI      0x20
        !            92:
        !            93: #define        AUICH_GCTRL     0x2c
        !            94: #define                AUICH_SSM_78    0x40000000      /* S/PDIF slots 7 and 8 */
        !            95: #define                AUICH_SSM_69    0x80000000      /* S/PDIF slots 6 and 9 */
        !            96: #define                AUICH_SSM_1011  0xc0000000      /* S/PDIF slots 10 and 11 */
        !            97: #define                AUICH_POM16     0x000000        /* PCM out precision 16bit */
        !            98: #define                AUICH_POM20     0x400000        /* PCM out precision 20bit */
        !            99: #define                AUICH_PCM246_MASK 0x300000
        !           100: #define                AUICH_PCM2      0x000000        /* 2ch output */
        !           101: #define                AUICH_PCM4      0x100000        /* 4ch output */
        !           102: #define                AUICH_PCM6      0x200000        /* 6ch output */
        !           103: #define                AUICH_S2RIE     0x40    /* int when tertiary codec resume */
        !           104: #define                AUICH_SRIE      0x20    /* int when 2ndary codec resume */
        !           105: #define                AUICH_PRIE      0x10    /* int when primary codec resume */
        !           106: #define                AUICH_ACLSO     0x08    /* aclink shut off */
        !           107: #define                AUICH_WRESET    0x04    /* warm reset */
        !           108: #define                AUICH_CRESET    0x02    /* cold reset */
        !           109: #define                AUICH_GIE               0x01    /* gpi int enable */
        !           110: #define        AUICH_GSTS      0x30
        !           111: #define                AUICH_MD3               0x20000 /* pwr-dn semaphore for modem */
        !           112: #define                AUICH_AD3               0x10000 /* pwr-dn semaphore for audio */
        !           113: #define                AUICH_RCS               0x08000 /* read completion status */
        !           114: #define                AUICH_B3S12     0x04000 /* bit 3 of slot 12 */
        !           115: #define                AUICH_B2S12     0x02000 /* bit 2 of slot 12 */
        !           116: #define                AUICH_B1S12     0x01000 /* bit 1 of slot 12 */
        !           117: #define                AUICH_SRI               0x00800 /* secondary resume int */
        !           118: #define                AUICH_PRI               0x00400 /* primary resume int */
        !           119: #define                AUICH_SCR               0x00200 /* secondary codec ready */
        !           120: #define                AUICH_PCR               0x00100 /* primary codec ready */
        !           121: #define                AUICH_MINT      0x00080 /* mic in int */
        !           122: #define                AUICH_POINT     0x00040 /* pcm out int */
        !           123: #define                AUICH_PIINT     0x00020 /* pcm in int */
        !           124: #define                AUICH_MOINT     0x00004 /* modem out int */
        !           125: #define                AUICH_MIINT     0x00002 /* modem in int */
        !           126: #define                AUICH_GSCI      0x00001 /* gpi status change */
        !           127: #define                AUICH_GSTS_BITS "\020\01gsci\02miict\03moint\06piint\07point\010mint\011pcr\012scr\013pri\014sri\015b1s12\016b2s12\017b3s12\020rcs\021ad3\022md3"
        !           128: #define        AUICH_CAS               0x34    /* 1/8 bit */
        !           129: #define        AUICH_SEMATIMO          1000    /* us */
        !           130: #define        AUICH_RESETIMO          500000  /* us */
        !           131:
        !           132: #define        ICH_SIS_NV_CTL  0x4c    /* some SiS/NVIDIA register.  From Linux */
        !           133: #define                ICH_SIS_CTL_UNMUTE      0x01    /* un-mute the output */
        !           134:
        !           135: /*
        !           136:  * according to the dev/audiovar.h AU_RING_SIZE is 2^16, what fits
        !           137:  * in our limits perfectly, i.e. setting it to higher value
        !           138:  * in your kernel config would improve perfomance, still 2^21 is the max
        !           139:  */
        !           140: #define        AUICH_DMALIST_MAX       32
        !           141: #define        AUICH_DMASEG_MAX        (65536*2)       /* 64k samples, 2x16 bit samples */
        !           142: struct auich_dmalist {
        !           143:        u_int32_t       base;
        !           144:        u_int32_t       len;
        !           145: #define        AUICH_DMAF_IOC  0x80000000      /* 1-int on complete */
        !           146: #define        AUICH_DMAF_BUP  0x40000000      /* 0-retrans last, 1-transmit 0 */
        !           147: };
        !           148:
        !           149: #define        AUICH_FIXED_RATE 48000
        !           150:
        !           151: struct auich_dma {
        !           152:        bus_dmamap_t map;
        !           153:        caddr_t addr;
        !           154:        bus_dma_segment_t segs[AUICH_DMALIST_MAX];
        !           155:        int nsegs;
        !           156:        size_t size;
        !           157:        struct auich_dma *next;
        !           158: };
        !           159:
        !           160: struct auich_softc {
        !           161:        struct device sc_dev;
        !           162:        void *sc_ih;
        !           163:
        !           164:        audio_device_t sc_audev;
        !           165:
        !           166:        bus_space_tag_t iot;
        !           167:        bus_space_tag_t iot_mix;
        !           168:        bus_space_handle_t mix_ioh;
        !           169:        bus_space_handle_t aud_ioh;
        !           170:        bus_dma_tag_t dmat;
        !           171:
        !           172:        struct ac97_codec_if *codec_if;
        !           173:        struct ac97_host_if host_if;
        !           174:
        !           175:        /* dma scatter-gather buffer lists, aligned to 8 bytes */
        !           176:        struct auich_dmalist *dmalist_pcmo, *dmap_pcmo;
        !           177:        struct auich_dmalist *dmalist_pcmi, *dmap_pcmi;
        !           178:        struct auich_dmalist *dmalist_mici, *dmap_mici;
        !           179:
        !           180:        bus_dmamap_t dmalist_map;
        !           181:        bus_dma_segment_t dmalist_seg[2];
        !           182:        caddr_t dmalist_kva;
        !           183:        bus_addr_t dmalist_pcmo_pa;
        !           184:        bus_addr_t dmalist_pcmi_pa;
        !           185:        bus_addr_t dmalist_mici_pa;
        !           186:
        !           187:        /* i/o buffer pointers */
        !           188:        u_int32_t pcmo_start, pcmo_p, pcmo_end;
        !           189:        int pcmo_blksize, pcmo_fifoe;
        !           190:        u_int32_t pcmi_start, pcmi_p, pcmi_end;
        !           191:        int pcmi_blksize, pcmi_fifoe;
        !           192:        u_int32_t mici_start, mici_p, mici_end;
        !           193:        int mici_blksize, mici_fifoe;
        !           194:        struct auich_dma *sc_dmas;
        !           195:
        !           196:        void (*sc_pintr)(void *);
        !           197:        void *sc_parg;
        !           198:
        !           199:        void (*sc_rintr)(void *);
        !           200:        void *sc_rarg;
        !           201:
        !           202:        void *powerhook;
        !           203:        int suspend;
        !           204:        u_int16_t ext_ctrl;
        !           205:        int sc_sample_size;
        !           206:        int sc_sts_reg;
        !           207:        int sc_ignore_codecready;
        !           208:        int flags;
        !           209:        int sc_ac97rate;
        !           210: };
        !           211:
        !           212: #ifdef AUICH_DEBUG
        !           213: #define        DPRINTF(l,x)    do { if (auich_debug & (l)) printf x; } while(0)
        !           214: int auich_debug = 0xfffe;
        !           215: #define        AUICH_DEBUG_CODECIO     0x0001
        !           216: #define        AUICH_DEBUG_DMA         0x0002
        !           217: #define        AUICH_DEBUG_PARAM       0x0004
        !           218: #else
        !           219: #define        DPRINTF(x,y)    /* nothing */
        !           220: #endif
        !           221:
        !           222: struct cfdriver        auich_cd = {
        !           223:        NULL, "auich", DV_DULL
        !           224: };
        !           225:
        !           226: int  auich_match(struct device *, void *, void *);
        !           227: void auich_attach(struct device *, struct device *, void *);
        !           228: int  auich_intr(void *);
        !           229:
        !           230: struct cfattach auich_ca = {
        !           231:        sizeof(struct auich_softc), auich_match, auich_attach
        !           232: };
        !           233:
        !           234: static const struct auich_devtype {
        !           235:        int     vendor;
        !           236:        int     product;
        !           237:        int     options;
        !           238:        char    name[8];
        !           239: } auich_devices[] = {
        !           240:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_6300ESB_ACA,  0, "ESB" },
        !           241:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_6321ESB_ACA,  0, "ESB2" },
        !           242:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801AA_ACA,  0, "ICH" },
        !           243:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801AB_ACA,  0, "ICH0" },
        !           244:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801BA_ACA,  0, "ICH2" },
        !           245:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801CA_ACA,  0, "ICH3" },
        !           246:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801DB_ACA,  0, "ICH4" },
        !           247:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801EB_ACA,  0, "ICH5" },
        !           248:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801FB_ACA,  0, "ICH6" },
        !           249:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82801GB_ACA,  0, "ICH7" },
        !           250:        { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82440MX_ACA,  0, "440MX" },
        !           251:        { PCI_VENDOR_SIS,       PCI_PRODUCT_SIS_7012_ACA,       0, "SiS7012" },
        !           252:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE_ACA,  0, "nForce" },
        !           253:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE2_ACA, 0, "nForce2" },
        !           254:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE2_400_ACA,
        !           255:            0, "nForce2" },
        !           256:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE3_ACA, 0, "nForce3" },
        !           257:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE3_250_ACA,
        !           258:            0, "nForce3" },
        !           259:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_NFORCE4_AC,  0, "nForce4" },
        !           260:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_MCP04_AC97,  0, "MCP04" },
        !           261:        { PCI_VENDOR_NVIDIA,    PCI_PRODUCT_NVIDIA_MCP51_ACA,   0, "MCP51" },
        !           262:        { PCI_VENDOR_AMD,       PCI_PRODUCT_AMD_PBC768_ACA,     0, "AMD768" },
        !           263:        { PCI_VENDOR_AMD,       PCI_PRODUCT_AMD_8111_ACA,       0, "AMD8111" },
        !           264: };
        !           265:
        !           266: int auich_open(void *, int);
        !           267: void auich_close(void *);
        !           268: int auich_query_encoding(void *, struct audio_encoding *);
        !           269: int auich_set_params(void *, int, int, struct audio_params *,
        !           270:     struct audio_params *);
        !           271: int auich_round_blocksize(void *, int);
        !           272: int auich_halt_output(void *);
        !           273: int auich_halt_input(void *);
        !           274: int auich_getdev(void *, struct audio_device *);
        !           275: int auich_set_port(void *, mixer_ctrl_t *);
        !           276: int auich_get_port(void *, mixer_ctrl_t *);
        !           277: int auich_query_devinfo(void *, mixer_devinfo_t *);
        !           278: void *auich_allocm(void *, int, size_t, int, int);
        !           279: void auich_freem(void *, void *, int);
        !           280: size_t auich_round_buffersize(void *, int, size_t);
        !           281: paddr_t auich_mappage(void *, void *, off_t, int);
        !           282: int auich_get_props(void *);
        !           283: int auich_trigger_output(void *, void *, void *, int, void (*)(void *),
        !           284:     void *, struct audio_params *);
        !           285: int auich_trigger_input(void *, void *, void *, int, void (*)(void *),
        !           286:     void *, struct audio_params *);
        !           287:
        !           288: void auich_powerhook(int, void *);
        !           289:
        !           290: struct audio_hw_if auich_hw_if = {
        !           291:        auich_open,
        !           292:        auich_close,
        !           293:        NULL,                   /* drain */
        !           294:        auich_query_encoding,
        !           295:        auich_set_params,
        !           296:        auich_round_blocksize,
        !           297:        NULL,                   /* commit_setting */
        !           298:        NULL,                   /* init_output */
        !           299:        NULL,                   /* init_input */
        !           300:        NULL,                   /* start_output */
        !           301:        NULL,                   /* start_input */
        !           302:        auich_halt_output,
        !           303:        auich_halt_input,
        !           304:        NULL,                   /* speaker_ctl */
        !           305:        auich_getdev,
        !           306:        NULL,                   /* getfd */
        !           307:        auich_set_port,
        !           308:        auich_get_port,
        !           309:        auich_query_devinfo,
        !           310:        auich_allocm,
        !           311:        auich_freem,
        !           312:        auich_round_buffersize,
        !           313:        auich_mappage,
        !           314:        auich_get_props,
        !           315:        auich_trigger_output,
        !           316:        auich_trigger_input
        !           317: };
        !           318:
        !           319: int  auich_attach_codec(void *, struct ac97_codec_if *);
        !           320: int  auich_read_codec(void *, u_int8_t, u_int16_t *);
        !           321: int  auich_write_codec(void *, u_int8_t, u_int16_t);
        !           322: void auich_reset_codec(void *);
        !           323: enum ac97_host_flags auich_flags_codec(void *);
        !           324: unsigned int auich_calibrate(struct auich_softc *);
        !           325:
        !           326: int
        !           327: auich_match(parent, match, aux)
        !           328:        struct device *parent;
        !           329:        void *match;
        !           330:        void *aux;
        !           331: {
        !           332:        struct pci_attach_args *pa = aux;
        !           333:        int i;
        !           334:
        !           335:        for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
        !           336:                if (PCI_VENDOR(pa->pa_id) == auich_devices[i].vendor &&
        !           337:                    PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
        !           338:                        return 1;
        !           339:
        !           340:        return 0;
        !           341: }
        !           342:
        !           343: void
        !           344: auich_attach(parent, self, aux)
        !           345:        struct device *parent, *self;
        !           346:        void *aux;
        !           347: {
        !           348:        struct auich_softc *sc = (struct auich_softc *)self;
        !           349:        struct pci_attach_args *pa = aux;
        !           350:        pci_intr_handle_t ih;
        !           351:        bus_size_t mix_size, aud_size;
        !           352:        pcireg_t csr;
        !           353:        const char *intrstr;
        !           354:        u_int32_t status;
        !           355:        bus_size_t dmasz;
        !           356:        int i, segs;
        !           357:
        !           358:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
        !           359:            (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ACA ||
        !           360:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801EB_ACA ||
        !           361:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801FB_ACA ||
        !           362:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801GB_ACA)) {
        !           363:                /*
        !           364:                 * Use native mode for ICH4/ICH5/ICH6/ICH7
        !           365:                 */
        !           366:                if (pci_mapreg_map(pa, AUICH_MMBAR, PCI_MAPREG_TYPE_MEM, 0,
        !           367:                    &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
        !           368:                        csr = pci_conf_read(pa->pa_pc, pa->pa_tag, AUICH_CFG);
        !           369:                        pci_conf_write(pa->pa_pc, pa->pa_tag, AUICH_CFG,
        !           370:                            csr | AUICH_CFG_IOSE);
        !           371:                        if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO,
        !           372:                            0, &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
        !           373:                                printf(": can't map codec mem/io space\n");
        !           374:                                return;
        !           375:                        }
        !           376:                }
        !           377:
        !           378:                if (pci_mapreg_map(pa, AUICH_MBBAR, PCI_MAPREG_TYPE_MEM, 0,
        !           379:                    &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
        !           380:                        csr = pci_conf_read(pa->pa_pc, pa->pa_tag, AUICH_CFG);
        !           381:                        pci_conf_write(pa->pa_pc, pa->pa_tag, AUICH_CFG,
        !           382:                            csr | AUICH_CFG_IOSE);
        !           383:                        if (pci_mapreg_map(pa, AUICH_NABMBAR,
        !           384:                            PCI_MAPREG_TYPE_IO, 0, &sc->iot,
        !           385:                            &sc->aud_ioh, NULL, &aud_size, 0)) {
        !           386:                                printf(": can't map device mem/io space\n");
        !           387:                                bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
        !           388:                                return;
        !           389:                        }
        !           390:                }
        !           391:        } else {
        !           392:                if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO,
        !           393:                    0, &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
        !           394:                        printf(": can't map codec i/o space\n");
        !           395:                        return;
        !           396:                }
        !           397:
        !           398:                if (pci_mapreg_map(pa, AUICH_NABMBAR, PCI_MAPREG_TYPE_IO,
        !           399:                    0, &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
        !           400:                        printf(": can't map device i/o space\n");
        !           401:                        bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
        !           402:                        return;
        !           403:                }
        !           404:        }
        !           405:        sc->dmat = pa->pa_dmat;
        !           406:
        !           407:        /* allocate dma memory */
        !           408:        dmasz = AUICH_DMALIST_MAX * 3 * sizeof(struct auich_dma);
        !           409:        segs = 1;
        !           410:        if (bus_dmamem_alloc(sc->dmat, dmasz, PAGE_SIZE, 0, sc->dmalist_seg,
        !           411:            segs, &segs, BUS_DMA_NOWAIT)) {
        !           412:                printf(": failed to alloc dmalist\n");
        !           413:                return;
        !           414:        }
        !           415:        if (bus_dmamem_map(sc->dmat, sc->dmalist_seg, segs, dmasz,
        !           416:            &sc->dmalist_kva, BUS_DMA_NOWAIT)) {
        !           417:                printf(": failed to map dmalist\n");
        !           418:                bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
        !           419:                return;
        !           420:        }
        !           421:        if (bus_dmamap_create(sc->dmat, dmasz, segs, dmasz, 0, BUS_DMA_NOWAIT,
        !           422:            &sc->dmalist_map)) {
        !           423:                printf(": failed to create dmalist map\n");
        !           424:                bus_dmamem_unmap(sc->dmat, sc->dmalist_kva, dmasz);
        !           425:                bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
        !           426:                return;
        !           427:        }
        !           428:        if (bus_dmamap_load_raw(sc->dmat, sc->dmalist_map, sc->dmalist_seg,
        !           429:            segs, dmasz, BUS_DMA_NOWAIT)) {
        !           430:                printf(": failed to load dmalist map: %d segs %lu size\n",
        !           431:                    segs, (u_long)dmasz);
        !           432:                bus_dmamap_destroy(sc->dmat, sc->dmalist_map);
        !           433:                bus_dmamem_unmap(sc->dmat, sc->dmalist_kva, dmasz);
        !           434:                bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
        !           435:                return;
        !           436:        }
        !           437:
        !           438:        if (pci_intr_map(pa, &ih)) {
        !           439:                bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
        !           440:                bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
        !           441:                return;
        !           442:        }
        !           443:        intrstr = pci_intr_string(pa->pa_pc, ih);
        !           444:        sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auich_intr,
        !           445:                                       sc, sc->sc_dev.dv_xname);
        !           446:        if (!sc->sc_ih) {
        !           447:                printf(": can't establish interrupt");
        !           448:                if (intrstr)
        !           449:                        printf(" at %s", intrstr);
        !           450:                printf("\n");
        !           451:                bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
        !           452:                bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
        !           453:                return;
        !           454:        }
        !           455:
        !           456:        for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
        !           457:                if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
        !           458:                        break;
        !           459:
        !           460:        snprintf(sc->sc_audev.name, sizeof sc->sc_audev.name, "%s AC97",
        !           461:                 auich_devices[i].name);
        !           462:        snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
        !           463:                 PCI_REVISION(pa->pa_class));
        !           464:        strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
        !           465:                sizeof sc->sc_audev.config);
        !           466:
        !           467:        printf(": %s, %s\n", intrstr, sc->sc_audev.name);
        !           468:
        !           469:        /* SiS 7012 needs special handling */
        !           470:        if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS &&
        !           471:            PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_7012_ACA) {
        !           472:                sc->sc_sts_reg = AUICH_PICB;
        !           473:                sc->sc_sample_size = 1;
        !           474:                /* un-mute output */
        !           475:                bus_space_write_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL,
        !           476:                    bus_space_read_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL) |
        !           477:                    ICH_SIS_CTL_UNMUTE);
        !           478:        } else {
        !           479:                sc->sc_sts_reg = AUICH_STS;
        !           480:                sc->sc_sample_size = 2;
        !           481:        }
        !           482:
        !           483:        sc->dmalist_pcmo = (struct auich_dmalist *)(sc->dmalist_kva +
        !           484:            (0 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
        !           485:        sc->dmalist_pcmo_pa = sc->dmalist_map->dm_segs[0].ds_addr +
        !           486:            (0 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
        !           487:
        !           488:        sc->dmalist_pcmi = (struct auich_dmalist *)(sc->dmalist_kva +
        !           489:            (1 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
        !           490:        sc->dmalist_pcmi_pa = sc->dmalist_map->dm_segs[0].ds_addr +
        !           491:            (1 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
        !           492:
        !           493:        sc->dmalist_mici = (struct auich_dmalist *)(sc->dmalist_kva +
        !           494:            (2 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
        !           495:        sc->dmalist_mici_pa = sc->dmalist_map->dm_segs[0].ds_addr +
        !           496:            (2 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
        !           497:
        !           498:        DPRINTF(AUICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n",
        !           499:            sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici));
        !           500:
        !           501:        /* Reset codec and AC'97 */
        !           502:        auich_reset_codec(sc);
        !           503:        status = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS);
        !           504:        if (!(status & AUICH_PCR)) {    /* reset failure */
        !           505:                if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
        !           506:                    (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ACA ||
        !           507:                     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801EB_ACA ||
        !           508:                     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801FB_ACA ||
        !           509:                     PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801GB_ACA)) {
        !           510:                        /* MSI 845G Max never return AUICH_PCR */
        !           511:                        sc->sc_ignore_codecready = 1;
        !           512:                } else {
        !           513:                        printf("%s: reset failed!\n", sc->sc_dev.dv_xname);
        !           514:                        return;
        !           515:                }
        !           516:        }
        !           517:
        !           518:        sc->host_if.arg = sc;
        !           519:        sc->host_if.attach = auich_attach_codec;
        !           520:        sc->host_if.read = auich_read_codec;
        !           521:        sc->host_if.write = auich_write_codec;
        !           522:        sc->host_if.reset = auich_reset_codec;
        !           523:        sc->host_if.flags = auich_flags_codec;
        !           524:        if (sc->sc_dev.dv_cfdata->cf_flags & 0x0001)
        !           525:                sc->flags = AC97_HOST_SWAPPED_CHANNELS;
        !           526:
        !           527:        if (ac97_attach(&sc->host_if) != 0) {
        !           528:                pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
        !           529:                bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
        !           530:                bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
        !           531:                return;
        !           532:        }
        !           533:
        !           534:        audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
        !           535:
        !           536:        /* Watch for power changes */
        !           537:        sc->suspend = PWR_RESUME;
        !           538:        sc->powerhook = powerhook_establish(auich_powerhook, sc);
        !           539:
        !           540:        sc->sc_ac97rate = -1;
        !           541: }
        !           542:
        !           543: int
        !           544: auich_read_codec(v, reg, val)
        !           545:        void *v;
        !           546:        u_int8_t reg;
        !           547:        u_int16_t *val;
        !           548: {
        !           549:        struct auich_softc *sc = v;
        !           550:        int i;
        !           551:
        !           552:        /* wait for an access semaphore */
        !           553:        for (i = AUICH_SEMATIMO; i-- &&
        !           554:            bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
        !           555:
        !           556:        if (!sc->sc_ignore_codecready && i < 0) {
        !           557:                DPRINTF(AUICH_DEBUG_CODECIO,
        !           558:                    ("%s: read_codec timeout\n", sc->sc_dev.dv_xname));
        !           559:                return (-1);
        !           560:        }
        !           561:
        !           562:        *val = bus_space_read_2(sc->iot_mix, sc->mix_ioh, reg);
        !           563:        DPRINTF(AUICH_DEBUG_CODECIO, ("%s: read_codec(%x, %x)\n",
        !           564:            sc->sc_dev.dv_xname, reg, *val));
        !           565:        return (0);
        !           566: }
        !           567:
        !           568: int
        !           569: auich_write_codec(v, reg, val)
        !           570:        void *v;
        !           571:        u_int8_t reg;
        !           572:        u_int16_t val;
        !           573: {
        !           574:        struct auich_softc *sc = v;
        !           575:        int i;
        !           576:
        !           577:        /* wait for an access semaphore */
        !           578:        for (i = AUICH_SEMATIMO; i-- &&
        !           579:            bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
        !           580:
        !           581:        if (sc->sc_ignore_codecready || i >= 0) {
        !           582:                DPRINTF(AUICH_DEBUG_CODECIO, ("%s: write_codec(%x, %x)\n",
        !           583:                    sc->sc_dev.dv_xname, reg, val));
        !           584:                bus_space_write_2(sc->iot_mix, sc->mix_ioh, reg, val);
        !           585:                return (0);
        !           586:        } else {
        !           587:                DPRINTF(AUICH_DEBUG_CODECIO,
        !           588:                    ("%s: write_codec timeout\n", sc->sc_dev.dv_xname));
        !           589:                return (-1);
        !           590:        }
        !           591: }
        !           592:
        !           593: int
        !           594: auich_attach_codec(v, cif)
        !           595:        void *v;
        !           596:        struct ac97_codec_if *cif;
        !           597: {
        !           598:        struct auich_softc *sc = v;
        !           599:
        !           600:        sc->codec_if = cif;
        !           601:        return 0;
        !           602: }
        !           603:
        !           604: void
        !           605: auich_reset_codec(v)
        !           606:        void *v;
        !           607: {
        !           608:        struct auich_softc *sc = v;
        !           609:        u_int32_t control;
        !           610:        int i;
        !           611:
        !           612:        control = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GCTRL);
        !           613:        control &= ~(AUICH_ACLSO | AUICH_PCM246_MASK);
        !           614:        control |= (control & AUICH_CRESET) ? AUICH_WRESET : AUICH_CRESET;
        !           615:        bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_GCTRL, control);
        !           616:
        !           617:        for (i = AUICH_RESETIMO; i-- &&
        !           618:            !(bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS) & AUICH_PCR);
        !           619:            DELAY(1));
        !           620:
        !           621:        if (i < 0)
        !           622:                DPRINTF(AUICH_DEBUG_CODECIO,
        !           623:                    ("%s: reset_codec timeout\n", sc->sc_dev.dv_xname));
        !           624: }
        !           625:
        !           626: enum ac97_host_flags
        !           627: auich_flags_codec(void *v)
        !           628: {
        !           629:        struct auich_softc *sc = v;
        !           630:
        !           631:        return (sc->flags);
        !           632: }
        !           633:
        !           634: int
        !           635: auich_open(v, flags)
        !           636:        void *v;
        !           637:        int flags;
        !           638: {
        !           639:        struct auich_softc *sc = v;
        !           640:
        !           641:        if (sc->sc_ac97rate == -1)
        !           642:                sc->sc_ac97rate = auich_calibrate(sc);
        !           643:        return 0;
        !           644: }
        !           645:
        !           646: void
        !           647: auich_close(v)
        !           648:        void *v;
        !           649: {
        !           650: }
        !           651:
        !           652: int
        !           653: auich_query_encoding(v, aep)
        !           654:        void *v;
        !           655:        struct audio_encoding *aep;
        !           656: {
        !           657:        switch (aep->index) {
        !           658:        case 0:
        !           659:                strlcpy(aep->name, AudioEulinear, sizeof aep->name);
        !           660:                aep->encoding = AUDIO_ENCODING_ULINEAR;
        !           661:                aep->precision = 8;
        !           662:                aep->flags = 0;
        !           663:                return (0);
        !           664:        case 1:
        !           665:                strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
        !           666:                aep->encoding = AUDIO_ENCODING_ULAW;
        !           667:                aep->precision = 8;
        !           668:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           669:                return (0);
        !           670:        case 2:
        !           671:                strlcpy(aep->name, AudioEalaw, sizeof aep->name);
        !           672:                aep->encoding = AUDIO_ENCODING_ALAW;
        !           673:                aep->precision = 8;
        !           674:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           675:                return (0);
        !           676:        case 3:
        !           677:                strlcpy(aep->name, AudioEslinear, sizeof aep->name);
        !           678:                aep->encoding = AUDIO_ENCODING_SLINEAR;
        !           679:                aep->precision = 8;
        !           680:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           681:                return (0);
        !           682:        case 4:
        !           683:                strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
        !           684:                aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
        !           685:                aep->precision = 16;
        !           686:                aep->flags = 0;
        !           687:                return (0);
        !           688:        case 5:
        !           689:                strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
        !           690:                aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
        !           691:                aep->precision = 16;
        !           692:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           693:                return (0);
        !           694:        case 6:
        !           695:                strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
        !           696:                aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
        !           697:                aep->precision = 16;
        !           698:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           699:                return (0);
        !           700:        case 7:
        !           701:                strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
        !           702:                aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
        !           703:                aep->precision = 16;
        !           704:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
        !           705:                return (0);
        !           706:        default:
        !           707:                return (EINVAL);
        !           708:        }
        !           709: }
        !           710:
        !           711: int
        !           712: auich_set_params(v, setmode, usemode, play, rec)
        !           713:        void *v;
        !           714:        int setmode, usemode;
        !           715:        struct audio_params *play, *rec;
        !           716: {
        !           717:        struct auich_softc *sc = v;
        !           718:        int error;
        !           719:        u_int orate;
        !           720:        u_int adj_rate;
        !           721:
        !           722:        if (setmode & AUMODE_PLAY) {
        !           723:                play->factor = 1;
        !           724:                play->sw_code = NULL;
        !           725:                switch(play->encoding) {
        !           726:                case AUDIO_ENCODING_ULAW:
        !           727:                        switch (play->channels) {
        !           728:                        case 1:
        !           729:                                play->factor = 4;
        !           730:                                play->sw_code = mulaw_to_slinear16_mts;
        !           731:                                break;
        !           732:                        case 2:
        !           733:                                play->factor = 2;
        !           734:                                play->sw_code = mulaw_to_slinear16;
        !           735:                                break;
        !           736:                        default:
        !           737:                                return (EINVAL);
        !           738:                        }
        !           739:                        break;
        !           740:                case AUDIO_ENCODING_SLINEAR_LE:
        !           741:                        switch (play->precision) {
        !           742:                        case 8:
        !           743:                                switch (play->channels) {
        !           744:                                case 1:
        !           745:                                        play->factor = 4;
        !           746:                                        play->sw_code = linear8_to_linear16_mts;
        !           747:                                        break;
        !           748:                                case 2:
        !           749:                                        play->factor = 2;
        !           750:                                        play->sw_code = linear8_to_linear16;
        !           751:                                        break;
        !           752:                                default:
        !           753:                                        return (EINVAL);
        !           754:                                }
        !           755:                                break;
        !           756:                        case 16:
        !           757:                                switch (play->channels) {
        !           758:                                case 1:
        !           759:                                        play->factor = 2;
        !           760:                                        play->sw_code = noswap_bytes_mts;
        !           761:                                        break;
        !           762:                                case 2:
        !           763:                                        break;
        !           764:                                default:
        !           765:                                        return (EINVAL);
        !           766:                                }
        !           767:                                break;
        !           768:                        default:
        !           769:                                return (EINVAL);
        !           770:                        }
        !           771:                        break;
        !           772:                case AUDIO_ENCODING_ULINEAR_LE:
        !           773:                        switch (play->precision) {
        !           774:                        case 8:
        !           775:                                switch (play->channels) {
        !           776:                                case 1:
        !           777:                                        play->factor = 4;
        !           778:                                        play->sw_code = ulinear8_to_linear16_mts;
        !           779:                                        break;
        !           780:                                case 2:
        !           781:                                        play->factor = 2;
        !           782:                                        play->sw_code = ulinear8_to_linear16;
        !           783:                                        break;
        !           784:                                default:
        !           785:                                        return (EINVAL);
        !           786:                                }
        !           787:                                break;
        !           788:                        case 16:
        !           789:                                switch (play->channels) {
        !           790:                                case 1:
        !           791:                                        play->factor = 2;
        !           792:                                        play->sw_code = change_sign16_mts;
        !           793:                                        break;
        !           794:                                case 2:
        !           795:                                        play->sw_code = change_sign16;
        !           796:                                        break;
        !           797:                                default:
        !           798:                                        return (EINVAL);
        !           799:                                }
        !           800:                                break;
        !           801:                        default:
        !           802:                                return (EINVAL);
        !           803:                        }
        !           804:                        break;
        !           805:                case AUDIO_ENCODING_ALAW:
        !           806:                        switch (play->channels) {
        !           807:                        case 1:
        !           808:                                play->factor = 4;
        !           809:                                play->sw_code = alaw_to_slinear16_mts;
        !           810:                                break;
        !           811:                        case 2:
        !           812:                                play->factor = 2;
        !           813:                                play->sw_code = alaw_to_slinear16;
        !           814:                                break;
        !           815:                        default:
        !           816:                                return (EINVAL);
        !           817:                        }
        !           818:                        break;
        !           819:                case AUDIO_ENCODING_SLINEAR_BE:
        !           820:                        switch (play->precision) {
        !           821:                        case 8:
        !           822:                                switch (play->channels) {
        !           823:                                case 1:
        !           824:                                        play->factor = 4;
        !           825:                                        play->sw_code = linear8_to_linear16_mts;
        !           826:                                        break;
        !           827:                                case 2:
        !           828:                                        play->factor = 2;
        !           829:                                        play->sw_code = linear8_to_linear16;
        !           830:                                        break;
        !           831:                                default:
        !           832:                                        return (EINVAL);
        !           833:                                }
        !           834:                                break;
        !           835:                        case 16:
        !           836:                                switch (play->channels) {
        !           837:                                case 1:
        !           838:                                        play->factor = 2;
        !           839:                                        play->sw_code = swap_bytes_mts;
        !           840:                                        break;
        !           841:                                case 2:
        !           842:                                        play->sw_code = swap_bytes;
        !           843:                                        break;
        !           844:                                default:
        !           845:                                        return (EINVAL);
        !           846:                                }
        !           847:                                break;
        !           848:                        default:
        !           849:                                return (EINVAL);
        !           850:                        }
        !           851:                        break;
        !           852:                case AUDIO_ENCODING_ULINEAR_BE:
        !           853:                        switch (play->precision) {
        !           854:                        case 8:
        !           855:                                switch (play->channels) {
        !           856:                                case 1:
        !           857:                                        play->factor = 4;
        !           858:                                        play->sw_code = ulinear8_to_linear16_mts;
        !           859:                                        break;
        !           860:                                case 2:
        !           861:                                        play->factor = 2;
        !           862:                                        play->sw_code = ulinear8_to_linear16;
        !           863:                                        break;
        !           864:                                default:
        !           865:                                        return (EINVAL);
        !           866:                                }
        !           867:                                break;
        !           868:                        case 16:
        !           869:                                switch (play->channels) {
        !           870:                                case 1:
        !           871:                                        play->factor = 2;
        !           872:                                        play->sw_code = change_sign16_swap_bytes_mts;
        !           873:                                        break;
        !           874:                                case 2:
        !           875:                                        play->sw_code = change_sign16_swap_bytes;
        !           876:                                        break;
        !           877:                                default:
        !           878:                                        return (EINVAL);
        !           879:                                }
        !           880:                                break;
        !           881:                        default:
        !           882:                                return (EINVAL);
        !           883:                        }
        !           884:                        break;
        !           885:                default:
        !           886:                        return (EINVAL);
        !           887:                }
        !           888:
        !           889:                orate = adj_rate = play->sample_rate;
        !           890:                if (sc->sc_ac97rate != 0)
        !           891:                        adj_rate = orate * AUICH_FIXED_RATE / sc->sc_ac97rate;
        !           892:                play->sample_rate = adj_rate;
        !           893:                error = ac97_set_rate(sc->codec_if, play, AUMODE_PLAY);
        !           894:                if (play->sample_rate == adj_rate)
        !           895:                        play->sample_rate = orate;
        !           896:                if (error)
        !           897:                        return (error);
        !           898:        }
        !           899:
        !           900:        if (setmode & AUMODE_RECORD) {
        !           901:                rec->factor = 1;
        !           902:                rec->sw_code = 0;
        !           903:                switch(rec->encoding) {
        !           904:                case AUDIO_ENCODING_ULAW:
        !           905:                        rec->sw_code = slinear16_to_mulaw_le;
        !           906:                        rec->factor = 2;
        !           907:                        break;
        !           908:                case AUDIO_ENCODING_ALAW:
        !           909:                        rec->sw_code = slinear16_to_alaw_le;
        !           910:                        rec->factor = 2;
        !           911:                        break;
        !           912:                case AUDIO_ENCODING_SLINEAR_LE:
        !           913:                        switch (rec->precision) {
        !           914:                        case 8:
        !           915:                                rec->sw_code = linear16_to_linear8_le;
        !           916:                                rec->factor = 2;
        !           917:                                break;
        !           918:                        case 16:
        !           919:                                break;
        !           920:                        default:
        !           921:                                return (EINVAL);
        !           922:                        }
        !           923:                        break;
        !           924:                case AUDIO_ENCODING_ULINEAR_LE:
        !           925:                        switch (rec->precision) {
        !           926:                        case 8:
        !           927:                                rec->sw_code = linear16_to_ulinear8_le;
        !           928:                                rec->factor = 2;
        !           929:                                break;
        !           930:                        case 16:
        !           931:                                rec->sw_code = change_sign16_le;
        !           932:                                break;
        !           933:                        default:
        !           934:                                return (EINVAL);
        !           935:                        }
        !           936:                        break;
        !           937:                case AUDIO_ENCODING_SLINEAR_BE:
        !           938:                        switch (rec->precision) {
        !           939:                        case 8:
        !           940:                                rec->sw_code = linear16_to_linear8_le;
        !           941:                                rec->factor = 2;
        !           942:                                break;
        !           943:                        case 16:
        !           944:                                rec->sw_code = swap_bytes;
        !           945:                                break;
        !           946:                        default:
        !           947:                                return (EINVAL);
        !           948:                        }
        !           949:                        break;
        !           950:                case AUDIO_ENCODING_ULINEAR_BE:
        !           951:                        switch (rec->precision) {
        !           952:                        case 8:
        !           953:                                rec->sw_code = linear16_to_ulinear8_le;
        !           954:                                rec->factor = 2;
        !           955:                                break;
        !           956:                        case 16:
        !           957:                                rec->sw_code = change_sign16_swap_bytes_le;
        !           958:                                break;
        !           959:                        default:
        !           960:                                return (EINVAL);
        !           961:                        }
        !           962:                        break;
        !           963:                default:
        !           964:                        return (EINVAL);
        !           965:                }
        !           966:
        !           967:                orate = rec->sample_rate;
        !           968:                if (sc->sc_ac97rate != 0)
        !           969:                        rec->sample_rate = orate * AUICH_FIXED_RATE /
        !           970:                            sc->sc_ac97rate;
        !           971:                error = ac97_set_rate(sc->codec_if, rec, AUMODE_RECORD);
        !           972:                rec->sample_rate = orate;
        !           973:                if (error)
        !           974:                        return (error);
        !           975:        }
        !           976:
        !           977:        return (0);
        !           978: }
        !           979:
        !           980: int
        !           981: auich_round_blocksize(v, blk)
        !           982:        void *v;
        !           983:        int blk;
        !           984: {
        !           985:        return (blk + 0x3f) & ~0x3f;
        !           986: }
        !           987:
        !           988: int
        !           989: auich_halt_output(v)
        !           990:        void *v;
        !           991: {
        !           992:        struct auich_softc *sc = v;
        !           993:
        !           994:        DPRINTF(AUICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
        !           995:
        !           996:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL, AUICH_RR);
        !           997:
        !           998:        return 0;
        !           999: }
        !          1000:
        !          1001: int
        !          1002: auich_halt_input(v)
        !          1003:        void *v;
        !          1004: {
        !          1005:        struct auich_softc *sc = v;
        !          1006:
        !          1007:        DPRINTF(AUICH_DEBUG_DMA,
        !          1008:            ("%s: halt_input\n", sc->sc_dev.dv_xname));
        !          1009:
        !          1010:        /* XXX halt both unless known otherwise */
        !          1011:
        !          1012:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
        !          1013:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
        !          1014:
        !          1015:        return 0;
        !          1016: }
        !          1017:
        !          1018: int
        !          1019: auich_getdev(v, adp)
        !          1020:        void *v;
        !          1021:        struct audio_device *adp;
        !          1022: {
        !          1023:        struct auich_softc *sc = v;
        !          1024:        *adp = sc->sc_audev;
        !          1025:        return 0;
        !          1026: }
        !          1027:
        !          1028: int
        !          1029: auich_set_port(v, cp)
        !          1030:        void *v;
        !          1031:        mixer_ctrl_t *cp;
        !          1032: {
        !          1033:        struct auich_softc *sc = v;
        !          1034:        return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
        !          1035: }
        !          1036:
        !          1037: int
        !          1038: auich_get_port(v, cp)
        !          1039:        void *v;
        !          1040:        mixer_ctrl_t *cp;
        !          1041: {
        !          1042:        struct auich_softc *sc = v;
        !          1043:        return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
        !          1044: }
        !          1045:
        !          1046: int
        !          1047: auich_query_devinfo(v, dp)
        !          1048:        void *v;
        !          1049:        mixer_devinfo_t *dp;
        !          1050: {
        !          1051:        struct auich_softc *sc = v;
        !          1052:        return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
        !          1053: }
        !          1054:
        !          1055: void *
        !          1056: auich_allocm(v, direction, size, pool, flags)
        !          1057:        void *v;
        !          1058:        int direction;
        !          1059:        size_t size;
        !          1060:        int pool, flags;
        !          1061: {
        !          1062:        struct auich_softc *sc = v;
        !          1063:        struct auich_dma *p;
        !          1064:        int error;
        !          1065:
        !          1066:        if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
        !          1067:                return NULL;
        !          1068:
        !          1069:        p = malloc(sizeof(*p), pool, flags);
        !          1070:        if (!p)
        !          1071:                return NULL;
        !          1072:        bzero(p, sizeof(*p));
        !          1073:
        !          1074:        p->size = size;
        !          1075:        if ((error = bus_dmamem_alloc(sc->dmat, p->size, NBPG, 0, p->segs,
        !          1076:            1, &p->nsegs, BUS_DMA_NOWAIT)) != 0) {
        !          1077:                printf("%s: unable to allocate dma, error = %d\n",
        !          1078:                    sc->sc_dev.dv_xname, error);
        !          1079:                free(p, pool);
        !          1080:                return NULL;
        !          1081:        }
        !          1082:
        !          1083:        if ((error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
        !          1084:            &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
        !          1085:                printf("%s: unable to map dma, error = %d\n",
        !          1086:                    sc->sc_dev.dv_xname, error);
        !          1087:                bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
        !          1088:                free(p, pool);
        !          1089:                return NULL;
        !          1090:        }
        !          1091:
        !          1092:        if ((error = bus_dmamap_create(sc->dmat, p->size, 1,
        !          1093:            p->size, 0, BUS_DMA_NOWAIT, &p->map)) != 0) {
        !          1094:                printf("%s: unable to create dma map, error = %d\n",
        !          1095:                    sc->sc_dev.dv_xname, error);
        !          1096:                bus_dmamem_unmap(sc->dmat, p->addr, size);
        !          1097:                bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
        !          1098:                free(p, pool);
        !          1099:                return NULL;
        !          1100:        }
        !          1101:
        !          1102:        if ((error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size,
        !          1103:            NULL, BUS_DMA_NOWAIT)) != 0) {
        !          1104:                printf("%s: unable to load dma map, error = %d\n",
        !          1105:                    sc->sc_dev.dv_xname, error);
        !          1106:                bus_dmamap_destroy(sc->dmat, p->map);
        !          1107:                bus_dmamem_unmap(sc->dmat, p->addr, size);
        !          1108:                bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
        !          1109:                free(p, pool);
        !          1110:                return NULL;
        !          1111:        }
        !          1112:
        !          1113:        p->next = sc->sc_dmas;
        !          1114:        sc->sc_dmas = p;
        !          1115:
        !          1116:        return p->addr;
        !          1117: }
        !          1118:
        !          1119: void
        !          1120: auich_freem(v, ptr, pool)
        !          1121:        void *v;
        !          1122:        void *ptr;
        !          1123:        int pool;
        !          1124: {
        !          1125:        struct auich_softc *sc = v;
        !          1126:        struct auich_dma *p;
        !          1127:
        !          1128:        for (p = sc->sc_dmas; p->addr != ptr; p = p->next)
        !          1129:                if (p->next == NULL) {
        !          1130:                        printf("auich_freem: trying to free not allocated memory");
        !          1131:                        return;
        !          1132:                }
        !          1133:
        !          1134:        bus_dmamap_unload(sc->dmat, p->map);
        !          1135:        bus_dmamap_destroy(sc->dmat, p->map);
        !          1136:        bus_dmamem_unmap(sc->dmat, p->addr, p->size);
        !          1137:        bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
        !          1138:        free(p, pool);
        !          1139: }
        !          1140:
        !          1141: size_t
        !          1142: auich_round_buffersize(v, direction, size)
        !          1143:        void *v;
        !          1144:        int direction;
        !          1145:        size_t size;
        !          1146: {
        !          1147:        if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
        !          1148:                size = AUICH_DMALIST_MAX * AUICH_DMASEG_MAX;
        !          1149:
        !          1150:        return size;
        !          1151: }
        !          1152:
        !          1153: paddr_t
        !          1154: auich_mappage(v, mem, off, prot)
        !          1155:        void *v;
        !          1156:        void *mem;
        !          1157:        off_t off;
        !          1158:        int prot;
        !          1159: {
        !          1160:        struct auich_softc *sc = v;
        !          1161:        struct auich_dma *p;
        !          1162:
        !          1163:        if (off < 0)
        !          1164:                return -1;
        !          1165:
        !          1166:        for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
        !          1167:        if (!p)
        !          1168:                return -1;
        !          1169:
        !          1170:        return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
        !          1171:            off, prot, BUS_DMA_WAITOK);
        !          1172: }
        !          1173:
        !          1174: int
        !          1175: auich_get_props(v)
        !          1176:        void *v;
        !          1177: {
        !          1178:        return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
        !          1179: }
        !          1180:
        !          1181: int
        !          1182: auich_intr(v)
        !          1183:        void *v;
        !          1184: {
        !          1185:        struct auich_softc *sc = v;
        !          1186:        int ret = 0, sts, gsts, i;
        !          1187:
        !          1188:        gsts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_GSTS);
        !          1189:        DPRINTF(AUICH_DEBUG_DMA, ("auich_intr: gsts=%b\n", gsts, AUICH_GSTS_BITS));
        !          1190:
        !          1191:        if (gsts & AUICH_POINT) {
        !          1192:                sts = bus_space_read_2(sc->iot, sc->aud_ioh,
        !          1193:                    AUICH_PCMO + sc->sc_sts_reg);
        !          1194:                DPRINTF(AUICH_DEBUG_DMA,
        !          1195:                    ("auich_intr: osts=%b\n", sts, AUICH_ISTS_BITS));
        !          1196:
        !          1197: #ifdef AUICH_DEBUG
        !          1198:                if (sts & AUICH_FIFOE) {
        !          1199:                        printf("%s: fifo underrun # %u\n",
        !          1200:                            sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
        !          1201:                }
        !          1202: #endif
        !          1203:                i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CIV);
        !          1204:                if (sts & (AUICH_LVBCI | AUICH_CELV)) {
        !          1205:                        struct auich_dmalist *q, *qe;
        !          1206:
        !          1207:                        q = sc->dmap_pcmo;
        !          1208:                        qe = &sc->dmalist_pcmo[i];
        !          1209:
        !          1210:                        while (q != qe) {
        !          1211:
        !          1212:                                q->base = sc->pcmo_p;
        !          1213:                                q->len = (sc->pcmo_blksize /
        !          1214:                                    sc->sc_sample_size) | AUICH_DMAF_IOC;
        !          1215:                                DPRINTF(AUICH_DEBUG_DMA,
        !          1216:                                    ("auich_intr: %p, %p = %x @ %p\n",
        !          1217:                                    qe, q, sc->pcmo_blksize /
        !          1218:                                    sc->sc_sample_size, sc->pcmo_p));
        !          1219:
        !          1220:                                sc->pcmo_p += sc->pcmo_blksize;
        !          1221:                                if (sc->pcmo_p >= sc->pcmo_end)
        !          1222:                                        sc->pcmo_p = sc->pcmo_start;
        !          1223:
        !          1224:                                if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
        !          1225:                                        q = sc->dmalist_pcmo;
        !          1226:                        }
        !          1227:
        !          1228:                        sc->dmap_pcmo = q;
        !          1229:                        bus_space_write_1(sc->iot, sc->aud_ioh,
        !          1230:                            AUICH_PCMO + AUICH_LVI,
        !          1231:                            (sc->dmap_pcmo - sc->dmalist_pcmo - 1) &
        !          1232:                            AUICH_LVI_MASK);
        !          1233:                }
        !          1234:
        !          1235:                if (sts & AUICH_BCIS && sc->sc_pintr)
        !          1236:                        sc->sc_pintr(sc->sc_parg);
        !          1237:
        !          1238:                /* int ack */
        !          1239:                bus_space_write_2(sc->iot, sc->aud_ioh,
        !          1240:                    AUICH_PCMO + sc->sc_sts_reg, sts &
        !          1241:                    (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
        !          1242:                bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
        !          1243:                ret++;
        !          1244:        }
        !          1245:
        !          1246:        if (gsts & AUICH_PIINT) {
        !          1247:                sts = bus_space_read_2(sc->iot, sc->aud_ioh,
        !          1248:                    AUICH_PCMI + sc->sc_sts_reg);
        !          1249:                DPRINTF(AUICH_DEBUG_DMA,
        !          1250:                    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
        !          1251:
        !          1252: #ifdef AUICH_DEBUG
        !          1253:                if (sts & AUICH_FIFOE) {
        !          1254:                        printf("%s: in fifo overrun # %u\n",
        !          1255:                            sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
        !          1256:                }
        !          1257: #endif
        !          1258:                i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
        !          1259:                if (sts & (AUICH_LVBCI | AUICH_CELV)) {
        !          1260:                        struct auich_dmalist *q, *qe;
        !          1261:
        !          1262:                        q = sc->dmap_pcmi;
        !          1263:                        qe = &sc->dmalist_pcmi[i];
        !          1264:
        !          1265:                        while (q != qe) {
        !          1266:
        !          1267:                                q->base = sc->pcmi_p;
        !          1268:                                q->len = (sc->pcmi_blksize /
        !          1269:                                    sc->sc_sample_size) | AUICH_DMAF_IOC;
        !          1270:                                DPRINTF(AUICH_DEBUG_DMA,
        !          1271:                                    ("auich_intr: %p, %p = %x @ %p\n",
        !          1272:                                    qe, q, sc->pcmi_blksize /
        !          1273:                                    sc->sc_sample_size, sc->pcmi_p));
        !          1274:
        !          1275:                                sc->pcmi_p += sc->pcmi_blksize;
        !          1276:                                if (sc->pcmi_p >= sc->pcmi_end)
        !          1277:                                        sc->pcmi_p = sc->pcmi_start;
        !          1278:
        !          1279:                                if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
        !          1280:                                        q = sc->dmalist_pcmi;
        !          1281:                        }
        !          1282:
        !          1283:                        sc->dmap_pcmi = q;
        !          1284:                        bus_space_write_1(sc->iot, sc->aud_ioh,
        !          1285:                            AUICH_PCMI + AUICH_LVI,
        !          1286:                            (sc->dmap_pcmi - sc->dmalist_pcmi - 1) &
        !          1287:                            AUICH_LVI_MASK);
        !          1288:                }
        !          1289:
        !          1290:                if (sts & AUICH_BCIS && sc->sc_rintr)
        !          1291:                        sc->sc_rintr(sc->sc_rarg);
        !          1292:
        !          1293:                /* int ack */
        !          1294:                bus_space_write_2(sc->iot, sc->aud_ioh,
        !          1295:                    AUICH_PCMI + sc->sc_sts_reg, sts &
        !          1296:                    (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
        !          1297:                bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_PIINT);
        !          1298:                ret++;
        !          1299:        }
        !          1300:
        !          1301:        if (gsts & AUICH_MIINT) {
        !          1302:                sts = bus_space_read_2(sc->iot, sc->aud_ioh,
        !          1303:                    AUICH_MICI + sc->sc_sts_reg);
        !          1304:                DPRINTF(AUICH_DEBUG_DMA,
        !          1305:                    ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
        !          1306: #ifdef AUICH_DEBUG
        !          1307:                if (sts & AUICH_FIFOE)
        !          1308:                        printf("%s: mic fifo overrun\n", sc->sc_dev.dv_xname);
        !          1309: #endif
        !          1310:
        !          1311:                /* TODO mic input dma */
        !          1312:
        !          1313:                bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_MIINT);
        !          1314:        }
        !          1315:
        !          1316:        return ret;
        !          1317: }
        !          1318:
        !          1319: int
        !          1320: auich_trigger_output(v, start, end, blksize, intr, arg, param)
        !          1321:        void *v;
        !          1322:        void *start, *end;
        !          1323:        int blksize;
        !          1324:        void (*intr)(void *);
        !          1325:        void *arg;
        !          1326:        struct audio_params *param;
        !          1327: {
        !          1328:        struct auich_softc *sc = v;
        !          1329:        struct auich_dmalist *q;
        !          1330:        struct auich_dma *p;
        !          1331:
        !          1332:        DPRINTF(AUICH_DEBUG_DMA,
        !          1333:            ("auich_trigger_output(%x, %x, %d, %p, %p, %p)\n",
        !          1334:            start, end, blksize, intr, arg, param));
        !          1335:
        !          1336:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
        !          1337:        if (!p)
        !          1338:                return -1;
        !          1339:
        !          1340:        sc->sc_pintr = intr;
        !          1341:        sc->sc_parg = arg;
        !          1342:
        !          1343:        /*
        !          1344:         * The logic behind this is:
        !          1345:         * setup one buffer to play, then LVI dump out the rest
        !          1346:         * to the scatter-gather chain.
        !          1347:         */
        !          1348:        sc->pcmo_start = p->segs->ds_addr;
        !          1349:        sc->pcmo_p = sc->pcmo_start + blksize;
        !          1350:        sc->pcmo_end = sc->pcmo_start + ((char *)end - (char *)start);
        !          1351:        sc->pcmo_blksize = blksize;
        !          1352:
        !          1353:        q = sc->dmap_pcmo = sc->dmalist_pcmo;
        !          1354:        q->base = sc->pcmo_start;
        !          1355:        q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
        !          1356:        if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
        !          1357:                q = sc->dmalist_pcmo;
        !          1358:        sc->dmap_pcmo = q;
        !          1359:
        !          1360:        bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_BDBAR,
        !          1361:            sc->dmalist_pcmo_pa);
        !          1362:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL,
        !          1363:            AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
        !          1364:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_LVI,
        !          1365:            (sc->dmap_pcmo - 1 - sc->dmalist_pcmo) & AUICH_LVI_MASK);
        !          1366:
        !          1367:        return 0;
        !          1368: }
        !          1369:
        !          1370: int
        !          1371: auich_trigger_input(v, start, end, blksize, intr, arg, param)
        !          1372:        void *v;
        !          1373:        void *start, *end;
        !          1374:        int blksize;
        !          1375:        void (*intr)(void *);
        !          1376:        void *arg;
        !          1377:        struct audio_params *param;
        !          1378: {
        !          1379:        struct auich_softc *sc = v;
        !          1380:        struct auich_dmalist *q;
        !          1381:        struct auich_dma *p;
        !          1382:
        !          1383:        DPRINTF(AUICH_DEBUG_DMA,
        !          1384:            ("auich_trigger_input(%x, %x, %d, %p, %p, %p)\n",
        !          1385:            start, end, blksize, intr, arg, param));
        !          1386:
        !          1387:        for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
        !          1388:        if (!p)
        !          1389:                return -1;
        !          1390:
        !          1391:        sc->sc_rintr = intr;
        !          1392:        sc->sc_rarg = arg;
        !          1393:
        !          1394:        /*
        !          1395:         * The logic behind this is:
        !          1396:         * setup one buffer to play, then LVI dump out the rest
        !          1397:         * to the scatter-gather chain.
        !          1398:         */
        !          1399:        sc->pcmi_start = p->segs->ds_addr;
        !          1400:        sc->pcmi_p = sc->pcmi_start + blksize;
        !          1401:        sc->pcmi_end = sc->pcmi_start + ((char *)end - (char *)start);
        !          1402:        sc->pcmi_blksize = blksize;
        !          1403:
        !          1404:        q = sc->dmap_pcmi = sc->dmalist_pcmi;
        !          1405:        q->base = sc->pcmi_start;
        !          1406:        q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
        !          1407:        if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
        !          1408:                q = sc->dmalist_pcmi;
        !          1409:        sc->dmap_pcmi = q;
        !          1410:
        !          1411:        bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
        !          1412:            sc->dmalist_pcmi_pa);
        !          1413:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
        !          1414:            AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
        !          1415:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
        !          1416:            (sc->dmap_pcmi - 1 - sc->dmalist_pcmi) & AUICH_LVI_MASK);
        !          1417:
        !          1418:        return 0;
        !          1419: }
        !          1420:
        !          1421: void
        !          1422: auich_powerhook(why, self)
        !          1423:        int why;
        !          1424:        void *self;
        !          1425: {
        !          1426:        struct auich_softc *sc = (struct auich_softc *)self;
        !          1427:
        !          1428:        if (why != PWR_RESUME) {
        !          1429:                /* Power down */
        !          1430:                DPRINTF(1, ("auich: power down\n"));
        !          1431:                sc->suspend = why;
        !          1432:                auich_read_codec(sc, AC97_REG_EXT_AUDIO_CTRL, &sc->ext_ctrl);
        !          1433:
        !          1434:        } else {
        !          1435:                /* Wake up */
        !          1436:                DPRINTF(1, ("auich: power resume\n"));
        !          1437:                if (sc->suspend == PWR_RESUME) {
        !          1438:                        printf("%s: resume without suspend?\n",
        !          1439:                            sc->sc_dev.dv_xname);
        !          1440:                        sc->suspend = why;
        !          1441:                        return;
        !          1442:                }
        !          1443:                sc->suspend = why;
        !          1444:                auich_reset_codec(sc);
        !          1445:                DELAY(1000);
        !          1446:                (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
        !          1447:                auich_write_codec(sc, AC97_REG_EXT_AUDIO_CTRL, sc->ext_ctrl);
        !          1448:        }
        !          1449: }
        !          1450:
        !          1451:
        !          1452:
        !          1453: /* -------------------------------------------------------------------- */
        !          1454: /* Calibrate card (some boards are overclocked and need scaling) */
        !          1455:
        !          1456: unsigned int
        !          1457: auich_calibrate(struct auich_softc *sc)
        !          1458: {
        !          1459:        struct timeval t1, t2;
        !          1460:        u_int8_t ociv, nciv;
        !          1461:        u_int32_t wait_us, actual_48k_rate, bytes, ac97rate;
        !          1462:        void *temp_buffer;
        !          1463:        struct auich_dma *p;
        !          1464:        int i;
        !          1465:
        !          1466:        ac97rate = AUICH_FIXED_RATE;
        !          1467:        /*
        !          1468:         * Grab audio from input for fixed interval and compare how
        !          1469:         * much we actually get with what we expect.  Interval needs
        !          1470:         * to be sufficiently short that no interrupts are
        !          1471:         * generated.
        !          1472:         */
        !          1473:
        !          1474:        /* Setup a buffer */
        !          1475:        bytes = 16000;
        !          1476:        temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes, M_DEVBUF,
        !          1477:            M_NOWAIT);
        !          1478:        if (temp_buffer == NULL)
        !          1479:                return (ac97rate);
        !          1480:        for (p = sc->sc_dmas; p && p->addr != temp_buffer; p = p->next)
        !          1481:                ;
        !          1482:        if (p == NULL) {
        !          1483:                printf("auich_calibrate: bad address %p\n", temp_buffer);
        !          1484:                return (ac97rate);
        !          1485:        }
        !          1486:
        !          1487:        for (i = 0; i < AUICH_DMALIST_MAX; i++) {
        !          1488:                sc->dmalist_pcmi[i].base = p->map->dm_segs[0].ds_addr;
        !          1489:                sc->dmalist_pcmi[i].len = bytes / sc->sc_sample_size;
        !          1490:        }
        !          1491:
        !          1492:        /*
        !          1493:         * our data format is stereo, 16 bit so each sample is 4 bytes.
        !          1494:         * assuming we get 48000 samples per second, we get 192000 bytes/sec.
        !          1495:         * we're going to start recording with interrupts disabled and measure
        !          1496:         * the time taken for one block to complete.  we know the block size,
        !          1497:         * we know the time in microseconds, we calculate the sample rate:
        !          1498:         *
        !          1499:         * actual_rate [bps] = bytes / (time [s] * 4)
        !          1500:         * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4)
        !          1501:         * actual_rate [Hz] = (bytes * 250000) / time [us]
        !          1502:         */
        !          1503:
        !          1504:        /* prepare */
        !          1505:        ociv = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
        !          1506:        nciv = ociv;
        !          1507:        bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
        !          1508:            sc->dmalist_pcmi_pa);
        !          1509:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
        !          1510:                          (0 - 1) & AUICH_LVI_MASK);
        !          1511:
        !          1512:        /* start */
        !          1513:        microuptime(&t1);
        !          1514:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
        !          1515:            AUICH_RPBM);
        !          1516:
        !          1517:        /* wait */
        !          1518:        while (nciv == ociv) {
        !          1519:                microuptime(&t2);
        !          1520:                if (t2.tv_sec - t1.tv_sec > 1)
        !          1521:                        break;
        !          1522:                nciv = bus_space_read_1(sc->iot, sc->aud_ioh,
        !          1523:                                        AUICH_PCMI + AUICH_CIV);
        !          1524:        }
        !          1525:        microuptime(&t2);
        !          1526:
        !          1527:        /* reset */
        !          1528:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
        !          1529:        bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
        !          1530:        DELAY(100);
        !          1531:
        !          1532:        /* turn time delta into us */
        !          1533:        wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec;
        !          1534:
        !          1535: #if 0
        !          1536:        auich_freem(sc, temp_buffer, M_DEVBUF);
        !          1537: #endif
        !          1538:
        !          1539:        if (nciv == ociv) {
        !          1540:                printf("%s: ac97 link rate calibration timed out after %d us\n",
        !          1541:                       sc->sc_dev.dv_xname, wait_us);
        !          1542:                return (ac97rate);
        !          1543:        }
        !          1544:
        !          1545:        actual_48k_rate = (bytes * 250000) / wait_us;
        !          1546:
        !          1547:        if (actual_48k_rate <= 48500)
        !          1548:                ac97rate = AUICH_FIXED_RATE;
        !          1549:        else
        !          1550:                ac97rate = actual_48k_rate;
        !          1551:
        !          1552:        printf("%s: measured ac97 link rate at %d Hz",
        !          1553:               sc->sc_dev.dv_xname, actual_48k_rate);
        !          1554:        if (ac97rate != actual_48k_rate)
        !          1555:                printf(", will use %d Hz", ac97rate);
        !          1556:        printf("\n");
        !          1557:
        !          1558:        return (ac97rate);
        !          1559: }

CVSweb