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

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

1.1       nbrk        1: /* $OpenBSD: auixp.c,v 1.10 2007/05/26 00:36:03 krw Exp $ */
                      2: /* $NetBSD: auixp.c,v 1.9 2005/06/27 21:13:09 thorpej Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. The name of the author may not be used to endorse or promote products
                     14:  *    derived from this software without specific prior written permission.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the NetBSD
                     18:  *     Foundation, Inc. and its contributors.
                     19:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     20:  *    contributors may be used to endorse or promote products derived
                     21:  *    from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     27:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     28:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     29:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     30:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     31:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35: /*
                     36:  * Audio driver for ATI IXP-{150,200,...} audio driver hardware.
                     37:  *
                     38:  * Recording and playback has been tested OK on various sample rates and
                     39:  * encodings.
                     40:  *
                     41:  * Known problems and issues :
                     42:  * - SPDIF is untested and needs some work still (LED stays off)
                     43:  * - 32 bit audio playback failed last time i tried but that might an AC'97
                     44:  *   codec support problem.
                     45:  * - 32 bit recording works but can't try out playing: see above.
                     46:  * - no suspend/resume support yet.
                     47:  * - multiple codecs are `supported' but not tested; the implemetation needs
                     48:  *   some cleaning up.
                     49:  */
                     50:
                     51: /*#define DEBUG_AUIXP*/
                     52:
                     53: #include <sys/types.h>
                     54: #include <sys/errno.h>
                     55: #include <sys/param.h>
                     56: #include <sys/systm.h>
                     57: #include <sys/malloc.h>
                     58: #include <sys/device.h>
                     59: #include <sys/conf.h>
                     60: #include <sys/exec.h>
                     61: #include <sys/selinfo.h>
                     62: #include <sys/audioio.h>
                     63: #include <sys/queue.h>
                     64:
                     65: #include <machine/bus.h>
                     66: #include <machine/intr.h>
                     67:
                     68: #include <dev/pci/pcidevs.h>
                     69: #include <dev/pci/pcivar.h>
                     70:
                     71: #include <dev/audio_if.h>
                     72: #include <dev/mulaw.h>
                     73: #include <dev/auconv.h>
                     74: #include <dev/ic/ac97.h>
                     75:
                     76: #include <dev/pci/auixpreg.h>
                     77: #include <dev/pci/auixpvar.h>
                     78:
                     79: /* codec detection constant indicating the interrupt flags */
                     80: #define ALL_CODECS_NOT_READY \
                     81:     (ATI_REG_ISR_CODEC0_NOT_READY | ATI_REG_ISR_CODEC1_NOT_READY |\
                     82:      ATI_REG_ISR_CODEC2_NOT_READY)
                     83: #define CODEC_CHECK_BITS (ALL_CODECS_NOT_READY|ATI_REG_ISR_NEW_FRAME)
                     84:
                     85: /* why isn't this base address register not in the headerfile? */
                     86: #define PCI_CBIO 0x10
                     87:
                     88: /* macro's used */
                     89: #define KERNADDR(p)    ((void *)((p)->addr))
                     90: #define        DMAADDR(p)      ((p)->map->dm_segs[0].ds_addr)
                     91:
                     92: const struct pci_matchid auixp_pci_devices[] = {
                     93:        { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_200 },
                     94:        { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_300 },
                     95:        { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_IXP_AUDIO_400 },
                     96: };
                     97:
                     98: struct cfdriver auixp_cd = {
                     99:        NULL, "auixp", DV_DULL
                    100: };
                    101:
                    102: int    auixp_match( struct device *, void *, void *);
                    103: void   auixp_attach(struct device *, struct device *, void *);
                    104: int    auixp_detach(struct device *, int);
                    105:
                    106: struct cfattach auixp_ca = {
                    107:        sizeof(struct auixp_softc), auixp_match, auixp_attach
                    108: };
                    109:
                    110: int    auixp_open(void *v, int flags);
                    111: void   auixp_close(void *v);
                    112: int    auixp_query_encoding(void *, struct audio_encoding *);
                    113: int    auixp_set_params(void *, int, int, struct audio_params *,
                    114:     struct audio_params *);
                    115: int    auixp_commit_settings(void *);
                    116: int    auixp_round_blocksize(void *, int);
                    117: int    auixp_trigger_output(void *, void *, void *, int,
                    118:     void (*)(void *), void *, struct audio_params *);
                    119: int    auixp_trigger_input(void *, void *, void *, int,
                    120:     void (*)(void *), void *, struct audio_params *);
                    121: int    auixp_halt_output(void *);
                    122: int    auixp_halt_input(void *);
                    123: int    auixp_set_port(void *, mixer_ctrl_t *);
                    124: int    auixp_get_port(void *, mixer_ctrl_t *);
                    125: int    auixp_query_devinfo(void *, mixer_devinfo_t *);
                    126: void * auixp_malloc(void *, int, size_t, int, int);
                    127: void   auixp_free(void *, void *, int);
                    128: int    auixp_getdev(void *, struct audio_device *);
                    129: size_t auixp_round_buffersize(void *, int, size_t);
                    130: int    auixp_get_props(void *);
                    131: int    auixp_intr(void *);
                    132: int    auixp_allocmem(struct auixp_softc *, size_t, size_t,
                    133:     struct auixp_dma *);
                    134: int    auixp_freemem(struct auixp_softc *, struct auixp_dma *);
                    135: paddr_t        auixp_mappage(void *, void *, off_t, int);
                    136:
                    137:
                    138: /* power management (do we support that already?) */
                    139: int    auixp_power(struct auixp_softc *, int);
                    140: #if 0
                    141: void   auixp_powerhook(int, void *);
                    142: int    auixp_suspend(struct auixp_softc *);
                    143: int    auixp_resume(struct auixp_softc *);
                    144: #endif
                    145:
                    146:
                    147: /* Supporting subroutines */
                    148: int    auixp_init(struct auixp_softc *);
                    149: void   auixp_autodetect_codecs(struct auixp_softc *);
                    150: void   auixp_post_config(void *);
                    151:
                    152: void   auixp_reset_aclink(struct auixp_softc *);
                    153: int    auixp_attach_codec(void *, struct ac97_codec_if *);
                    154: int    auixp_read_codec(void *, u_int8_t, u_int16_t *);
                    155: int    auixp_write_codec(void *, u_int8_t, u_int16_t);
                    156: int    auixp_wait_for_codecs(struct auixp_softc *, const char *);
                    157: void   auixp_reset_codec(void *);
                    158: enum ac97_host_flags   auixp_flags_codec(void *);
                    159:
                    160: void   auixp_enable_dma(struct auixp_softc *, struct auixp_dma *);
                    161: void   auixp_disable_dma(struct auixp_softc *, struct auixp_dma *);
                    162: void   auixp_enable_interrupts(struct auixp_softc *);
                    163: void   auixp_disable_interrupts(struct auixp_softc *);
                    164:
                    165: void   auixp_link_daisychain(struct auixp_softc *,
                    166:     struct auixp_dma *, struct auixp_dma *, int, int);
                    167: int    auixp_allocate_dma_chain(struct auixp_softc *, struct auixp_dma **);
                    168: void   auixp_program_dma_chain(struct auixp_softc *, struct auixp_dma *);
                    169: void   auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
                    170: void   auixp_update_busbusy(struct auixp_softc *);
                    171:
                    172: #ifdef DEBUG_AUIXP
                    173: #define DPRINTF(x)     printf x;
                    174: #else
                    175: #define DPRINTF(x)
                    176: #endif
                    177:
                    178: struct audio_hw_if auixp_hw_if = {
                    179:        auixp_open,
                    180:        auixp_close,
                    181:        NULL,                   /* drain */
                    182:        auixp_query_encoding,
                    183:        auixp_set_params,
                    184:        auixp_round_blocksize,
                    185:        auixp_commit_settings,
                    186:        NULL,                   /* init_output  */
                    187:        NULL,                   /* init_input   */
                    188:        NULL,                   /* start_output */
                    189:        NULL,                   /* start_input  */
                    190:        auixp_halt_output,
                    191:        auixp_halt_input,
                    192:        NULL,                   /* speaker_ctl */
                    193:        auixp_getdev,
                    194:        NULL,                   /* getfd */
                    195:        auixp_set_port,
                    196:        auixp_get_port,
                    197:        auixp_query_devinfo,
                    198:        auixp_malloc,
                    199:        auixp_free,
                    200:        auixp_round_buffersize,
                    201:        auixp_mappage,
                    202:        auixp_get_props,
                    203:        auixp_trigger_output,
                    204:        auixp_trigger_input
                    205: };
                    206:
                    207: int
                    208: auixp_open(void *v, int flags)
                    209: {
                    210:
                    211:        return 0;
                    212: }
                    213:
                    214: void
                    215: auixp_close(void *v)
                    216: {
                    217: }
                    218:
                    219: int
                    220: auixp_query_encoding(void *hdl, struct audio_encoding *aep)
                    221: {
                    222:        switch (aep->index) {
                    223:        case 0:
                    224:                strlcpy(aep->name, AudioEulinear, sizeof aep->name);
                    225:                aep->encoding = AUDIO_ENCODING_ULINEAR;
                    226:                aep->precision = 8;
                    227:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    228:                return (0);
                    229:        case 1:
                    230:                strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
                    231:                aep->encoding = AUDIO_ENCODING_ULAW;
                    232:                aep->precision = 8;
                    233:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    234:                return (0);
                    235:        case 2:
                    236:                strlcpy(aep->name, AudioEalaw, sizeof aep->name);
                    237:                aep->encoding = AUDIO_ENCODING_ALAW;
                    238:                aep->precision = 8;
                    239:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    240:                return (0);
                    241:        case 3:
                    242:                strlcpy(aep->name, AudioEslinear, sizeof aep->name);
                    243:                aep->encoding = AUDIO_ENCODING_SLINEAR;
                    244:                aep->precision = 8;
                    245:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    246:                return (0);
                    247:        case 4:
                    248:                strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
                    249:                aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
                    250:                aep->precision = 16;
                    251:                aep->flags = 0;
                    252:                return (0);
                    253:        case 5:
                    254:                strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
                    255:                aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
                    256:                aep->precision = 16;
                    257:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    258:                return (0);
                    259:        case 6:
                    260:                strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
                    261:                aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
                    262:                aep->precision = 16;
                    263:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    264:                return (0);
                    265:        case 7:
                    266:                strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
                    267:                aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
                    268:                aep->precision = 16;
                    269:                aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
                    270:                return (0);
                    271:        default:
                    272:                return (EINVAL);
                    273:        }
                    274: }
                    275:
                    276:
                    277: /* commit setting and program ATI IXP chip */
                    278: int
                    279: auixp_commit_settings(void *hdl)
                    280: {
                    281:        struct auixp_codec *co;
                    282:        struct auixp_softc *sc;
                    283:        bus_space_tag_t    iot;
                    284:        bus_space_handle_t ioh;
                    285:        struct audio_params *params;
                    286:        u_int32_t value;
                    287:
                    288:        /* XXX would it be better to stop interrupts first? XXX */
                    289:        co = (struct auixp_codec *) hdl;
                    290:        sc = co->sc;
                    291:        iot = sc->sc_iot;
                    292:        ioh = sc->sc_ioh;
                    293:
                    294:        /* process input settings */
                    295:        params = &sc->sc_play_params;
                    296:
                    297:        /* set input interleaving (precision) */
                    298:        value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
                    299:        value &= ~ATI_REG_CMD_INTERLEAVE_IN;
                    300:        if (params->precision <= 16)
                    301:                value |= ATI_REG_CMD_INTERLEAVE_IN;
                    302:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                    303:
                    304:        /* process output settings */
                    305:        params = &sc->sc_play_params;
                    306:
                    307:        value  =  bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT);
                    308:        value &= ~ATI_REG_OUT_DMA_SLOT_MASK;
                    309:
                    310:        /* TODO SPDIF case for 8 channels */
                    311:        switch (params->channels) {
                    312:        case 6:
                    313:                value |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
                    314:                         ATI_REG_OUT_DMA_SLOT_BIT(8);
                    315:                /* FALLTHROUGH */
                    316:        case 4:
                    317:                value |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
                    318:                         ATI_REG_OUT_DMA_SLOT_BIT(9);
                    319:                /* FALLTHROUGH */
                    320:        default:
                    321:                value |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
                    322:                         ATI_REG_OUT_DMA_SLOT_BIT(4);
                    323:                break;
                    324:        }
                    325:        /* set output threshold */
                    326:        value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT;
                    327:        bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value);
                    328:
                    329:        /* set output interleaving (precision) */
                    330:        value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
                    331:        value &= ~ATI_REG_CMD_INTERLEAVE_OUT;
                    332:        if (params->precision <= 16)
                    333:                value |= ATI_REG_CMD_INTERLEAVE_OUT;
                    334:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                    335:
                    336:        /* enable 6 channel reordering */
                    337:        value  =  bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER);
                    338:        value &= ~ATI_REG_6CH_REORDER_EN;
                    339:        if (params->channels == 6)
                    340:                value |= ATI_REG_6CH_REORDER_EN;
                    341:        bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value);
                    342:
                    343:        if (sc->has_spdif) {
                    344:                /* set SPDIF (if present) */
                    345:                value  =  bus_space_read_4(iot, ioh, ATI_REG_CMD);
                    346:                value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK;
                    347:                value |=  ATI_REG_CMD_SPDF_CONFIG_34; /* NetBSD AC'97 default */
                    348:
                    349:                /* XXX this is probably not necessary unless splitted XXX */
                    350:                value &= ~ATI_REG_CMD_INTERLEAVE_SPDF;
                    351:                if (params->precision <= 16)
                    352:                        value |= ATI_REG_CMD_INTERLEAVE_SPDF;
                    353:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                    354:        }
                    355:
                    356:        return 0;
                    357: }
                    358:
                    359:
                    360: /* set audio properties in desired setting */
                    361: int
                    362: auixp_set_params(void *hdl, int setmode, int usemode,
                    363:     struct audio_params *play, struct audio_params *rec)
                    364: {
                    365:        struct auixp_codec *co;
                    366:        struct auixp_softc *sc;
                    367:        int error;
                    368:
                    369:        co = (struct auixp_codec *) hdl;
                    370:        sc = co->sc;
                    371:        if (setmode & AUMODE_PLAY) {
                    372:                play->factor = 1;
                    373:                play->sw_code = NULL;
                    374:                switch(play->encoding) {
                    375:                case AUDIO_ENCODING_ULAW:
                    376:                        switch (play->channels) {
                    377:                        case 1:
                    378:                                play->factor = 4;
                    379:                                play->sw_code = mulaw_to_slinear16_mts;
                    380:                                break;
                    381:                        case 2:
                    382:                                play->factor = 2;
                    383:                                play->sw_code = mulaw_to_slinear16;
                    384:                                break;
                    385:                        default:
                    386:                                return (EINVAL);
                    387:                        }
                    388:                        break;
                    389:                case AUDIO_ENCODING_SLINEAR_LE:
                    390:                        switch (play->precision) {
                    391:                        case 8:
                    392:                                switch (play->channels) {
                    393:                                case 1:
                    394:                                        play->factor = 4;
                    395:                                        play->sw_code = linear8_to_linear16_mts;
                    396:                                        break;
                    397:                                case 2:
                    398:                                        play->factor = 2;
                    399:                                        play->sw_code = linear8_to_linear16;
                    400:                                        break;
                    401:                                default:
                    402:                                        return (EINVAL);
                    403:                                }
                    404:                                break;
                    405:                        case 16:
                    406:                                switch (play->channels) {
                    407:                                case 1:
                    408:                                        play->factor = 2;
                    409:                                        play->sw_code = noswap_bytes_mts;
                    410:                                        break;
                    411:                                case 2:
                    412:                                        break;
                    413:                                default:
                    414:                                        return (EINVAL);
                    415:                                }
                    416:                                break;
                    417:                        default:
                    418:                                return (EINVAL);
                    419:                        }
                    420:                        break;
                    421:                case AUDIO_ENCODING_ULINEAR_LE:
                    422:                        switch (play->precision) {
                    423:                        case 8:
                    424:                                switch (play->channels) {
                    425:                                case 1:
                    426:                                        play->factor = 4;
                    427:                                        play->sw_code = ulinear8_to_linear16_mts;
                    428:                                        break;
                    429:                                case 2:
                    430:                                        play->factor = 2;
                    431:                                        play->sw_code = ulinear8_to_linear16;
                    432:                                        break;
                    433:                                default:
                    434:                                        return (EINVAL);
                    435:                                }
                    436:                                break;
                    437:                        case 16:
                    438:                                switch (play->channels) {
                    439:                                case 1:
                    440:                                        play->factor = 2;
                    441:                                        play->sw_code = change_sign16_mts;
                    442:                                        break;
                    443:                                case 2:
                    444:                                        play->sw_code = change_sign16;
                    445:                                        break;
                    446:                                default:
                    447:                                        return (EINVAL);
                    448:                                }
                    449:                                break;
                    450:                        default:
                    451:                                return (EINVAL);
                    452:                        }
                    453:                        break;
                    454:                case AUDIO_ENCODING_ALAW:
                    455:                        switch (play->channels) {
                    456:                        case 1:
                    457:                                play->factor = 4;
                    458:                                play->sw_code = alaw_to_slinear16_mts;
                    459:                                break;
                    460:                        case 2:
                    461:                                play->factor = 2;
                    462:                                play->sw_code = alaw_to_slinear16;
                    463:                                break;
                    464:                        default:
                    465:                                return (EINVAL);
                    466:                        }
                    467:                        break;
                    468:                case AUDIO_ENCODING_SLINEAR_BE:
                    469:                        switch (play->precision) {
                    470:                        case 8:
                    471:                                switch (play->channels) {
                    472:                                case 1:
                    473:                                        play->factor = 4;
                    474:                                        play->sw_code = linear8_to_linear16_mts;
                    475:                                        break;
                    476:                                case 2:
                    477:                                        play->factor = 2;
                    478:                                        play->sw_code = linear8_to_linear16;
                    479:                                        break;
                    480:                                default:
                    481:                                        return (EINVAL);
                    482:                                }
                    483:                                break;
                    484:                        case 16:
                    485:                                switch (play->channels) {
                    486:                                case 1:
                    487:                                        play->factor = 2;
                    488:                                        play->sw_code = swap_bytes_mts;
                    489:                                        break;
                    490:                                case 2:
                    491:                                        play->sw_code = swap_bytes;
                    492:                                        break;
                    493:                                default:
                    494:                                        return (EINVAL);
                    495:                                }
                    496:                                break;
                    497:                        default:
                    498:                                return (EINVAL);
                    499:                        }
                    500:                        break;
                    501:                case AUDIO_ENCODING_ULINEAR_BE:
                    502:                        switch (play->precision) {
                    503:                        case 8:
                    504:                                switch (play->channels) {
                    505:                                case 1:
                    506:                                        play->factor = 4;
                    507:                                        play->sw_code = ulinear8_to_linear16_mts;
                    508:                                        break;
                    509:                                case 2:
                    510:                                        play->factor = 2;
                    511:                                        play->sw_code = ulinear8_to_linear16;
                    512:                                        break;
                    513:                                default:
                    514:                                        return (EINVAL);
                    515:                                }
                    516:                                break;
                    517:                        case 16:
                    518:                                switch (play->channels) {
                    519:                                case 1:
                    520:                                        play->factor = 2;
                    521:                                        play->sw_code = change_sign16_swap_bytes_mts;
                    522:                                        break;
                    523:                                case 2:
                    524:                                        play->sw_code = change_sign16_swap_bytes;
                    525:                                        break;
                    526:                                default:
                    527:                                        return (EINVAL);
                    528:                                }
                    529:                                break;
                    530:                        default:
                    531:                                return (EINVAL);
                    532:                        }
                    533:                        break;
                    534:                default:
                    535:                        return (EINVAL);
                    536:                }
                    537:
                    538:                error = ac97_set_rate(co->codec_if, play, AUMODE_PLAY);
                    539:                if (error)
                    540:                        return (error);
                    541:        }
                    542:
                    543:        if (setmode & AUMODE_RECORD) {
                    544:                rec->factor = 1;
                    545:                rec->sw_code = 0;
                    546:                switch(rec->encoding) {
                    547:                case AUDIO_ENCODING_ULAW:
                    548:                        rec->sw_code = ulinear8_to_mulaw;
                    549:                        break;
                    550:                case AUDIO_ENCODING_SLINEAR_LE:
                    551:                        if (rec->precision == 8)
                    552:                                rec->sw_code = change_sign8;
                    553:                        break;
                    554:                case AUDIO_ENCODING_ULINEAR_LE:
                    555:                        if (rec->precision == 16)
                    556:                                rec->sw_code = change_sign16;
                    557:                        break;
                    558:                case AUDIO_ENCODING_ALAW:
                    559:                        rec->sw_code = ulinear8_to_alaw;
                    560:                        break;
                    561:                case AUDIO_ENCODING_SLINEAR_BE:
                    562:                        if (rec->precision == 16)
                    563:                                rec->sw_code = swap_bytes;
                    564:                        else
                    565:                                rec->sw_code = change_sign8;
                    566:                        break;
                    567:                case AUDIO_ENCODING_ULINEAR_BE:
                    568:                        if (rec->precision == 16)
                    569:                                rec->sw_code = swap_bytes_change_sign16;
                    570:                        break;
                    571:                default:
                    572:                        return (EINVAL);
                    573:                }
                    574:
                    575:                error = ac97_set_rate(co->codec_if, rec, AUMODE_RECORD);
                    576:                if (error)
                    577:                        return (error);
                    578:        }
                    579:
                    580:        return (0);
                    581: }
                    582:
                    583:
                    584: /* called to translate a requested blocksize to a hw-possible one */
                    585: int
                    586: auixp_round_blocksize(void *v, int blk)
                    587: {
                    588:
                    589:        blk = (blk + 0x1f) & ~0x1f;
                    590:        /* Be conservative; align to 32 bytes and maximise it to 64 kb */
                    591:        if (blk > 0x10000)
                    592:                blk = 0x10000;
                    593:
                    594:        return blk;
                    595: }
                    596:
                    597:
                    598: /*
                    599:  * allocate dma capable memory and record its information for later retrieval
                    600:  * when we program the dma chain itself. The trigger routines passes on the
                    601:  * kernel virtual address we return here as a reference to the mapping.
                    602:  */
                    603: void *
                    604: auixp_malloc(void *hdl, int direction, size_t size, int pool, int flags)
                    605: {
                    606:        struct auixp_codec *co;
                    607:        struct auixp_softc *sc;
                    608:        struct auixp_dma *dma;
                    609:        int error;
                    610:
                    611:        co = (struct auixp_codec *) hdl;
                    612:        sc = co->sc;
                    613:        /* get us a auixp_dma structure */
                    614:        dma = malloc(sizeof(*dma), pool, flags);
                    615:        if (!dma)
                    616:                return NULL;
                    617:
                    618:        /* get us a dma buffer itself */
                    619:        error = auixp_allocmem(sc, size, 16, dma);
                    620:        if (error) {
                    621:                free(dma, pool);
                    622:                printf("%s: auixp_malloc: not enough memory\n",
                    623:                    sc->sc_dev.dv_xname);
                    624:                return NULL;
                    625:        }
                    626:        SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain);
                    627:
                    628:        DPRINTF(("auixp_malloc: returning kern %p,   hw 0x%08x for %d bytes "
                    629:            "in %d segs\n", KERNADDR(dma), (u_int32_t) DMAADDR(dma), dma->size,
                    630:            dma->nsegs)
                    631:        );
                    632:
                    633:        return KERNADDR(dma);
                    634: }
                    635:
                    636: /*
                    637:  * free and release dma capable memory we allocated before and remove its
                    638:  * recording
                    639:  */
                    640: void
                    641: auixp_free(void *hdl, void *addr, int pool)
                    642: {
                    643:        struct auixp_codec *co;
                    644:        struct auixp_softc *sc;
                    645:        struct auixp_dma *dma;
                    646:
                    647:        co = (struct auixp_codec *) hdl;
                    648:        sc = co->sc;
                    649:        SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain) {
                    650:                if (KERNADDR(dma) == addr) {
                    651:                        SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,
                    652:                            dma_chain);
                    653:                        auixp_freemem(sc, dma);
                    654:                        free(dma, pool);
                    655:                        return;
                    656:                }
                    657:        }
                    658: }
                    659:
                    660: int
                    661: auixp_getdev(void *v, struct audio_device *adp)
                    662: {
                    663:        struct auixp_softc *sc = v;
                    664:        *adp = sc->sc_audev;
                    665:        return 0;
                    666: }
                    667:
                    668: /* pass request to AC'97 codec code */
                    669: int
                    670: auixp_set_port(void *hdl, mixer_ctrl_t *mc)
                    671: {
                    672:        struct auixp_codec *co;
                    673:
                    674:        co = (struct auixp_codec *) hdl;
                    675:        return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc);
                    676: }
                    677:
                    678:
                    679: /* pass request to AC'97 codec code */
                    680: int
                    681: auixp_get_port(void *hdl, mixer_ctrl_t *mc)
                    682: {
                    683:        struct auixp_codec *co;
                    684:
                    685:        co = (struct auixp_codec *) hdl;
                    686:        return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc);
                    687: }
                    688:
                    689: /* pass request to AC'97 codec code */
                    690: int
                    691: auixp_query_devinfo(void *hdl, mixer_devinfo_t *di)
                    692: {
                    693:        struct auixp_codec *co;
                    694:
                    695:        co = (struct auixp_codec *) hdl;
                    696:        return co->codec_if->vtbl->query_devinfo(co->codec_if, di);
                    697: }
                    698:
                    699:
                    700: size_t
                    701: auixp_round_buffersize(void *hdl, int direction, size_t bufsize)
                    702: {
                    703:
                    704:        /* XXX force maximum? i.e. 256 kb? */
                    705:        return bufsize;
                    706: }
                    707:
                    708:
                    709: int
                    710: auixp_get_props(void *hdl)
                    711: {
                    712:
                    713:        return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
                    714: }
                    715:
                    716:
                    717: /*
                    718:  * A dma descriptor has dma->nsegs segments defined in dma->segs set up when
                    719:  * we claimed the memory.
                    720:  *
                    721:  * Due to our demand for one contiguous DMA area, we only have one segment. A
                    722:  * c_dma structure is about 3 kb for the 256 entries we maximally program
                    723:  * -arbitrary limit AFAIK- so all is most likely to be in one segment/page
                    724:  * anyway.
                    725:  *
                    726:  * XXX ought to implement fragmented dma area XXX
                    727:  *
                    728:  * Note that _v variables depict kernel virtual addresses, _p variables depict
                    729:  * physical addresses.
                    730:  */
                    731: void
                    732: auixp_link_daisychain(struct auixp_softc *sc,
                    733:                struct auixp_dma *c_dma, struct auixp_dma *s_dma,
                    734:                int blksize, int blocks)
                    735: {
                    736:        atiixp_dma_desc_t *caddr_v, *next_caddr_v;
                    737:        u_int32_t caddr_p, next_caddr_p, saddr_p;
                    738:        int i;
                    739:
                    740:        /* just make sure we are not changing when its running */
                    741:        auixp_disable_dma(sc, c_dma);
                    742:
                    743:        /* setup dma chain start addresses */
                    744:        caddr_v = KERNADDR(c_dma);
                    745:        caddr_p = DMAADDR(c_dma);
                    746:        saddr_p = DMAADDR(s_dma);
                    747:
                    748:        /* program the requested number of blocks */
                    749:        for (i = 0; i < blocks; i++) {
                    750:                /* clear the block just in case */
                    751:                bzero(caddr_v, sizeof(atiixp_dma_desc_t));
                    752:
                    753:                /* round robin the chain dma addresses for its successor */
                    754:                next_caddr_v = caddr_v + 1;
                    755:                next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t);
                    756:
                    757:                if (i == blocks-1) {
                    758:                        next_caddr_v = KERNADDR(c_dma);
                    759:                        next_caddr_p = DMAADDR(c_dma);
                    760:                }
                    761:
                    762:                /* fill in the hardware dma chain descriptor in little-endian */
                    763:                caddr_v->addr   = htole32(saddr_p);
                    764:                caddr_v->status = htole16(0);
                    765:                caddr_v->size   = htole16((blksize >> 2)); /* in dwords (!!!) */
                    766:                caddr_v->next   = htole32(next_caddr_p);
                    767:
                    768:                /* advance slot */
                    769:                saddr_p += blksize;     /* XXX assuming contiguous XXX */
                    770:                caddr_v  = next_caddr_v;
                    771:                caddr_p  = next_caddr_p;
                    772:        }
                    773: }
                    774:
                    775:
                    776: int
                    777: auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
                    778: {
                    779:        struct auixp_dma *dma;
                    780:        int error;
                    781:
                    782:        /* allocate keeper of dma area */
                    783:        *dmap = NULL;
                    784:        dma = malloc(sizeof(*dma), M_DEVBUF, M_NOWAIT);
                    785:        if (!dma)
                    786:                return ENOMEM;
                    787:        bzero(dma, sizeof(*dma));
                    788:
                    789:        /* allocate for daisychain of IXP hardware-dma descriptors */
                    790:        error = auixp_allocmem(sc, DMA_DESC_CHAIN * sizeof(atiixp_dma_desc_t),
                    791:            16, dma);
                    792:        if (error) {
                    793:                printf("%s: can't malloc dma descriptor chain\n",
                    794:                    sc->sc_dev.dv_xname);
                    795:                free(dma, M_DEVBUF);
                    796:                return ENOMEM;
                    797:        }
                    798:
                    799:        /* return info and initialise structure */
                    800:        dma->intr    = NULL;
                    801:        dma->intrarg = NULL;
                    802:
                    803:        *dmap = dma;
                    804:        return 0;
                    805: }
                    806:
                    807:
                    808: /* program dma chain in its link address descriptor */
                    809: void
                    810: auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma)
                    811: {
                    812:        bus_space_tag_t    iot;
                    813:        bus_space_handle_t ioh;
                    814:        u_int32_t value;
                    815:
                    816:        iot = sc->sc_iot;
                    817:        ioh = sc->sc_ioh;
                    818:        /* get hardware start address of DMA chain and set valid-flag in it */
                    819:        /* XXX always at start? XXX */
                    820:        value = DMAADDR(dma);
                    821:        value = value | ATI_REG_LINKPTR_EN;
                    822:
                    823:        /* reset linkpointer */
                    824:        bus_space_write_4(iot, ioh, dma->linkptr, 0);
                    825:
                    826:        /* reset this DMA engine */
                    827:        auixp_disable_dma(sc, dma);
                    828:        auixp_enable_dma(sc, dma);
                    829:
                    830:        /* program new DMA linkpointer */
                    831:        bus_space_write_4(iot, ioh, dma->linkptr, value);
                    832: }
                    833:
                    834:
                    835: /* called from interrupt code to signal end of one dma-slot */
                    836: void
                    837: auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma)
                    838: {
                    839:
                    840:        /* be very paranoid */
                    841:        if (!dma)
                    842:                panic("auixp: update: dma = NULL");
                    843:        if (!dma->intr)
                    844:                panic("auixp: update: dma->intr = NULL");
                    845:
                    846:        /* request more input from upper layer */
                    847:        (*dma->intr)(dma->intrarg);
                    848: }
                    849:
                    850:
                    851: /*
                    852:  * The magic `busbusy' bit that needs to be set when dma is active; allowing
                    853:  * busmastering?
                    854:  */
                    855: void
                    856: auixp_update_busbusy(struct auixp_softc *sc)
                    857: {
                    858:        bus_space_tag_t    iot;
                    859:        bus_space_handle_t ioh;
                    860:        u_int32_t value;
                    861:        int running;
                    862:
                    863:        iot = sc->sc_iot;
                    864:        ioh = sc->sc_ioh;
                    865:        /* set bus-busy flag when either recording or playing is performed */
                    866:        value  = bus_space_read_4(iot, ioh, ATI_REG_IER);
                    867:        value &= ~ATI_REG_IER_SET_BUS_BUSY;
                    868:
                    869:        running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running));
                    870:        if (running)
                    871:                value |= ATI_REG_IER_SET_BUS_BUSY;
                    872:
                    873:        bus_space_write_4(iot, ioh, ATI_REG_IER, value);
                    874:
                    875: }
                    876:
                    877:
                    878: /*
                    879:  * Called from upper audio layer to request playing audio, only called once;
                    880:  * audio is refilled by calling the intr() function when space is available
                    881:  * again.
                    882:  */
                    883: /* XXX almost literally a copy of trigger-input; could be factorised XXX */
                    884: int
                    885: auixp_trigger_output(void *hdl, void *start, void *end, int blksize,
                    886:     void (*intr)(void *), void *intrarg, struct audio_params *param)
                    887: {
                    888:        struct auixp_codec *co;
                    889:        struct auixp_softc *sc;
                    890:        struct auixp_dma   *chain_dma;
                    891:        struct auixp_dma   *sound_dma;
                    892:        u_int32_t blocks;
                    893:
                    894:        co = (struct auixp_codec *) hdl;
                    895:        sc = co->sc;
                    896:        chain_dma = sc->sc_output_dma;
                    897:        /* add functions to call back */
                    898:        chain_dma->intr    = intr;
                    899:        chain_dma->intrarg = intrarg;
                    900:
                    901:        /*
                    902:         * Program output DMA chain with blocks from [start...end] with
                    903:         * blksize fragments.
                    904:         *
                    905:         * NOTE, we can assume its in one block since we asked for it to be in
                    906:         * one contiguous blob; XXX change this? XXX
                    907:         */
                    908:        blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
                    909:
                    910:        /* lookup `start' address in our list of DMA area's */
                    911:        SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
                    912:                if (KERNADDR(sound_dma) == start)
                    913:                        break;
                    914:        }
                    915:
                    916:        /* not ours ? then bail out */
                    917:        if (!sound_dma) {
                    918:                printf("%s: auixp_trigger_output: bad sound addr %p\n",
                    919:                    sc->sc_dev.dv_xname, start);
                    920:                return EINVAL;
                    921:        }
                    922:
                    923:        /* link round-robin daisychain and program hardware */
                    924:        auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
                    925:        auixp_program_dma_chain(sc, chain_dma);
                    926:
                    927:        /* mark we are now able to run now */
                    928:        chain_dma->running = 1;
                    929:
                    930:        /* update bus-flags; XXX programs more flags XXX */
                    931:        auixp_update_busbusy(sc);
                    932:
                    933:        /* callbacks happen in interrupt routine */
                    934:        return 0;
                    935: }
                    936:
                    937:
                    938: /* halt output of audio, just disable its dma and update bus state */
                    939: int
                    940: auixp_halt_output(void *hdl)
                    941: {
                    942:        struct auixp_codec *co;
                    943:        struct auixp_softc *sc;
                    944:        struct auixp_dma   *dma;
                    945:
                    946:        co  = (struct auixp_codec *) hdl;
                    947:        sc  = co->sc;
                    948:        dma = sc->sc_output_dma;
                    949:        auixp_disable_dma(sc, dma);
                    950:
                    951:        dma->running = 0;
                    952:        auixp_update_busbusy(sc);
                    953:
                    954:        return 0;
                    955: }
                    956:
                    957:
                    958: /* XXX almost literally a copy of trigger-output; could be factorised XXX */
                    959: int
                    960: auixp_trigger_input(void *hdl, void *start, void *end, int blksize,
                    961:     void (*intr)(void *), void *intrarg, struct audio_params *param)
                    962: {
                    963:        struct auixp_codec *co;
                    964:        struct auixp_softc *sc;
                    965:        struct auixp_dma   *chain_dma;
                    966:        struct auixp_dma   *sound_dma;
                    967:        u_int32_t blocks;
                    968:
                    969:        co = (struct auixp_codec *) hdl;
                    970:        sc = co->sc;
                    971:        chain_dma = sc->sc_input_dma;
                    972:        /* add functions to call back */
                    973:        chain_dma->intr    = intr;
                    974:        chain_dma->intrarg = intrarg;
                    975:
                    976:        /*
                    977:         * Program output DMA chain with blocks from [start...end] with
                    978:         * blksize fragments.
                    979:         *
                    980:         * NOTE, we can assume its in one block since we asked for it to be in
                    981:         * one contiguous blob; XXX change this? XXX
                    982:         */
                    983:        blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
                    984:
                    985:        /* lookup `start' address in our list of DMA area's */
                    986:        SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain) {
                    987:                if (KERNADDR(sound_dma) == start)
                    988:                        break;
                    989:        }
                    990:
                    991:        /* not ours ? then bail out */
                    992:        if (!sound_dma) {
                    993:                printf("%s: auixp_trigger_input: bad sound addr %p\n",
                    994:                    sc->sc_dev.dv_xname, start);
                    995:                return EINVAL;
                    996:        }
                    997:
                    998:        /* link round-robin daisychain and program hardware */
                    999:        auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
                   1000:        auixp_program_dma_chain(sc, chain_dma);
                   1001:
                   1002:        /* mark we are now able to run now */
                   1003:        chain_dma->running = 1;
                   1004:
                   1005:        /* update bus-flags; XXX programs more flags XXX */
                   1006:        auixp_update_busbusy(sc);
                   1007:
                   1008:        /* callbacks happen in interrupt routine */
                   1009:        return 0;
                   1010: }
                   1011:
                   1012:
                   1013: /* halt sampling audio, just disable its dma and update bus state */
                   1014: int
                   1015: auixp_halt_input(void *hdl)
                   1016: {
                   1017:        struct auixp_codec *co;
                   1018:        struct auixp_softc *sc;
                   1019:        struct auixp_dma   *dma;
                   1020:
                   1021:        co = (struct auixp_codec *) hdl;
                   1022:        sc = co->sc;
                   1023:        dma = sc->sc_input_dma;
                   1024:        auixp_disable_dma(sc, dma);
                   1025:
                   1026:        dma->running = 0;
                   1027:        auixp_update_busbusy(sc);
                   1028:
                   1029:        return 0;
                   1030: }
                   1031:
                   1032:
                   1033: /*
                   1034:  * IXP audio interrupt handler
                   1035:  *
                   1036:  * note that we return the number of bits handled; the return value is not
                   1037:  * documented but I saw it implemented in other drivers. Probably returning a
                   1038:  * value > 0 means "I've dealt with it"
                   1039:  *
                   1040:  */
                   1041: int
                   1042: auixp_intr(void *softc)
                   1043: {
                   1044:        struct auixp_softc *sc;
                   1045:        bus_space_tag_t    iot;
                   1046:        bus_space_handle_t ioh;
                   1047:        u_int32_t status, enable, detected_codecs;
                   1048:        int ret;
                   1049:
                   1050:        sc = softc;
                   1051:        iot = sc->sc_iot;
                   1052:        ioh = sc->sc_ioh;
                   1053:        ret = 0;
                   1054:        /* get status from the interrupt status register */
                   1055:        status = bus_space_read_4(iot, ioh, ATI_REG_ISR);
                   1056:
                   1057:        if (status == 0)
                   1058:                return 0;
                   1059:
                   1060:        DPRINTF(("%s: (status = %x)\n", sc->sc_dev.dv_xname, status));
                   1061:
                   1062:        /* check DMA UPDATE flags for input & output */
                   1063:        if (status & ATI_REG_ISR_IN_STATUS) {
                   1064:                ret++; DPRINTF(("IN_STATUS\n"));
                   1065:                auixp_dma_update(sc, sc->sc_input_dma);
                   1066:        }
                   1067:        if (status & ATI_REG_ISR_OUT_STATUS) {
                   1068:                ret++; DPRINTF(("OUT_STATUS\n"));
                   1069:                auixp_dma_update(sc, sc->sc_output_dma);
                   1070:        }
                   1071:
                   1072:        /* XXX XRUN flags not used/needed yet; should i implement it? XXX */
                   1073:        /* acknowledge the interrupts nevertheless */
                   1074:        if (status & ATI_REG_ISR_IN_XRUN) {
                   1075:                ret++; DPRINTF(("IN_XRUN\n"));
                   1076:                /* auixp_dma_xrun(sc, sc->sc_input_dma);  */
                   1077:        }
                   1078:        if (status & ATI_REG_ISR_OUT_XRUN) {
                   1079:                ret++; DPRINTF(("OUT_XRUN\n"));
                   1080:                /* auixp_dma_xrun(sc, sc->sc_output_dma); */
                   1081:        }
                   1082:
                   1083:        /* check if we are looking for codec detection */
                   1084:        if (status & CODEC_CHECK_BITS) {
                   1085:                ret++;
                   1086:                /* mark missing codecs as not ready */
                   1087:                detected_codecs = status & CODEC_CHECK_BITS;
                   1088:                sc->sc_codec_not_ready_bits |= detected_codecs;
                   1089:
                   1090:                /* disable detected interrupt sources */
                   1091:                enable  = bus_space_read_4(iot, ioh, ATI_REG_IER);
                   1092:                enable &= ~detected_codecs;
                   1093:                bus_space_write_4(iot, ioh, ATI_REG_IER, enable);
                   1094:        }
                   1095:
                   1096:        /* acknowledge interrupt sources */
                   1097:        bus_space_write_4(iot, ioh, ATI_REG_ISR, status);
                   1098:
                   1099:        return ret;
                   1100: }
                   1101:
                   1102:
                   1103: /* allocate memory for dma purposes; on failure of any of the steps, roll back */
                   1104: int
                   1105: auixp_allocmem(struct auixp_softc *sc, size_t size,
                   1106:               size_t align, struct auixp_dma *dma)
                   1107: {
                   1108:        int error;
                   1109:
                   1110:        /* remember size */
                   1111:        dma->size = size;
                   1112:
                   1113:        /* allocate DMA safe memory but in just one segment for now :( */
                   1114:        error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,
                   1115:            dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,
                   1116:            BUS_DMA_NOWAIT);
                   1117:        if (error)
                   1118:                return error;
                   1119:
                   1120:        /*
                   1121:         * map allocated memory into kernel virtual address space and keep it
                   1122:         * coherent with the CPU.
                   1123:         */
                   1124:        error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,
                   1125:                                &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
                   1126:        if (error)
                   1127:                goto free;
                   1128:
                   1129:        /* allocate associated dma handle and initialize it. */
                   1130:        error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,
                   1131:                                  BUS_DMA_NOWAIT, &dma->map);
                   1132:        if (error)
                   1133:                goto unmap;
                   1134:
                   1135:        /*
                   1136:         * load the dma handle with mappings for a dma transfer; all pages
                   1137:         * need to be wired.
                   1138:         */
                   1139:        error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,
                   1140:                                BUS_DMA_NOWAIT);
                   1141:        if (error)
                   1142:                goto destroy;
                   1143:
                   1144:        return 0;
                   1145:
                   1146: destroy:
                   1147:        bus_dmamap_destroy(sc->sc_dmat, dma->map);
                   1148: unmap:
                   1149:        bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size);
                   1150: free:
                   1151:        bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs);
                   1152:
                   1153:        return error;
                   1154: }
                   1155:
                   1156:
                   1157: /* undo dma mapping and release memory allocated */
                   1158: int
                   1159: auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p)
                   1160: {
                   1161:
                   1162:        bus_dmamap_unload(sc->sc_dmat, p->map);
                   1163:        bus_dmamap_destroy(sc->sc_dmat, p->map);
                   1164:        bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
                   1165:        bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
                   1166:
                   1167:        return 0;
                   1168: }
                   1169:
                   1170:
                   1171: /* memory map dma memory */
                   1172: paddr_t
                   1173: auixp_mappage(void *hdl, void *mem, off_t off, int prot)
                   1174: {
                   1175:        struct auixp_codec *co;
                   1176:        struct auixp_softc *sc;
                   1177:        struct auixp_dma *p;
                   1178:
                   1179:        co = (struct auixp_codec *) hdl;
                   1180:        sc  = co->sc;
                   1181:        /* for sanity */
                   1182:        if (off < 0)
                   1183:                return -1;
                   1184:
                   1185:        /* look up allocated DMA area */
                   1186:        SLIST_FOREACH(p, &sc->sc_dma_list, dma_chain) {
                   1187:                if (KERNADDR(p) == mem)
                   1188:                        break;
                   1189:        }
                   1190:
                   1191:        /* have we found it ? */
                   1192:        if (!p)
                   1193:                return -1;
                   1194:
                   1195:        /* return mmap'd region */
                   1196:        return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs,
                   1197:            off, prot, BUS_DMA_WAITOK);
                   1198: }
                   1199:
                   1200: int
                   1201: auixp_match(struct device *dev, void *match, void *aux)
                   1202: {
                   1203:        return (pci_matchbyid((struct pci_attach_args *)aux, auixp_pci_devices,
                   1204:            sizeof(auixp_pci_devices)/sizeof(auixp_pci_devices[0])));
                   1205: }
                   1206:
                   1207: void
                   1208: auixp_attach(struct device *parent, struct device *self, void *aux)
                   1209: {
                   1210:        struct auixp_softc *sc;
                   1211:        struct pci_attach_args *pa;
                   1212:        pcitag_t tag;
                   1213:        pci_chipset_tag_t pc;
                   1214:        pci_intr_handle_t ih;
                   1215:        const char *intrstr;
                   1216:        int len;
                   1217:
                   1218:        sc = (struct auixp_softc *)self;
                   1219:        pa = (struct pci_attach_args *)aux;
                   1220:        tag = pa->pa_tag;
                   1221:        pc = pa->pa_pc;
                   1222:
                   1223:        /* map memory; its not sized -> what is the size? max PCI slot size? */
                   1224:        if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_MEM, 0,
                   1225:            &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
                   1226:                printf(": can't map memory space\n");
                   1227:                return;
                   1228:        }
                   1229:
                   1230:        /* Initialize softc */
                   1231:        sc->sc_tag = tag;
                   1232:        sc->sc_pct = pc;
                   1233:        sc->sc_dmat = pa->pa_dmat;
                   1234:        SLIST_INIT(&sc->sc_dma_list);
                   1235:
                   1236:        /* get us the auixp_dma structures */
                   1237:        auixp_allocate_dma_chain(sc, &sc->sc_output_dma);
                   1238:        auixp_allocate_dma_chain(sc, &sc->sc_input_dma);
                   1239:
                   1240:        /* when that fails we are dead in the water */
                   1241:        if (!sc->sc_output_dma || !sc->sc_input_dma)
                   1242:                return;
                   1243:
                   1244:        /* fill in the missing details about the dma channels. */
                   1245:
                   1246:        /* for output */
                   1247:        sc->sc_output_dma->linkptr        = ATI_REG_OUT_DMA_LINKPTR;
                   1248:        sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN |
                   1249:                                            ATI_REG_CMD_SEND_EN;
                   1250:        /* have spdif? then this too! XXX not seeing LED yet! XXX */
                   1251:        if (sc->has_spdif)
                   1252:                sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN;
                   1253:
                   1254:        /* and for input */
                   1255:        sc->sc_input_dma->linkptr         = ATI_REG_IN_DMA_LINKPTR;
                   1256:        sc->sc_input_dma->dma_enable_bit  = ATI_REG_CMD_IN_DMA_EN  |
                   1257:                                            ATI_REG_CMD_RECEIVE_EN;
                   1258:
                   1259: #if 0
                   1260:        /* could preliminary program DMA chain */
                   1261:        auixp_program_dma_chain(sc, sc->sc_output_dma);
                   1262:        auixp_program_dma_chain(sc, sc->sc_input_dma);
                   1263: #endif
                   1264:
                   1265:        if (pci_intr_map(pa, &ih)) {
                   1266:                printf(": can't map interrupt\n");
                   1267:                return;
                   1268:        }
                   1269:        intrstr = pci_intr_string(pc, ih);
                   1270:        sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auixp_intr, sc,
                   1271:            sc->sc_dev.dv_xname);
                   1272:        if (sc->sc_ih == NULL) {
                   1273:                printf(": can't establish interrupt");
                   1274:                if (intrstr != NULL)
                   1275:                        printf(" at %s", intrstr);
                   1276:                printf("\n");
                   1277:                return;
                   1278:        }
                   1279:        printf(": %s\n", intrstr);
                   1280:
                   1281:        strlcpy(sc->sc_audev.name, "ATI IXP AC97", sizeof sc->sc_audev.name);
                   1282:        snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
                   1283:            PCI_REVISION(pa->pa_class));
                   1284:        strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
                   1285:            sizeof sc->sc_audev.config);
                   1286:
                   1287:        /* power up chip */
                   1288:        auixp_power(sc, PCI_PMCSR_STATE_D0);
                   1289:
                   1290:        /* init chip */
                   1291:        if (auixp_init(sc) == -1) {
                   1292:                printf("%s: auixp_attach: unable to initialize the card\n",
                   1293:                    sc->sc_dev.dv_xname);
                   1294:                return;
                   1295:        }
                   1296:
                   1297:        /* XXX set up power hooks; not implemented yet XXX */
                   1298:
                   1299:        len = 1;        /* shut up gcc */
                   1300: #ifdef notyet
                   1301:        /* create suspend save area */
                   1302:        len = sizeof(u_int16_t) * (ESA_REV_B_CODE_MEMORY_LENGTH
                   1303:            + ESA_REV_B_DATA_MEMORY_LENGTH + 1);
                   1304:        sc->savemem = (u_int16_t *)malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
                   1305:        if (sc->savemem == NULL) {
                   1306:                printf("%s: unable to allocate suspend buffer\n",
                   1307:                    sc->sc_dev.dv_xname);
                   1308:                return;
                   1309:        }
                   1310:
                   1311:        sc->powerhook = powerhook_establish(auixp_powerhook, sc);
                   1312:        if (sc->powerhook == NULL)
                   1313:                printf("%s: WARNING: unable to establish powerhook\n",
                   1314:                    sc->sc_dev.dv_xname);
                   1315:
                   1316: #endif
                   1317:
                   1318:        /*
                   1319:         * delay further configuration of codecs and audio after interrupts
                   1320:         * are enabled.
                   1321:         */
                   1322:        mountroothook_establish(auixp_post_config, self);
                   1323: }
                   1324:
                   1325: /* called from autoconfigure system when interrupts are enabled */
                   1326: void
                   1327: auixp_post_config(void *self)
                   1328: {
                   1329:        struct auixp_softc *sc;
                   1330:        struct auixp_codec *codec;
                   1331:        int codec_nr;
                   1332:
                   1333:        sc = (struct auixp_softc *)self;
                   1334:        /* detect the AC97 codecs */
                   1335:        auixp_autodetect_codecs(sc);
                   1336:
                   1337: #if notyet
                   1338:        /* copy formats and invalidate entries not suitable for codec0 */
                   1339:        sc->has_4ch   = AC97_IS_4CH(codec->codec_if);
                   1340:        sc->has_6ch   = AC97_IS_6CH(codec->codec_if);
                   1341:        sc->is_fixed  = AC97_IS_FIXED_RATE(codec->codec_if);
                   1342:        sc->has_spdif = AC97_HAS_SPDIF(codec->codec_if);
                   1343: #endif
                   1344:
                   1345:        /* attach audio devices for all detected codecs */
                   1346:        for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
                   1347:                codec = &sc->sc_codec[codec_nr];
                   1348:                if (codec->present)
                   1349:                        audio_attach_mi(&auixp_hw_if, codec, &sc->sc_dev);
                   1350:        }
                   1351:
                   1352:        /* done! now enable all interrupts we can service */
                   1353:        auixp_enable_interrupts(sc);
                   1354: }
                   1355:
                   1356: void
                   1357: auixp_enable_interrupts(struct auixp_softc *sc)
                   1358: {
                   1359:        bus_space_tag_t     iot;
                   1360:        bus_space_handle_t  ioh;
                   1361:        u_int32_t value;
                   1362:
                   1363:        iot = sc->sc_iot;
                   1364:        ioh = sc->sc_ioh;
                   1365:        /* clear all pending */
                   1366:        bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
                   1367:
                   1368:        /* enable all relevant interrupt sources we can handle */
                   1369:        value = bus_space_read_4(iot, ioh, ATI_REG_IER);
                   1370:
                   1371:        value |= ATI_REG_IER_IO_STATUS_EN;
                   1372: #ifdef notyet
                   1373:        value |= ATI_REG_IER_IN_XRUN_EN;
                   1374:        value |= ATI_REG_IER_OUT_XRUN_EN;
                   1375:
                   1376:        value |= ATI_REG_IER_SPDIF_XRUN_EN;
                   1377:        value |= ATI_REG_IER_SPDF_STATUS_EN;
                   1378: #endif
                   1379:
                   1380:        bus_space_write_4(iot, ioh, ATI_REG_IER, value);
                   1381: }
                   1382:
                   1383: void
                   1384: auixp_disable_interrupts(struct auixp_softc *sc)
                   1385: {
                   1386:        bus_space_tag_t     iot;
                   1387:        bus_space_handle_t  ioh;
                   1388:
                   1389:        iot = sc->sc_iot;
                   1390:        ioh = sc->sc_ioh;
                   1391:        /* disable all interrupt sources */
                   1392:        bus_space_write_4(iot, ioh, ATI_REG_IER, 0);
                   1393:
                   1394:        /* clear all pending */
                   1395:        bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff);
                   1396: }
                   1397:
                   1398: /* dismantle what we've set up by undoing setup */
                   1399: int
                   1400: auixp_detach(struct device *self, int flags)
                   1401: {
                   1402:        struct auixp_softc *sc;
                   1403:
                   1404:        sc = (struct auixp_softc *)self;
                   1405:        /* XXX shouldn't we just reset the chip? XXX */
                   1406:        /*
                   1407:         * should we explicitly disable interrupt generation and acknowledge
                   1408:         * what's left on? better be safe than sorry.
                   1409:         */
                   1410:        auixp_disable_interrupts(sc);
                   1411:
                   1412:        /* tear down .... */
                   1413:        config_detach(&sc->sc_dev, flags);      /* XXX OK? XXX */
                   1414:
                   1415:        if (sc->sc_ih != NULL)
                   1416:                pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
                   1417:        if (sc->sc_ios)
                   1418:                bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
                   1419:
                   1420:        if (sc->savemem)
                   1421:                free(sc->savemem, M_DEVBUF);
                   1422:
                   1423:        return 0;
                   1424: }
                   1425:
                   1426:
                   1427: /*
                   1428:  * codec handling
                   1429:  *
                   1430:  * IXP audio support can have upto 3 codecs! are they chained ? or
                   1431:  * alternative outlets with the same audio feed i.e. with different mixer
                   1432:  * settings? XXX does NetBSD support more than one audio codec? XXX
                   1433:  */
                   1434:
                   1435:
                   1436: int
                   1437: auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if)
                   1438: {
                   1439:        struct auixp_codec *ixp_codec;
                   1440:
                   1441:        ixp_codec = aux;
                   1442:        ixp_codec->codec_if = codec_if;
                   1443:        ixp_codec->present  = 1;
                   1444:
                   1445:        return 0;
                   1446: }
                   1447:
                   1448: int
                   1449: auixp_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
                   1450: {
                   1451:        struct auixp_codec *co;
                   1452:        struct auixp_softc *sc;
                   1453:        bus_space_tag_t     iot;
                   1454:        bus_space_handle_t  ioh;
                   1455:        u_int32_t data;
                   1456:        int timeout;
                   1457:
                   1458:        co  = aux;
                   1459:        sc  = co->sc;
                   1460:        iot = sc->sc_iot;
                   1461:        ioh = sc->sc_ioh;
                   1462:        if (auixp_wait_for_codecs(sc, "read_codec"))
                   1463:                return 0xffff;
                   1464:
                   1465:        /* build up command for reading codec register */
                   1466:        data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
                   1467:                ATI_REG_PHYS_OUT_ADDR_EN |
                   1468:                ATI_REG_PHYS_OUT_RW |
                   1469:                co->codec_nr;
                   1470:
                   1471:        bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data);
                   1472:
                   1473:        if (auixp_wait_for_codecs(sc, "read_codec"))
                   1474:                return 0xffff;
                   1475:
                   1476:        /* wait until codec info is clocked in */
                   1477:        timeout = 500;          /* 500*2 usec -> 0.001 sec */
                   1478:        do {
                   1479:                data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR);
                   1480:                if (data & ATI_REG_PHYS_IN_READ_FLAG) {
                   1481:                        DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n",
                   1482:                                reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT));
                   1483:                        *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT;
                   1484:                        return 0;
                   1485:                }
                   1486:                DELAY(2);
                   1487:                timeout--;
                   1488:        } while (timeout > 0);
                   1489:
                   1490:        if (reg < 0x7c)
                   1491:                printf("%s: codec read timeout! (reg %x)\n",
                   1492:                    sc->sc_dev.dv_xname, reg);
                   1493:
                   1494:        return 0xffff;
                   1495: }
                   1496:
                   1497: int
                   1498: auixp_write_codec(void *aux, u_int8_t reg, u_int16_t data)
                   1499: {
                   1500:        struct auixp_codec *co;
                   1501:        struct auixp_softc *sc;
                   1502:        bus_space_tag_t     iot;
                   1503:        bus_space_handle_t  ioh;
                   1504:        u_int32_t value;
                   1505:
                   1506:        DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data));
                   1507:        co  = aux;
                   1508:        sc  = co->sc;
                   1509:        iot = sc->sc_iot;
                   1510:        ioh = sc->sc_ioh;
                   1511:        if (auixp_wait_for_codecs(sc, "write_codec"))
                   1512:                return -1;
                   1513:
                   1514:        /* build up command for writing codec register */
                   1515:        value = (((u_int32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT) |
                   1516:                (((u_int32_t)  reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT) |
                   1517:                ATI_REG_PHYS_OUT_ADDR_EN |
                   1518:                co->codec_nr;
                   1519:
                   1520:        bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value);
                   1521:
                   1522:        return 0;
                   1523: }
                   1524:
                   1525: void
                   1526: auixp_reset_codec(void *aux)
                   1527: {
                   1528:
                   1529:        /* nothing to be done? */
                   1530: }
                   1531:
                   1532: enum ac97_host_flags
                   1533: auixp_flags_codec(void *aux)
                   1534: {
                   1535:        struct auixp_codec *ixp_codec;
                   1536:
                   1537:        ixp_codec = aux;
                   1538:        return ixp_codec->codec_flags;
                   1539: }
                   1540:
                   1541: int
                   1542: auixp_wait_for_codecs(struct auixp_softc *sc, const char *func)
                   1543: {
                   1544:        bus_space_tag_t      iot;
                   1545:        bus_space_handle_t   ioh;
                   1546:        u_int32_t value;
                   1547:        int timeout;
                   1548:
                   1549:        iot = sc->sc_iot;
                   1550:        ioh = sc->sc_ioh;
                   1551:        /* wait until all codec transfers are done */
                   1552:        timeout = 500;          /* 500*2 usec -> 0.001 sec */
                   1553:        do {
                   1554:                value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR);
                   1555:                if ((value & ATI_REG_PHYS_OUT_ADDR_EN) == 0)
                   1556:                        return 0;
                   1557:
                   1558:                DELAY(2);
                   1559:                timeout--;
                   1560:        } while (timeout > 0);
                   1561:
                   1562:        printf("%s: %s: timed out\n", func, sc->sc_dev.dv_xname);
                   1563:        return -1;
                   1564: }
                   1565:
                   1566: void
                   1567: auixp_autodetect_codecs(struct auixp_softc *sc)
                   1568: {
                   1569:        bus_space_tag_t      iot;
                   1570:        bus_space_handle_t   ioh;
                   1571:        pcireg_t subdev;
                   1572:        struct auixp_codec  *codec;
                   1573:        int timeout, codec_nr;
                   1574:
                   1575:        iot = sc->sc_iot;
                   1576:        ioh = sc->sc_ioh;
                   1577:        subdev = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_SUBSYS_ID_REG);
                   1578:
                   1579:        /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */
                   1580:        sc->sc_codec_not_ready_bits = 0;
                   1581:        sc->sc_num_codecs = 0;
                   1582:
                   1583:        /* enable all codecs to interrupt as well as the new frame interrupt */
                   1584:        bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS);
                   1585:
                   1586:        /* wait for the interrupts to happen */
                   1587:        timeout = 100;          /* 100.000 usec -> 0.1 sec */
                   1588:
                   1589:        while (timeout > 0) {
                   1590:                DELAY(1000);
                   1591:                if (sc->sc_codec_not_ready_bits)
                   1592:                        break;
                   1593:                timeout--;
                   1594:        }
                   1595:
                   1596:        if (timeout == 0)
                   1597:                printf("%s: WARNING: timeout during codec detection; "
                   1598:                        "codecs might be present but haven't interrupted\n",
                   1599:                        sc->sc_dev.dv_xname);
                   1600:
                   1601:        /* disable all interrupts for now */
                   1602:        auixp_disable_interrupts(sc);
                   1603:
                   1604:        /* Attach AC97 host interfaces */
                   1605:        for (codec_nr = 0; codec_nr < ATI_IXP_CODECS; codec_nr++) {
                   1606:                codec = &sc->sc_codec[codec_nr];
                   1607:                bzero(codec, sizeof(struct auixp_codec));
                   1608:
                   1609:                codec->sc       = sc;
                   1610:                codec->codec_nr = codec_nr;
                   1611:                codec->present  = 0;
                   1612:
                   1613:                codec->host_if.arg    = codec;
                   1614:                codec->host_if.attach = auixp_attach_codec;
                   1615:                codec->host_if.read   = auixp_read_codec;
                   1616:                codec->host_if.write  = auixp_write_codec;
                   1617:                codec->host_if.reset  = auixp_reset_codec;
                   1618:                codec->host_if.flags  = auixp_flags_codec;
                   1619:                switch (subdev) {
                   1620:                case 0x1311462: /* MSI S270 */
                   1621:                        codec->codec_flags = AC97_HOST_DONT_ENABLE_SPDIF;
                   1622:                        break;
                   1623:                }
                   1624:        }
                   1625:
                   1626:        if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY)) {
                   1627:                /* codec 0 present */
                   1628:                DPRINTF(("auixp : YAY! codec 0 present!\n"));
                   1629:                if (ac97_attach(&sc->sc_codec[0].host_if) == 0)
                   1630:                        sc->sc_num_codecs++;
                   1631:        }
                   1632:
                   1633: #ifdef notyet
                   1634:        if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY)) {
                   1635:                /* codec 1 present */
                   1636:                DPRINTF(("auixp : YAY! codec 1 present!\n"));
                   1637:                if (ac97_attach(&sc->sc_codec[1].host_if, &sc->sc_dev) == 0)
                   1638:                        sc->sc_num_codecs++;
                   1639:        }
                   1640:
                   1641:        if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY)) {
                   1642:                /* codec 2 present */
                   1643:                DPRINTF(("auixp : YAY! codec 2 present!\n"));
                   1644:                if (ac97_attach(&sc->sc_codec[2].host_if, &sc->sc_dev) == 0)
                   1645:                        sc->sc_num_codecs++;
                   1646:        }
                   1647: #endif
                   1648:
                   1649:        if (sc->sc_num_codecs == 0) {
                   1650:                printf("%s: no codecs detected or initialised\n",
                   1651:                    sc->sc_dev.dv_xname);
                   1652:                return;
                   1653:        }
                   1654: }
                   1655:
                   1656: void
                   1657: auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
                   1658: {
                   1659:        bus_space_tag_t      iot;
                   1660:        bus_space_handle_t   ioh;
                   1661:        u_int32_t value;
                   1662:
                   1663:        iot = sc->sc_iot;
                   1664:        ioh = sc->sc_ioh;
                   1665:        /* lets not stress the DMA engine more than necessary */
                   1666:        value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1667:        if (value & dma->dma_enable_bit) {
                   1668:                value &= ~dma->dma_enable_bit;
                   1669:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1670:        }
                   1671: }
                   1672:
                   1673: void
                   1674: auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
                   1675: {
                   1676:        bus_space_tag_t      iot;
                   1677:        bus_space_handle_t   ioh;
                   1678:        u_int32_t value;
                   1679:
                   1680:        iot = sc->sc_iot;
                   1681:        ioh = sc->sc_ioh;
                   1682:        /* lets not stress the DMA engine more than necesssary */
                   1683:        value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1684:        if (!(value & dma->dma_enable_bit)) {
                   1685:                value |= dma->dma_enable_bit;
                   1686:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1687:        }
                   1688: }
                   1689:
                   1690: void
                   1691: auixp_reset_aclink(struct auixp_softc *sc)
                   1692: {
                   1693:        bus_space_tag_t      iot;
                   1694:        bus_space_handle_t   ioh;
                   1695:        u_int32_t value, timeout;
                   1696:
                   1697:        iot = sc->sc_iot;
                   1698:        ioh = sc->sc_ioh;
                   1699:
                   1700:        /* if power is down, power it up */
                   1701:        value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1702:        if (value & ATI_REG_CMD_POWERDOWN) {
                   1703:                printf("%s: powering up\n", sc->sc_dev.dv_xname);
                   1704:
                   1705:                /* explicitly enable power */
                   1706:                value &= ~ATI_REG_CMD_POWERDOWN;
                   1707:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1708:
                   1709:                /* have to wait at least 10 usec for it to initialise */
                   1710:                DELAY(20);
                   1711:        };
                   1712:
                   1713:        printf("%s: soft resetting aclink\n", sc->sc_dev.dv_xname);
                   1714:
                   1715:        /* perform a soft reset */
                   1716:        value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1717:        value |= ATI_REG_CMD_AC_SOFT_RESET;
                   1718:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1719:
                   1720:        /* need to read the CMD reg and wait aprox. 10 usec to init */
                   1721:        value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1722:        DELAY(20);
                   1723:
                   1724:        /* clear soft reset flag again */
                   1725:        value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1726:        value &= ~ATI_REG_CMD_AC_SOFT_RESET;
                   1727:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1728:
                   1729:        /* check if the ac-link is working; reset device otherwise */
                   1730:        timeout = 10;
                   1731:        value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1732:        while (!(value & ATI_REG_CMD_ACLINK_ACTIVE)) {
                   1733:                printf("%s: not up; resetting aclink hardware\n",
                   1734:                                sc->sc_dev.dv_xname);
                   1735:
                   1736:                /* dip aclink reset but keep the acsync */
                   1737:                value &= ~ATI_REG_CMD_AC_RESET;
                   1738:                value |=  ATI_REG_CMD_AC_SYNC;
                   1739:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1740:
                   1741:                /* need to read CMD again and wait again (clocking in issue?) */
                   1742:                value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1743:                DELAY(20);
                   1744:
                   1745:                /* assert aclink reset again */
                   1746:                value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1747:                value |=  ATI_REG_CMD_AC_RESET;
                   1748:                bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1749:
                   1750:                /* check if its active now */
                   1751:                value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1752:
                   1753:                timeout--;
                   1754:                if (timeout == 0) break;
                   1755:        };
                   1756:
                   1757:        if (timeout == 0) {
                   1758:                printf("%s: giving up aclink reset\n", sc->sc_dev.dv_xname);
                   1759:        };
                   1760:        if (timeout != 10) {
                   1761:                printf("%s: aclink hardware reset successful\n",
                   1762:                        sc->sc_dev.dv_xname);
                   1763:        };
                   1764:
                   1765:        /* assert reset and sync for safety */
                   1766:        value  = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1767:        value |= ATI_REG_CMD_AC_SYNC | ATI_REG_CMD_AC_RESET;
                   1768:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1769: }
                   1770:
                   1771: /* chip hard init */
                   1772: int
                   1773: auixp_init(struct auixp_softc *sc)
                   1774: {
                   1775:        bus_space_tag_t      iot;
                   1776:        bus_space_handle_t   ioh;
                   1777:        u_int32_t value;
                   1778:
                   1779:        iot = sc->sc_iot;
                   1780:        ioh = sc->sc_ioh;
                   1781:        /* disable all interrupts and clear all sources */
                   1782:        auixp_disable_interrupts(sc);
                   1783:
                   1784:        /* clear all DMA enables (preserving rest of settings) */
                   1785:        value = bus_space_read_4(iot, ioh, ATI_REG_CMD);
                   1786:        value &= ~( ATI_REG_CMD_IN_DMA_EN  |
                   1787:                    ATI_REG_CMD_OUT_DMA_EN |
                   1788:                    ATI_REG_CMD_SPDF_OUT_EN );
                   1789:        bus_space_write_4(iot, ioh, ATI_REG_CMD, value);
                   1790:
                   1791:        /* Reset AC-link */
                   1792:        auixp_reset_aclink(sc);
                   1793:
                   1794:        /*
                   1795:         * codecs get auto-detected later
                   1796:         *
                   1797:         * note: we are NOT enabling interrupts yet, no codecs have been
                   1798:         * detected yet nor is anything else set up
                   1799:         */
                   1800:
                   1801:        return 0;
                   1802: }
                   1803:
                   1804: /*
                   1805:  * TODO power saving and suspend / resume support
                   1806:  */
                   1807: int
                   1808: auixp_power(struct auixp_softc *sc, int state)
                   1809: {
                   1810:        pcitag_t tag;
                   1811:        pci_chipset_tag_t pc;
                   1812:        pcireg_t data;
                   1813:        int pmcapreg;
                   1814:
                   1815:        tag = sc->sc_tag;
                   1816:        pc = sc->sc_pct;
                   1817:        if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &pmcapreg, 0)) {
                   1818:                data = pci_conf_read(pc, tag, pmcapreg + PCI_PMCSR);
                   1819:                if ((data & PCI_PMCSR_STATE_MASK) != state)
                   1820:                        pci_conf_write(pc, tag, pmcapreg + PCI_PMCSR, state);
                   1821:        }
                   1822:
                   1823:        return 0;
                   1824: }
                   1825:
                   1826: #if 0
                   1827: void
                   1828: auixp_powerhook(int why, void *hdl)
                   1829: {
                   1830:        struct auixp_softc *sc;
                   1831:
                   1832:        sc = (struct auixp_softc *)hdl;
                   1833:        switch (why) {
                   1834:        case PWR_SUSPEND:
                   1835:        case PWR_STANDBY:
                   1836:                auixp_suspend(sc);
                   1837:                break;
                   1838:        case PWR_RESUME:
                   1839:                auixp_resume(sc);
                   1840: /* XXX fix me XXX */
                   1841:                (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
                   1842:                break;
                   1843:        }
                   1844: }
                   1845:
                   1846: int
                   1847: auixp_suspend(struct auixp_softc *sc)
                   1848: {
                   1849:
                   1850:        /* XXX no power functions yet XXX */
                   1851:        return 0;
                   1852: }
                   1853:
                   1854: int
                   1855: auixp_resume(struct auixp_softc *sc)
                   1856: {
                   1857:
                   1858:        /* XXX no power functions yet XXX */
                   1859:        return 0;
                   1860: }
                   1861: #endif /* 0 */

CVSweb