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

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

1.1     ! nbrk        1: /*     $OpenBSD: maestro.c,v 1.21 2006/12/29 13:04:37 pedro Exp $      */
        !             2: /* $FreeBSD: /c/ncvs/src/sys/dev/sound/pci/maestro.c,v 1.3 2000/11/21 12:22:11 julian Exp $ */
        !             3: /*
        !             4:  * FreeBSD's ESS Agogo/Maestro driver
        !             5:  * Converted from FreeBSD's pcm to OpenBSD's audio.
        !             6:  * Copyright (c) 2000, 2001 David Leonard & Marc Espie
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30: /*-
        !            31:  * (FreeBSD) Credits:
        !            32:  * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp>
        !            33:  *
        !            34:  * Part of this code (especially in many magic numbers) was heavily inspired
        !            35:  * by the Linux driver originally written by
        !            36:  * Alan Cox <alan.cox@linux.org>, modified heavily by
        !            37:  * Zach Brown <zab@zabbo.net>.
        !            38:  *
        !            39:  * busdma()-ize and buffer size reduction were suggested by
        !            40:  * Cameron Grant <gandalf@vilnya.demon.co.uk>.
        !            41:  * Also he showed me the way to use busdma() suite.
        !            42:  *
        !            43:  * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500
        !            44:  * were looked at by
        !            45:  * Munehiro Matsuda <haro@tk.kubota.co.jp>,
        !            46:  * who brought patches based on the Linux driver with some simplification.
        !            47:  */
        !            48:
        !            49: #include <sys/param.h>
        !            50: #include <sys/systm.h>
        !            51: #include <sys/kernel.h>
        !            52: #include <sys/malloc.h>
        !            53: #include <sys/device.h>
        !            54: #include <sys/proc.h>
        !            55: #include <sys/queue.h>
        !            56: #include <sys/fcntl.h>
        !            57:
        !            58: #include <dev/pci/pcidevs.h>
        !            59: #include <dev/pci/pcivar.h>
        !            60:
        !            61: #include <sys/audioio.h>
        !            62: #include <dev/audio_if.h>
        !            63: #include <dev/mulaw.h>
        !            64: #include <dev/auconv.h>
        !            65:
        !            66: #include <dev/ic/ac97.h>
        !            67:
        !            68: /* -----------------------------
        !            69:  * PCI config registers
        !            70:  */
        !            71:
        !            72: /* Legacy emulation */
        !            73: #define CONF_LEGACY    0x40
        !            74:
        !            75: #define LEGACY_DISABLED        0x8000
        !            76:
        !            77: /* Chip configurations */
        !            78: #define CONF_MAESTRO   0x50
        !            79: #define MAESTRO_CHIBUS         0x00100000
        !            80: #define MAESTRO_POSTEDWRITE    0x00000080
        !            81: #define MAESTRO_DMA_PCITIMING  0x00000040
        !            82: #define MAESTRO_SWAP_LR                0x00000010
        !            83:
        !            84: /* ACPI configurations */
        !            85: #define CONF_ACPI_STOPCLOCK    0x54
        !            86: #define ACPI_PART_2ndC_CLOCK   15
        !            87: #define ACPI_PART_CODEC_CLOCK  14
        !            88: #define ACPI_PART_978          13 /* Docking station or something */
        !            89: #define ACPI_PART_SPDIF                12
        !            90: #define ACPI_PART_GLUE         11 /* What? */
        !            91: #define ACPI_PART_DAA          10
        !            92: #define ACPI_PART_PCI_IF       9
        !            93: #define ACPI_PART_HW_VOL       8
        !            94: #define ACPI_PART_GPIO         7
        !            95: #define ACPI_PART_ASSP         6
        !            96: #define ACPI_PART_SB           5
        !            97: #define ACPI_PART_FM           4
        !            98: #define ACPI_PART_RINGBUS      3
        !            99: #define ACPI_PART_MIDI         2
        !           100: #define ACPI_PART_GAME_PORT    1
        !           101: #define ACPI_PART_WP           0
        !           102:
        !           103: /* Power management */
        !           104: #define        CONF_PM_PTR     0x34    /* BYTE R */
        !           105: #define        PM_CID          0       /* BYTE R */
        !           106: #define        PPMI_CID        1
        !           107: #define        PM_CTRL         4       /* BYTE RW */
        !           108: #define        PPMI_D0         0       /* Full power */
        !           109: #define        PPMI_D1         1       /* Medium power */
        !           110: #define        PPMI_D2         2       /* Low power */
        !           111: #define        PPMI_D3         3       /* Turned off */
        !           112:
        !           113:
        !           114: /* -----------------------------
        !           115:  * I/O ports
        !           116:  */
        !           117:
        !           118: /* Direct Sound Processor (aka Wave Processor) */
        !           119: #define PORT_DSP_DATA  0x00    /* WORD RW */
        !           120: #define PORT_DSP_INDEX 0x02    /* WORD RW */
        !           121: #define PORT_INT_STAT  0x04    /* WORD RW */
        !           122: #define PORT_SAMPLE_CNT        0x06    /* WORD RO */
        !           123:
        !           124: /* WaveCache */
        !           125: #define PORT_WAVCACHE_INDEX    0x10    /* WORD RW */
        !           126: #define PORT_WAVCACHE_DATA     0x12    /* WORD RW */
        !           127: #define WAVCACHE_PCMBAR                0x1fc
        !           128: #define WAVCACHE_WTBAR         0x1f0
        !           129: #define WAVCACHE_BASEADDR_SHIFT        12
        !           130:
        !           131: #define WAVCACHE_CHCTL_ADDRTAG_MASK    0xfff8
        !           132: #define WAVCACHE_CHCTL_U8              0x0004
        !           133: #define WAVCACHE_CHCTL_STEREO          0x0002
        !           134: #define WAVCACHE_CHCTL_DECREMENTAL     0x0001
        !           135:
        !           136: #define PORT_WAVCACHE_CTRL     0x14    /* WORD RW */
        !           137: #define WAVCACHE_EXTRA_CH_ENABLED      0x0200
        !           138: #define WAVCACHE_ENABLED               0x0100
        !           139: #define WAVCACHE_CH_60_ENABLED         0x0080
        !           140: #define WAVCACHE_WTSIZE_MASK   0x0060
        !           141: #define WAVCACHE_WTSIZE_1MB    0x0000
        !           142: #define WAVCACHE_WTSIZE_2MB    0x0020
        !           143: #define WAVCACHE_WTSIZE_4MB    0x0040
        !           144: #define WAVCACHE_WTSIZE_8MB    0x0060
        !           145: #define WAVCACHE_SGC_MASK              0x000c
        !           146: #define WAVCACHE_SGC_DISABLED          0x0000
        !           147: #define WAVCACHE_SGC_40_47             0x0004
        !           148: #define WAVCACHE_SGC_32_47             0x0008
        !           149: #define WAVCACHE_TESTMODE              0x0001
        !           150:
        !           151: /* Host Interruption */
        !           152: #define PORT_HOSTINT_CTRL      0x18    /* WORD RW */
        !           153: #define HOSTINT_CTRL_SOFT_RESET                0x8000
        !           154: #define HOSTINT_CTRL_DSOUND_RESET      0x4000
        !           155: #define HOSTINT_CTRL_HW_VOL_TO_PME     0x0400
        !           156: #define HOSTINT_CTRL_CLKRUN_ENABLED    0x0100
        !           157: #define HOSTINT_CTRL_HWVOL_ENABLED     0x0040
        !           158: #define HOSTINT_CTRL_ASSP_INT_ENABLED  0x0010
        !           159: #define HOSTINT_CTRL_ISDN_INT_ENABLED  0x0008
        !           160: #define HOSTINT_CTRL_DSOUND_INT_ENABLED        0x0004
        !           161: #define HOSTINT_CTRL_MPU401_INT_ENABLED        0x0002
        !           162: #define HOSTINT_CTRL_SB_INT_ENABLED    0x0001
        !           163:
        !           164: #define PORT_HOSTINT_STAT      0x1a    /* BYTE RW */
        !           165: #define HOSTINT_STAT_HWVOL     0x40
        !           166: #define HOSTINT_STAT_ASSP      0x10
        !           167: #define HOSTINT_STAT_ISDN      0x08
        !           168: #define HOSTINT_STAT_DSOUND    0x04
        !           169: #define HOSTINT_STAT_MPU401    0x02
        !           170: #define HOSTINT_STAT_SB                0x01
        !           171:
        !           172: /* Hardware volume */
        !           173: #define PORT_HWVOL_VOICE_SHADOW        0x1c    /* BYTE RW */
        !           174: #define PORT_HWVOL_VOICE       0x1d    /* BYTE RW */
        !           175: #define PORT_HWVOL_MASTER_SHADOW 0x1e  /* BYTE RW */
        !           176: #define PORT_HWVOL_MASTER      0x1f    /* BYTE RW */
        !           177:
        !           178: /* CODEC */
        !           179: #define        PORT_CODEC_CMD  0x30    /* BYTE W */
        !           180: #define CODEC_CMD_READ 0x80
        !           181: #define        CODEC_CMD_WRITE 0x00
        !           182: #define        CODEC_CMD_ADDR_MASK     0x7f
        !           183:
        !           184: #define PORT_CODEC_STAT        0x30    /* BYTE R */
        !           185: #define CODEC_STAT_MASK        0x01
        !           186: #define CODEC_STAT_RW_DONE     0x00
        !           187: #define CODEC_STAT_PROGLESS    0x01
        !           188:
        !           189: #define PORT_CODEC_REG 0x32    /* WORD RW */
        !           190:
        !           191: /* Ring bus control */
        !           192: #define PORT_RINGBUS_CTRL      0x34    /* DWORD RW */
        !           193: #define RINGBUS_CTRL_I2S_ENABLED       0x80000000
        !           194: #define RINGBUS_CTRL_RINGBUS_ENABLED   0x20000000
        !           195: #define RINGBUS_CTRL_ACLINK_ENABLED    0x10000000
        !           196: #define RINGBUS_CTRL_AC97_SWRESET      0x08000000
        !           197: #define RINGBUS_CTRL_IODMA_PLAYBACK_ENABLED    0x04000000
        !           198: #define RINGBUS_CTRL_IODMA_RECORD_ENABLED      0x02000000
        !           199:
        !           200: #define RINGBUS_SRC_MIC                20
        !           201: #define RINGBUS_SRC_I2S                16
        !           202: #define RINGBUS_SRC_ADC                12
        !           203: #define RINGBUS_SRC_MODEM      8
        !           204: #define RINGBUS_SRC_DSOUND     4
        !           205: #define RINGBUS_SRC_ASSP       0
        !           206:
        !           207: #define RINGBUS_DEST_MONORAL   000
        !           208: #define RINGBUS_DEST_STEREO    010
        !           209: #define RINGBUS_DEST_NONE      0
        !           210: #define RINGBUS_DEST_DAC       1
        !           211: #define RINGBUS_DEST_MODEM_IN  2
        !           212: #define RINGBUS_DEST_RESERVED3 3
        !           213: #define RINGBUS_DEST_DSOUND_IN 4
        !           214: #define RINGBUS_DEST_ASSP_IN   5
        !           215:
        !           216: /* General Purpose I/O */
        !           217: #define PORT_GPIO_DATA 0x60    /* WORD RW */
        !           218: #define PORT_GPIO_MASK 0x64    /* WORD RW */
        !           219: #define PORT_GPIO_DIR  0x68    /* WORD RW */
        !           220:
        !           221: /* Application Specific Signal Processor */
        !           222: #define PORT_ASSP_MEM_INDEX    0x80    /* DWORD RW */
        !           223: #define PORT_ASSP_MEM_DATA     0x84    /* WORD RW */
        !           224: #define PORT_ASSP_CTRL_A       0xa2    /* BYTE RW */
        !           225: #define PORT_ASSP_CTRL_B       0xa4    /* BYTE RW */
        !           226: #define PORT_ASSP_CTRL_C       0xa6    /* BYTE RW */
        !           227: #define PORT_ASSP_HOST_WR_INDEX        0xa8    /* BYTE W */
        !           228: #define PORT_ASSP_HOST_WR_DATA 0xaa    /* BYTE RW */
        !           229: #define PORT_ASSP_INT_STAT     0xac    /* BYTE RW */
        !           230:
        !           231:
        !           232: /* -----------------------------
        !           233:  * Wave Processor Indexed Data Registers.
        !           234:  */
        !           235:
        !           236: #define WPREG_DATA_PORT                0
        !           237: #define WPREG_CRAM_PTR         1
        !           238: #define WPREG_CRAM_DATA                2
        !           239: #define WPREG_WAVE_DATA                3
        !           240: #define WPREG_WAVE_PTR_LOW     4
        !           241: #define WPREG_WAVE_PTR_HIGH    5
        !           242:
        !           243: #define WPREG_TIMER_FREQ       6
        !           244: #define WP_TIMER_FREQ_PRESCALE_MASK    0x00e0  /* actual - 9 */
        !           245: #define WP_TIMER_FREQ_PRESCALE_SHIFT   5
        !           246: #define WP_TIMER_FREQ_DIVIDE_MASK      0x001f
        !           247: #define WP_TIMER_FREQ_DIVIDE_SHIFT     0
        !           248:
        !           249: #define WPREG_WAVE_ROMRAM      7
        !           250: #define WP_WAVE_VIRTUAL_ENABLED        0x0400
        !           251: #define WP_WAVE_8BITRAM_ENABLED        0x0200
        !           252: #define WP_WAVE_DRAM_ENABLED   0x0100
        !           253: #define WP_WAVE_RAMSPLIT_MASK  0x00ff
        !           254: #define WP_WAVE_RAMSPLIT_SHIFT 0
        !           255:
        !           256: #define WPREG_BASE             12
        !           257: #define WP_PARAOUT_BASE_MASK   0xf000
        !           258: #define WP_PARAOUT_BASE_SHIFT  12
        !           259: #define WP_PARAIN_BASE_MASK    0x0f00
        !           260: #define WP_PARAIN_BASE_SHIFT   8
        !           261: #define WP_SERIAL0_BASE_MASK   0x00f0
        !           262: #define WP_SERIAL0_BASE_SHIFT  4
        !           263: #define WP_SERIAL1_BASE_MASK   0x000f
        !           264: #define WP_SERIAL1_BASE_SHIFT  0
        !           265:
        !           266: #define WPREG_TIMER_ENABLE     17
        !           267: #define WPREG_TIMER_START      23
        !           268:
        !           269:
        !           270: /* -----------------------------
        !           271:  * Audio Processing Unit.
        !           272:  */
        !           273: #define APUREG_APUTYPE 0
        !           274: #define APU_DMA_ENABLED        0x4000
        !           275: #define APU_INT_ON_LOOP        0x2000
        !           276: #define APU_ENDCURVE   0x1000
        !           277: #define APU_APUTYPE_MASK       0x00f0
        !           278: #define APU_FILTERTYPE_MASK    0x000c
        !           279: #define APU_FILTERQ_MASK       0x0003
        !           280:
        !           281: /* APU types */
        !           282: #define APU_APUTYPE_SHIFT      4
        !           283:
        !           284: #define APUTYPE_INACTIVE       0
        !           285: #define APUTYPE_16BITLINEAR    1
        !           286: #define APUTYPE_16BITSTEREO    2
        !           287: #define APUTYPE_8BITLINEAR     3
        !           288: #define APUTYPE_8BITSTEREO     4
        !           289: #define APUTYPE_8BITDIFF       5
        !           290: #define APUTYPE_DIGITALDELAY   6
        !           291: #define APUTYPE_DUALTAP_READER 7
        !           292: #define APUTYPE_CORRELATOR     8
        !           293: #define APUTYPE_INPUTMIXER     9
        !           294: #define APUTYPE_WAVETABLE      10
        !           295: #define APUTYPE_RATECONV       11
        !           296: #define APUTYPE_16BITPINGPONG  12
        !           297: /* APU type 13 through 15 are reserved. */
        !           298:
        !           299: /* Filter types */
        !           300: #define APU_FILTERTYPE_SHIFT   2
        !           301:
        !           302: #define FILTERTYPE_2POLE_LOPASS                0
        !           303: #define FILTERTYPE_2POLE_BANDPASS      1
        !           304: #define FILTERTYPE_2POLE_HIPASS                2
        !           305: #define FILTERTYPE_1POLE_LOPASS                3
        !           306: #define FILTERTYPE_1POLE_HIPASS                4
        !           307: #define FILTERTYPE_PASSTHROUGH         5
        !           308:
        !           309: /* Filter Q */
        !           310: #define APU_FILTERQ_SHIFT      0
        !           311:
        !           312: #define FILTERQ_LESSQ  0
        !           313: #define FILTERQ_MOREQ  3
        !           314:
        !           315: /* APU register 2 */
        !           316: #define APUREG_FREQ_LOBYTE     2
        !           317: #define APU_FREQ_LOBYTE_MASK   0xff00
        !           318: #define APU_plus6dB            0x0010
        !           319:
        !           320: /* APU register 3 */
        !           321: #define APUREG_FREQ_HIWORD     3
        !           322: #define APU_FREQ_HIWORD_MASK   0x0fff
        !           323:
        !           324: /* Frequency */
        !           325: #define APU_FREQ_LOBYTE_SHIFT  8
        !           326: #define APU_FREQ_HIWORD_SHIFT  0
        !           327: #define FREQ_Hz2DIV(freq)      (((u_int64_t)(freq) << 16) / 48000)
        !           328:
        !           329: /* APU register 4 */
        !           330: #define APUREG_WAVESPACE       4
        !           331: #define APU_STEREO             0x8000
        !           332: #define APU_USE_SYSMEM         0x4000
        !           333: #define APU_PCMBAR_MASK                0x6000
        !           334: #define APU_64KPAGE_MASK       0xff00
        !           335:
        !           336: /* PCM Base Address Register selection */
        !           337: #define APU_PCMBAR_SHIFT       13
        !           338:
        !           339: /* 64KW (==128KB) Page */
        !           340: #define APU_64KPAGE_SHIFT      8
        !           341:
        !           342: /* APU register 5 - 7 */
        !           343: #define APUREG_CURPTR  5
        !           344: #define APUREG_ENDPTR  6
        !           345: #define APUREG_LOOPLEN 7
        !           346:
        !           347: /* APU register 9 */
        !           348: #define APUREG_AMPLITUDE       9
        !           349: #define APU_AMPLITUDE_NOW_MASK 0xff00
        !           350: #define APU_AMPLITUDE_DEST_MASK        0x00ff
        !           351:
        !           352: /* Amplitude now? */
        !           353: #define APU_AMPLITUDE_NOW_SHIFT        8
        !           354:
        !           355: /* APU register 10 */
        !           356: #define APUREG_POSITION        10
        !           357: #define APU_RADIUS_MASK        0x00c0
        !           358: #define APU_PAN_MASK   0x003f
        !           359:
        !           360: /* Radius control. */
        !           361: #define APU_RADIUS_SHIFT       6
        !           362: #define RADIUS_CENTERCIRCLE    0
        !           363: #define RADIUS_MIDDLE          1
        !           364: #define RADIUS_OUTSIDE         2
        !           365:
        !           366: /* Polar pan. */
        !           367: #define APU_PAN_SHIFT  0
        !           368: #define PAN_RIGHT      0x00
        !           369: #define PAN_FRONT      0x08
        !           370: #define PAN_LEFT       0x10
        !           371:
        !           372:
        !           373: /* -----------------------------
        !           374:  * Limits.
        !           375:  */
        !           376: #define WPWA_MAX       ((1 << 22) - 1)
        !           377: #define WPWA_MAXADDR   ((1 << 23) - 1)
        !           378: #define MAESTRO_MAXADDR        ((1 << 28) - 1)
        !           379:
        !           380:
        !           381:
        !           382: #ifdef AUDIO_DEBUG
        !           383: #define DPRINTF(x)     if (maestrodebug) printf x
        !           384: #define DLPRINTF(i, x) if (maestrodebug & i) printf x
        !           385: int    maestrodebug = 0;
        !           386: u_long maestrointr_called;
        !           387: u_long maestrodma_effective;
        !           388:
        !           389: #define MAESTRODEBUG_INTR 1
        !           390: #define MAESTRODEBUG_TIMER 2
        !           391: #else
        !           392: #define DPRINTF(x)
        !           393: #define DLPRINTF(i, x)
        !           394: #endif
        !           395:
        !           396: #define MAESTRO_BUFSIZ         0x4000
        !           397: #define lengthof(array)                (sizeof (array) / sizeof (array)[0])
        !           398:
        !           399: #define STEP_VOLUME            0x22
        !           400: #define MIDDLE_VOLUME          (STEP_VOLUME * 4)
        !           401:
        !           402: typedef struct salloc_pool {
        !           403:        struct salloc_zone {
        !           404:                SLIST_ENTRY(salloc_zone) link;
        !           405:                caddr_t         addr;
        !           406:                size_t          size;
        !           407:        } *zones;
        !           408:        SLIST_HEAD(salloc_head, salloc_zone) free, used, spare;
        !           409: } *salloc_t;
        !           410:
        !           411: struct maestro_softc;
        !           412:
        !           413: #define MAESTRO_PLAY   1
        !           414: #define MAESTRO_STEREO 2
        !           415: #define MAESTRO_8BIT   4
        !           416: #define MAESTRO_UNSIGNED       8
        !           417: #define MAESTRO_RUNNING        16
        !           418:
        !           419: struct maestro_channel {
        !           420:        struct maestro_softc    *sc;
        !           421:        int                     num;
        !           422:        u_int32_t               blocksize;
        !           423:        u_int16_t               mode;
        !           424:        u_int32_t               speed;
        !           425:        u_int32_t               dv;
        !           426:        u_int16_t               start;
        !           427:        u_int16_t               threshold;
        !           428:        u_int16_t               end;
        !           429:        u_int16_t               current;
        !           430:        u_int                   wpwa;
        !           431:        void                    (*intr)(void *);
        !           432:        void                    *intr_arg;
        !           433: };
        !           434:
        !           435: struct maestro_softc {
        !           436:        struct device           dev;
        !           437:
        !           438:        void                    *ih;
        !           439:        pci_chipset_tag_t       pc;
        !           440:        pcitag_t                pt;
        !           441:
        !           442: #define MAESTRO_FLAG_SETUPGPIO 0x0001
        !           443:        int                     flags;
        !           444:        bus_space_tag_t         iot;
        !           445:        bus_space_handle_t      ioh;
        !           446:        bus_dma_tag_t           dmat;
        !           447:
        !           448:        caddr_t                 dmabase;
        !           449:        bus_addr_t              physaddr;
        !           450:        size_t                  dmasize;
        !           451:        bus_dmamap_t            dmamap;
        !           452:        bus_dma_segment_t       dmaseg;
        !           453:        salloc_t                dmapool;
        !           454:
        !           455:        struct ac97_codec_if    *codec_if;
        !           456:        struct ac97_host_if     host_if;
        !           457:        struct audio_device     *sc_audev;
        !           458:
        !           459:        void                    *powerhook;
        !           460:        int                     suspend;
        !           461:
        !           462:        struct maestro_channel  play;
        !           463:        struct maestro_channel  record;
        !           464: };
        !           465:
        !           466:
        !           467: typedef        u_int16_t wpreg_t;
        !           468: typedef        u_int16_t wcreg_t;
        !           469:
        !           470: salloc_t salloc_new(caddr_t, size_t, int);
        !           471: void   salloc_destroy(salloc_t);
        !           472: caddr_t        salloc_alloc(salloc_t, size_t);
        !           473: void   salloc_free(salloc_t, caddr_t);
        !           474: void   salloc_insert(salloc_t, struct salloc_head *,
        !           475:                struct salloc_zone *, int);
        !           476:
        !           477: int    maestro_match(struct device *, void *, void *);
        !           478: void   maestro_attach(struct device *, struct device *, void *);
        !           479: int    maestro_intr(void *);
        !           480:
        !           481: int    maestro_open(void *, int);
        !           482: void   maestro_close(void *);
        !           483: int    maestro_query_encoding(void *, struct audio_encoding *);
        !           484: int    maestro_set_params(void *, int, int, struct audio_params *,
        !           485:                            struct audio_params *);
        !           486: int    maestro_round_blocksize(void *, int);
        !           487: int    maestro_halt_output(void *);
        !           488: int    maestro_halt_input(void *);
        !           489: int    maestro_getdev(void *, struct audio_device *);
        !           490: int    maestro_set_port(void *, mixer_ctrl_t *);
        !           491: int    maestro_get_port(void *, mixer_ctrl_t *);
        !           492: int    maestro_query_devinfo(void *, mixer_devinfo_t *);
        !           493: void   *maestro_malloc(void *, int, size_t, int, int);
        !           494: void   maestro_free(void *, void *, int);
        !           495: paddr_t        maestro_mappage(void *, void *, off_t, int);
        !           496: int    maestro_get_props(void *);
        !           497: int    maestro_trigger_output(void *, void *, void *, int, void (*)(void *),
        !           498:                                void *, struct audio_params *);
        !           499: int    maestro_trigger_input(void *, void *, void *, int, void (*)(void *),
        !           500:                               void *, struct audio_params *);
        !           501:
        !           502: int    maestro_attach_codec(void *, struct ac97_codec_if *);
        !           503: int    maestro_read_codec(void *, u_int8_t, u_int16_t *);
        !           504: int    maestro_write_codec(void *, u_int8_t, u_int16_t);
        !           505: void   maestro_reset_codec(void *);
        !           506:
        !           507: void   maestro_initcodec(void *);
        !           508:
        !           509: void   maestro_set_speed(struct maestro_channel *, u_long *);
        !           510: void   maestro_init(struct maestro_softc *);
        !           511: void   maestro_power(struct maestro_softc *, int);
        !           512: void   maestro_powerhook(int, void *);
        !           513:
        !           514: void   maestro_channel_start(struct maestro_channel *);
        !           515: void   maestro_channel_stop(struct maestro_channel *);
        !           516: void   maestro_channel_advance_dma(struct maestro_channel *);
        !           517: void   maestro_channel_suppress_jitter(struct maestro_channel *);
        !           518:
        !           519: int    maestro_get_flags(struct pci_attach_args *);
        !           520:
        !           521: void   ringbus_setdest(struct maestro_softc *, int, int);
        !           522:
        !           523: wpreg_t        wp_reg_read(struct maestro_softc *, int);
        !           524: void   wp_reg_write(struct maestro_softc *, int, wpreg_t);
        !           525: wpreg_t        wp_apu_read(struct maestro_softc *, int, int);
        !           526: void   wp_apu_write(struct maestro_softc *, int, int, wpreg_t);
        !           527: void   wp_settimer(struct maestro_softc *, u_int);
        !           528: void   wp_starttimer(struct maestro_softc *);
        !           529: void   wp_stoptimer(struct maestro_softc *);
        !           530:
        !           531: wcreg_t        wc_reg_read(struct maestro_softc *, int);
        !           532: void   wc_reg_write(struct maestro_softc *, int, wcreg_t);
        !           533: wcreg_t        wc_ctrl_read(struct maestro_softc *, int);
        !           534: void   wc_ctrl_write(struct maestro_softc *, int, wcreg_t);
        !           535:
        !           536: u_int maestro_calc_timer_freq(struct maestro_channel *);
        !           537: void maestro_update_timer(struct maestro_softc *);
        !           538:
        !           539: struct cfdriver maestro_cd = {
        !           540:        NULL, "maestro", DV_DULL
        !           541: };
        !           542:
        !           543: struct cfattach maestro_ca = {
        !           544:        sizeof (struct maestro_softc), maestro_match, maestro_attach
        !           545: };
        !           546:
        !           547: struct audio_hw_if maestro_hw_if = {
        !           548:        maestro_open,
        !           549:        maestro_close,
        !           550:        NULL,
        !           551:        maestro_query_encoding,
        !           552:        maestro_set_params,
        !           553:        maestro_round_blocksize,
        !           554:        NULL,
        !           555:        NULL,
        !           556:        NULL,
        !           557:        NULL,
        !           558:        NULL,
        !           559:        maestro_halt_output,
        !           560:        maestro_halt_input,
        !           561:        NULL,
        !           562:        maestro_getdev,
        !           563:        NULL,
        !           564:        maestro_set_port,
        !           565:        maestro_get_port,
        !           566:        maestro_query_devinfo,
        !           567:        maestro_malloc,
        !           568:        maestro_free,
        !           569:        NULL,
        !           570:        maestro_mappage,
        !           571:        maestro_get_props,
        !           572:        maestro_trigger_output,
        !           573:        maestro_trigger_input
        !           574: };
        !           575:
        !           576: struct audio_device maestro_audev = {
        !           577:        "ESS Maestro", "", "maestro"
        !           578: };
        !           579:
        !           580: struct {
        !           581:        u_short vendor, product;
        !           582:        int flags;
        !           583: } maestro_pcitab[] = {
        !           584:        { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTROII,    0 },
        !           585:        { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO2E,    0 },
        !           586:        { PCI_VENDOR_PLATFORM, PCI_PRODUCT_PLATFORM_ES1849,     0 },
        !           587:        { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAMAESTRO,         MAESTRO_FLAG_SETUPGPIO },
        !           588:        { PCI_VENDOR_NEC, PCI_PRODUCT_NEC_VERSAPRONXVA26D,      MAESTRO_FLAG_SETUPGPIO }
        !           589: };
        !           590: #define NMAESTRO_PCITAB        lengthof(maestro_pcitab)
        !           591:
        !           592: int
        !           593: maestro_get_flags(pa)
        !           594:        struct pci_attach_args *pa;
        !           595: {
        !           596:        int i;
        !           597:
        !           598:        /* Distinguish audio devices from modems with the same manfid */
        !           599:        if (PCI_CLASS(pa->pa_class) != PCI_CLASS_MULTIMEDIA)
        !           600:                return (-1);
        !           601:        if (PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_MULTIMEDIA_AUDIO)
        !           602:                return (-1);
        !           603:        for (i = 0; i < NMAESTRO_PCITAB; i++)
        !           604:                if (PCI_VENDOR(pa->pa_id) == maestro_pcitab[i].vendor &&
        !           605:                    PCI_PRODUCT(pa->pa_id) == maestro_pcitab[i].product)
        !           606:                        return (maestro_pcitab[i].flags);
        !           607:        return (-1);
        !           608: }
        !           609:
        !           610: /* -----------------------------
        !           611:  * Driver interface.
        !           612:  */
        !           613:
        !           614: int
        !           615: maestro_match(parent, match, aux)
        !           616:        struct device *parent;
        !           617:        void *match;
        !           618:        void *aux;
        !           619: {
        !           620:        struct pci_attach_args *pa = (struct pci_attach_args *)aux;
        !           621:
        !           622:        if (maestro_get_flags(pa) == -1)
        !           623:                return (0);
        !           624:        else
        !           625:                return (1);
        !           626: }
        !           627:
        !           628: void
        !           629: maestro_attach(parent, self, aux)
        !           630:        struct device *parent;
        !           631:        struct device *self;
        !           632:        void *aux;
        !           633: {
        !           634:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !           635:        struct pci_attach_args *pa = (struct pci_attach_args *)aux;
        !           636:        pci_chipset_tag_t pc = pa->pa_pc;
        !           637:        char const *intrstr;
        !           638:        pci_intr_handle_t ih;
        !           639:        int error;
        !           640:        u_int16_t cdata;
        !           641:        int dmastage = 0;
        !           642:        int rseg;
        !           643:
        !           644:        sc->sc_audev = &maestro_audev;
        !           645:        sc->flags = maestro_get_flags(pa);
        !           646:
        !           647:        sc->pc = pa->pa_pc;
        !           648:        sc->pt = pa->pa_tag;
        !           649:        sc->dmat = pa->pa_dmat;
        !           650:
        !           651:        /* Map interrupt */
        !           652:        if (pci_intr_map(pa, &ih)) {
        !           653:                printf(": couldn't map interrupt\n");
        !           654:                return;
        !           655:        }
        !           656:        intrstr = pci_intr_string(pc, ih);
        !           657:        sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, maestro_intr, sc,
        !           658:            sc->dev.dv_xname);
        !           659:        if (sc->ih == NULL) {
        !           660:                printf(": couldn't establish interrupt");
        !           661:                if (intrstr != NULL)
        !           662:                        printf(" at %s\n", intrstr);
        !           663:                return;
        !           664:        }
        !           665:        printf(": %s", intrstr);
        !           666:
        !           667:        /* Rangers, power up */
        !           668:        maestro_power(sc, PPMI_D0);
        !           669:        DELAY(100000);
        !           670:
        !           671:        /* Map i/o */
        !           672:        if ((error = pci_mapreg_map(pa, PCI_MAPS, PCI_MAPREG_TYPE_IO,
        !           673:            0, &sc->iot, &sc->ioh, NULL, NULL, 0)) != 0) {
        !           674:                printf(", couldn't map i/o space\n");
        !           675:                goto bad;
        !           676:        };
        !           677:
        !           678:        /* Allocate fixed DMA segment :-( */
        !           679:        sc->dmasize = MAESTRO_BUFSIZ * 16;
        !           680:        if ((error = bus_dmamem_alloc(sc->dmat, sc->dmasize, NBPG, 0,
        !           681:            &sc->dmaseg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
        !           682:                printf(", unable to alloc dma, error %d\n", error);
        !           683:                goto bad;
        !           684:        }
        !           685:        dmastage = 1;
        !           686:        if ((error = bus_dmamem_map(sc->dmat, &sc->dmaseg, 1,
        !           687:            sc->dmasize, &sc->dmabase, BUS_DMA_NOWAIT |
        !           688:            BUS_DMA_COHERENT)) != 0) {
        !           689:                printf(", unable to map dma, error %d\n", error);
        !           690:                goto bad;
        !           691:        }
        !           692:        dmastage = 2;
        !           693:        if ((error = bus_dmamap_create(sc->dmat, sc->dmasize, 1,
        !           694:            sc->dmasize, 0, BUS_DMA_NOWAIT, &sc->dmamap)) != 0) {
        !           695:                printf(", unable to create dma map, error %d\n", error);
        !           696:                goto bad;
        !           697:        }
        !           698:        dmastage = 3;
        !           699:        if ((error = bus_dmamap_load(sc->dmat, sc->dmamap,
        !           700:            sc->dmabase, sc->dmasize, NULL, BUS_DMA_NOWAIT)) != 0) {
        !           701:                printf(", unable to load dma map, error %d\n", error);
        !           702:                goto bad;
        !           703:        }
        !           704:
        !           705:        /* XXX
        !           706:         * The first byte of the allocated memory is not usable,
        !           707:         * the WP sometimes uses it to store status.
        !           708:         */
        !           709:        /* Make DMA memory pool */
        !           710:        if ((sc->dmapool = salloc_new(sc->dmabase+16, sc->dmasize-16,
        !           711:            128/*overkill?*/)) == NULL) {
        !           712:                printf(", unable to make dma pool\n");
        !           713:                goto bad;
        !           714:        }
        !           715:
        !           716:        sc->physaddr = sc->dmamap->dm_segs[0].ds_addr;
        !           717:
        !           718:        printf("\n");
        !           719:
        !           720:        /* Kick device */
        !           721:        maestro_init(sc);
        !           722:        maestro_read_codec(sc, 0, &cdata);
        !           723:        if (cdata == 0x80) {
        !           724:                printf("%s: PT101 codec unsupported, no mixer\n",
        !           725:                    sc->dev.dv_xname);
        !           726:                /* Init values from Linux, no idea what this does. */
        !           727:                maestro_write_codec(sc, 0x2a, 0x0001);
        !           728:                maestro_write_codec(sc, 0x2C, 0x0000);
        !           729:                maestro_write_codec(sc, 0x2C, 0xFFFF);
        !           730:                maestro_write_codec(sc, 0x10, 0x9F1F);
        !           731:                maestro_write_codec(sc, 0x12, 0x0808);
        !           732:                maestro_write_codec(sc, 0x14, 0x9F1F);
        !           733:                maestro_write_codec(sc, 0x16, 0x9F1F);
        !           734:                maestro_write_codec(sc, 0x18, 0x0404);
        !           735:                maestro_write_codec(sc, 0x1A, 0x0000);
        !           736:                maestro_write_codec(sc, 0x1C, 0x0000);
        !           737:                maestro_write_codec(sc, 0x02, 0x0404);
        !           738:                maestro_write_codec(sc, 0x04, 0x0808);
        !           739:                maestro_write_codec(sc, 0x0C, 0x801F);
        !           740:                maestro_write_codec(sc, 0x0E, 0x801F);
        !           741:                /* no control over the mixer, sorry */
        !           742:                sc->codec_if = NULL;
        !           743:        } else {
        !           744:                /* Attach the AC'97 */
        !           745:                sc->host_if.arg = sc;
        !           746:                sc->host_if.attach = maestro_attach_codec;
        !           747:                sc->host_if.read = maestro_read_codec;
        !           748:                sc->host_if.write = maestro_write_codec;
        !           749:                sc->host_if.reset = maestro_reset_codec;
        !           750:                if (ac97_attach(&sc->host_if) != 0) {
        !           751:                        printf("%s: couldn't attach codec\n", sc->dev.dv_xname);
        !           752:                        goto bad;
        !           753:                }
        !           754:        }
        !           755:
        !           756:        sc->play.mode = MAESTRO_PLAY;
        !           757:        sc->play.sc = sc;
        !           758:        sc->play.num = 0;
        !           759:        sc->record.sc = sc;
        !           760:        sc->record.num = 2;
        !           761:        sc->record.mode = 0;
        !           762:
        !           763:        /* Attach audio */
        !           764:        audio_attach_mi(&maestro_hw_if, sc, &sc->dev);
        !           765:
        !           766:        /* Hook power changes */
        !           767:        sc->suspend = PWR_RESUME;
        !           768:        sc->powerhook = powerhook_establish(maestro_powerhook, sc);
        !           769:
        !           770:        return;
        !           771:
        !           772:  bad:
        !           773:        /* Power down. */
        !           774:        maestro_power(sc, PPMI_D3);
        !           775:        if (sc->ih)
        !           776:                pci_intr_disestablish(pc, sc->ih);
        !           777:        printf("%s: disabled\n", sc->dev.dv_xname);
        !           778:        if (sc->dmapool)
        !           779:                salloc_destroy(sc->dmapool);
        !           780:        if (dmastage >= 3)
        !           781:                bus_dmamap_destroy(sc->dmat, sc->dmamap);
        !           782:        if (dmastage >= 2)
        !           783:                bus_dmamem_unmap(sc->dmat, sc->dmabase, sc->dmasize);
        !           784:        if (dmastage >= 1)
        !           785:                bus_dmamem_free(sc->dmat, &sc->dmaseg, 1);
        !           786: }
        !           787:
        !           788: void
        !           789: maestro_init(sc)
        !           790:        struct maestro_softc *sc;
        !           791: {
        !           792:        int reg;
        !           793:        pcireg_t data;
        !           794:
        !           795:        /* Disable all legacy emulations. */
        !           796:        data = pci_conf_read(sc->pc, sc->pt, CONF_LEGACY);
        !           797:        data |= LEGACY_DISABLED;
        !           798:        pci_conf_write(sc->pc, sc->pt, CONF_LEGACY, data);
        !           799:
        !           800:        /* Disconnect from CHI. (Makes Dell inspiron 7500 work?)
        !           801:         * Enable posted write.
        !           802:         * Prefer PCI timing rather than that of ISA.
        !           803:         * Don't swap L/R. */
        !           804:        data = pci_conf_read(sc->pc, sc->pt, CONF_MAESTRO);
        !           805:        data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING;
        !           806:        data &= ~MAESTRO_SWAP_LR;
        !           807:        pci_conf_write(sc->pc, sc->pt, CONF_MAESTRO, data);
        !           808:        /* Reset direct sound. */
        !           809:        bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
        !           810:            HOSTINT_CTRL_DSOUND_RESET);
        !           811:        DELAY(10000);   /* XXX - too long? */
        !           812:        bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
        !           813:        DELAY(10000);
        !           814:
        !           815:        /* Enable direct sound and hardware volume control interruptions. */
        !           816:        bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL,
        !           817:            HOSTINT_CTRL_DSOUND_INT_ENABLED | HOSTINT_CTRL_HWVOL_ENABLED);
        !           818:
        !           819:        /* Setup Wave Processor. */
        !           820:
        !           821:        /* Enable WaveCache, set DMA base address. */
        !           822:        wp_reg_write(sc, WPREG_WAVE_ROMRAM,
        !           823:            WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED);
        !           824:        bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_CTRL,
        !           825:            WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB);
        !           826:
        !           827:        for (reg = WAVCACHE_PCMBAR; reg < WAVCACHE_PCMBAR + 4; reg++)
        !           828:                wc_reg_write(sc, reg,
        !           829:                        sc->physaddr >> WAVCACHE_BASEADDR_SHIFT);
        !           830:
        !           831:        /* Setup Codec/Ringbus. */
        !           832:        maestro_initcodec(sc);
        !           833:        bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL,
        !           834:            RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED);
        !           835:
        !           836:        wp_reg_write(sc, WPREG_BASE, 0x8500);   /* Parallel I/O */
        !           837:        ringbus_setdest(sc, RINGBUS_SRC_ADC,
        !           838:            RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN);
        !           839:        ringbus_setdest(sc, RINGBUS_SRC_DSOUND,
        !           840:            RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC);
        !           841:
        !           842:        /* Setup ASSP. Needed for Dell Inspiron 7500? */
        !           843:        bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_B, 0x00);
        !           844:        bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_A, 0x03);
        !           845:        bus_space_write_1(sc->iot, sc->ioh, PORT_ASSP_CTRL_C, 0x00);
        !           846:
        !           847:        /*
        !           848:         * Reset hw volume to a known value so that we may handle diffs
        !           849:         * off to AC'97.
        !           850:         */
        !           851:
        !           852:        bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER, MIDDLE_VOLUME);
        !           853:        /* Setup GPIO if needed (NEC systems) */
        !           854:        if (sc->flags & MAESTRO_FLAG_SETUPGPIO) {
        !           855:                /* Matthew Braithwaite <matt@braithwaite.net> reported that
        !           856:                 * NEC Versa LX doesn't need GPIO operation. */
        !           857:                bus_space_write_2(sc->iot, sc->ioh,
        !           858:                    PORT_GPIO_MASK, 0x9ff);
        !           859:                bus_space_write_2(sc->iot, sc->ioh, PORT_GPIO_DIR,
        !           860:                    bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR) | 0x600);
        !           861:                bus_space_write_2(sc->iot, sc->ioh,
        !           862:                    PORT_GPIO_DATA, 0x200);
        !           863:        }
        !           864: }
        !           865:
        !           866: /* -----------------------------
        !           867:  * Audio interface
        !           868:  */
        !           869:
        !           870: int
        !           871: maestro_round_blocksize(self, blk)
        !           872:        void *self;
        !           873:        int blk;
        !           874: {
        !           875:        return ((blk + 0xf) & ~0xf);
        !           876: }
        !           877:
        !           878: void *
        !           879: maestro_malloc(arg, dir, size, pool, flags)
        !           880:        void *arg;
        !           881:        int dir;
        !           882:        size_t size;
        !           883:        int pool, flags;
        !           884: {
        !           885:        struct maestro_softc *sc = (struct maestro_softc *)arg;
        !           886:
        !           887:        return (salloc_alloc(sc->dmapool, size));
        !           888: }
        !           889:
        !           890: void
        !           891: maestro_free(self, ptr, pool)
        !           892:        void *self, *ptr;
        !           893:        int pool;
        !           894: {
        !           895:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !           896:
        !           897:        salloc_free(sc->dmapool, ptr);
        !           898: }
        !           899:
        !           900: paddr_t
        !           901: maestro_mappage(self, mem, off, prot)
        !           902:        void *self, *mem;
        !           903:        off_t off;
        !           904:        int prot;
        !           905: {
        !           906:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !           907:
        !           908:        if (off < 0)
        !           909:                return -1;
        !           910:        return bus_dmamem_mmap(sc->dmat, &sc->dmaseg, 1,
        !           911:                off, prot, BUS_DMA_WAITOK);
        !           912: }
        !           913:
        !           914: int
        !           915: maestro_get_props(self)
        !           916:        void *self;
        !           917: {
        !           918:        /* struct maestro_softc *sc = (struct maestro_softc *)self; */
        !           919:
        !           920:        return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT); /* XXX */
        !           921: }
        !           922:
        !           923: int
        !           924: maestro_getdev(self, retp)
        !           925:        void *self;
        !           926:        struct audio_device *retp;
        !           927: {
        !           928:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !           929:
        !           930:        *retp = *sc->sc_audev;
        !           931:        return 0;
        !           932: }
        !           933:
        !           934: int
        !           935: maestro_set_port(self, cp)
        !           936:        void *self;
        !           937:        mixer_ctrl_t *cp;
        !           938: {
        !           939:        struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
        !           940:
        !           941:        if (c)
        !           942:                return (c->vtbl->mixer_set_port(c, cp));
        !           943:        else
        !           944:                return (ENXIO);
        !           945: }
        !           946:
        !           947: int
        !           948: maestro_get_port(self, cp)
        !           949:        void *self;
        !           950:        mixer_ctrl_t *cp;
        !           951: {
        !           952:        struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
        !           953:
        !           954:        if (c)
        !           955:                return (c->vtbl->mixer_get_port(c, cp));
        !           956:        else
        !           957:                return (ENXIO);
        !           958: }
        !           959:
        !           960: int
        !           961: maestro_query_devinfo(self, cp)
        !           962:        void *self;
        !           963:        mixer_devinfo_t *cp;
        !           964: {
        !           965:        struct ac97_codec_if *c = ((struct maestro_softc *)self)->codec_if;
        !           966:
        !           967:        if (c)
        !           968:                return (c->vtbl->query_devinfo(c, cp));
        !           969:        else
        !           970:                return (ENXIO);
        !           971: }
        !           972:
        !           973: struct audio_encoding maestro_tab[] = {
        !           974:        {0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0},
        !           975:        {1, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0},
        !           976:        {2, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0},
        !           977:        {3, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16,
        !           978:            AUDIO_ENCODINGFLAG_EMULATED},
        !           979:        {4, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16,
        !           980:            AUDIO_ENCODINGFLAG_EMULATED},
        !           981:        {5, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16,
        !           982:            AUDIO_ENCODINGFLAG_EMULATED},
        !           983:        {6, AudioEmulaw, AUDIO_ENCODING_ULAW, 8,
        !           984:            AUDIO_ENCODINGFLAG_EMULATED},
        !           985:        {7, AudioEalaw, AUDIO_ENCODING_ALAW, 8,
        !           986:            AUDIO_ENCODINGFLAG_EMULATED}
        !           987: };
        !           988:
        !           989: int
        !           990: maestro_query_encoding(hdl, fp)
        !           991:        void *hdl;
        !           992:        struct audio_encoding *fp;
        !           993: {
        !           994:        if (fp->index < 0 || fp->index >= lengthof(maestro_tab))
        !           995:                return (EINVAL);
        !           996:        *fp = maestro_tab[fp->index];
        !           997:        return (0);
        !           998: }
        !           999:
        !          1000: #define UNUSED __attribute__((unused))
        !          1001:
        !          1002: void
        !          1003: maestro_set_speed(ch, prate)
        !          1004:        struct maestro_channel *ch;
        !          1005:        u_long *prate;
        !          1006: {
        !          1007:        ch->speed = *prate;
        !          1008:        if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
        !          1009:                ch->speed /= 2;
        !          1010:
        !          1011:        /* special common case */
        !          1012:        if (ch->speed == 48000) {
        !          1013:                ch->dv = 0x10000;
        !          1014:        } else {
        !          1015:                /* compute 16 bits fixed point value of speed/48000,
        !          1016:                 * being careful not to overflow */
        !          1017:                 ch->dv = (((ch->speed % 48000) << 16U) + 24000) / 48000
        !          1018:                    + ((ch->speed / 48000) << 16U);
        !          1019:                /* And this is the real rate obtained */
        !          1020:                ch->speed = (ch->dv >> 16U) * 48000 +
        !          1021:                    (((ch->dv & 0xffff)*48000)>>16U);
        !          1022:        }
        !          1023:        *prate = ch->speed;
        !          1024:        if ((ch->mode & (MAESTRO_8BIT | MAESTRO_STEREO)) == MAESTRO_8BIT)
        !          1025:                *prate *= 2;
        !          1026: }
        !          1027:
        !          1028: u_int
        !          1029: maestro_calc_timer_freq(ch)
        !          1030:        struct maestro_channel *ch;
        !          1031: {
        !          1032:        u_int   ss = 2;
        !          1033:
        !          1034:        if (ch->mode & MAESTRO_8BIT)
        !          1035:                ss = 1;
        !          1036:        return (ch->speed * ss) / ch->blocksize;
        !          1037: }
        !          1038:
        !          1039: void
        !          1040: maestro_update_timer(sc)
        !          1041:        struct maestro_softc *sc;
        !          1042: {
        !          1043:        u_int freq = 0;
        !          1044:        u_int n;
        !          1045:
        !          1046:        if (sc->play.mode & MAESTRO_RUNNING)
        !          1047:                freq = maestro_calc_timer_freq(&sc->play);
        !          1048:        if (sc->record.mode & MAESTRO_RUNNING) {
        !          1049:                n = maestro_calc_timer_freq(&sc->record);
        !          1050:                if (freq < n)
        !          1051:                        freq = n;
        !          1052:        }
        !          1053:        if (freq) {
        !          1054:                wp_settimer(sc, freq);
        !          1055:                wp_starttimer(sc);
        !          1056:        } else
        !          1057:                wp_stoptimer(sc);
        !          1058: }
        !          1059:
        !          1060:
        !          1061: int
        !          1062: maestro_set_params(hdl, setmode, usemode, play, rec)
        !          1063:        void *hdl;
        !          1064:        int setmode, usemode;
        !          1065:        struct audio_params *play, *rec;
        !          1066: {
        !          1067:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1068:
        !          1069:        if ((setmode & AUMODE_PLAY) == 0)
        !          1070:                return (0);
        !          1071:
        !          1072:        /* Disallow parameter change on a running audio for now */
        !          1073:        if (sc->play.mode & MAESTRO_RUNNING)
        !          1074:                return (EINVAL);
        !          1075:
        !          1076:        if (play->sample_rate < 4000)
        !          1077:                play->sample_rate = 4000;
        !          1078:        else if (play->sample_rate > 48000)
        !          1079:                play->sample_rate = 48000;
        !          1080:
        !          1081:        play->factor = 1;
        !          1082:        play->sw_code = NULL;
        !          1083:        if (play->channels != 1 && play->channels != 2)
        !          1084:                return (EINVAL);
        !          1085:
        !          1086:
        !          1087:        sc->play.mode = MAESTRO_PLAY;
        !          1088:        if (play->channels == 2)
        !          1089:                sc->play.mode |= MAESTRO_STEREO;
        !          1090:
        !          1091:        if (play->encoding == AUDIO_ENCODING_ULAW) {
        !          1092:                play->factor = 2;
        !          1093:                play->sw_code = mulaw_to_slinear16_le;
        !          1094:        } else if (play->encoding == AUDIO_ENCODING_ALAW) {
        !          1095:                play->factor = 2;
        !          1096:                play->sw_code = alaw_to_slinear16_le;
        !          1097:        } else if (play->precision == 8) {
        !          1098:                sc->play.mode |= MAESTRO_8BIT;
        !          1099:                if (play->encoding == AUDIO_ENCODING_ULINEAR_LE ||
        !          1100:                    play->encoding == AUDIO_ENCODING_ULINEAR_BE)
        !          1101:                    sc->play.mode |= MAESTRO_UNSIGNED;
        !          1102:        }
        !          1103:        else if (play->encoding == AUDIO_ENCODING_ULINEAR_LE)
        !          1104:                play->sw_code = change_sign16_le;
        !          1105:        else if (play->encoding == AUDIO_ENCODING_SLINEAR_BE)
        !          1106:                play->sw_code = swap_bytes;
        !          1107:        else if (play->encoding == AUDIO_ENCODING_ULINEAR_BE)
        !          1108:                play->sw_code = change_sign16_swap_bytes_le;
        !          1109:        else if (play->encoding != AUDIO_ENCODING_SLINEAR_LE)
        !          1110:                return (EINVAL);
        !          1111:
        !          1112:        maestro_set_speed(&sc->play, &play->sample_rate);
        !          1113:        return (0);
        !          1114: }
        !          1115:
        !          1116: int
        !          1117: maestro_open(hdl, flags)
        !          1118:        void *hdl;
        !          1119:        int flags;
        !          1120: {
        !          1121:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1122:        DPRINTF(("%s: open(%d)\n", sc->dev.dv_xname, flags));
        !          1123:
        !          1124: /* XXX work around VM brokeness */
        !          1125: #if 0
        !          1126:        if ((OFLAGS(flags) & O_ACCMODE) != O_WRONLY)
        !          1127:                return (EINVAL);
        !          1128: #endif
        !          1129:        sc->play.mode = MAESTRO_PLAY;
        !          1130:        sc->record.mode = 0;
        !          1131: #ifdef AUDIO_DEBUG
        !          1132:        maestrointr_called = 0;
        !          1133:        maestrodma_effective = 0;
        !          1134: #endif
        !          1135:        return (0);
        !          1136: }
        !          1137:
        !          1138: void
        !          1139: maestro_close(hdl)
        !          1140:        void *hdl;
        !          1141: {
        !          1142:        struct maestro_softc *sc UNUSED = (struct maestro_softc *)hdl;
        !          1143:        /* nothing to do */
        !          1144: }
        !          1145:
        !          1146:
        !          1147: void
        !          1148: maestro_channel_stop(ch)
        !          1149:        struct maestro_channel *ch;
        !          1150: {
        !          1151:        wp_apu_write(ch->sc, ch->num, APUREG_APUTYPE,
        !          1152:            APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
        !          1153:        if (ch->mode & MAESTRO_STEREO)
        !          1154:            wp_apu_write(ch->sc, ch->num+1, APUREG_APUTYPE,
        !          1155:                APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
        !          1156:        /* four channels for record... */
        !          1157:        if (ch->mode & MAESTRO_PLAY)
        !          1158:                return;
        !          1159:        wp_apu_write(ch->sc, ch->num+2, APUREG_APUTYPE,
        !          1160:            APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
        !          1161:        if (ch->mode & MAESTRO_STEREO)
        !          1162:            wp_apu_write(ch->sc, ch->num+3, APUREG_APUTYPE,
        !          1163:                APUTYPE_INACTIVE << APU_APUTYPE_SHIFT);
        !          1164:
        !          1165: }
        !          1166:
        !          1167: int
        !          1168: maestro_halt_input(hdl)
        !          1169:        void *hdl;
        !          1170: {
        !          1171:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1172:        maestro_channel_stop(&sc->record);
        !          1173:        sc->record.mode &= ~MAESTRO_RUNNING;
        !          1174:        maestro_update_timer(sc);
        !          1175:        return 0;
        !          1176: }
        !          1177:
        !          1178: int
        !          1179: maestro_halt_output(hdl)
        !          1180:        void *hdl;
        !          1181: {
        !          1182:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1183:
        !          1184:        maestro_channel_stop(&sc->play);
        !          1185:        sc->play.mode &= ~MAESTRO_RUNNING;
        !          1186:        maestro_update_timer(sc);
        !          1187:        return 0;
        !          1188: }
        !          1189:
        !          1190: int
        !          1191: maestro_trigger_input(hdl, start, end, blksize, intr, arg, param)
        !          1192:        void *hdl;
        !          1193:        void *start, *end;
        !          1194:        int blksize;
        !          1195:        void (*intr)(void *);
        !          1196:        void *arg;
        !          1197:        struct audio_params *param;
        !          1198: {
        !          1199:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1200:
        !          1201:        sc->record.mode |= MAESTRO_RUNNING;
        !          1202:        sc->record.blocksize = blksize;
        !          1203:
        !          1204:        maestro_channel_start(&sc->record);
        !          1205:
        !          1206:        sc->record.threshold = sc->record.start;
        !          1207:        maestro_update_timer(sc);
        !          1208:        return 0;
        !          1209: }
        !          1210:
        !          1211: void
        !          1212: maestro_channel_start(ch)
        !          1213:        struct maestro_channel *ch;
        !          1214: {
        !          1215:        struct maestro_softc *sc = ch->sc;
        !          1216:        int n = ch->num;
        !          1217:        int aputype;
        !          1218:        wcreg_t wcreg = (sc->physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK;
        !          1219:
        !          1220:        switch(ch->mode & (MAESTRO_STEREO | MAESTRO_8BIT)) {
        !          1221:        case 0:
        !          1222:                aputype = APUTYPE_16BITLINEAR;
        !          1223:                break;
        !          1224:        case MAESTRO_STEREO:
        !          1225:                aputype = APUTYPE_16BITSTEREO;
        !          1226:                break;
        !          1227:        case MAESTRO_8BIT:
        !          1228:                aputype = APUTYPE_8BITLINEAR;
        !          1229:                break;
        !          1230:        case MAESTRO_8BIT|MAESTRO_STEREO:
        !          1231:                aputype = APUTYPE_8BITSTEREO;
        !          1232:                break;
        !          1233:        }
        !          1234:        if (ch->mode & MAESTRO_UNSIGNED)
        !          1235:                wcreg |= WAVCACHE_CHCTL_U8;
        !          1236:        if ((ch->mode & MAESTRO_STEREO) == 0) {
        !          1237:                DPRINTF(("Setting mono parameters\n"));
        !          1238:                wp_apu_write(sc, n, APUREG_WAVESPACE, ch->wpwa & 0xff00);
        !          1239:                wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
        !          1240:                wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
        !          1241:                wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
        !          1242:                wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
        !          1243:                wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
        !          1244:                    | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
        !          1245:                    | (PAN_FRONT << APU_PAN_SHIFT));
        !          1246:                wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
        !          1247:                    | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
        !          1248:                wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
        !          1249:                wc_ctrl_write(sc, n, wcreg);
        !          1250:                wp_apu_write(sc, n, APUREG_APUTYPE,
        !          1251:                    (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
        !          1252:        } else {
        !          1253:                wcreg |= WAVCACHE_CHCTL_STEREO;
        !          1254:                DPRINTF(("Setting stereo parameters\n"));
        !          1255:                wp_apu_write(sc, n+1, APUREG_WAVESPACE, ch->wpwa & 0xff00);
        !          1256:                wp_apu_write(sc, n+1, APUREG_CURPTR, ch->current);
        !          1257:                wp_apu_write(sc, n+1, APUREG_ENDPTR, ch->end);
        !          1258:                wp_apu_write(sc, n+1, APUREG_LOOPLEN, ch->end - ch->start);
        !          1259:                wp_apu_write(sc, n+1, APUREG_AMPLITUDE, 0xe800);
        !          1260:                wp_apu_write(sc, n+1, APUREG_POSITION, 0x8f00
        !          1261:                    | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
        !          1262:                    | (PAN_LEFT << APU_PAN_SHIFT));
        !          1263:                wp_apu_write(sc, n+1, APUREG_FREQ_LOBYTE, APU_plus6dB
        !          1264:                    | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
        !          1265:                wp_apu_write(sc, n+1, APUREG_FREQ_HIWORD, ch->dv >> 8);
        !          1266:                if (ch->mode & MAESTRO_8BIT)
        !          1267:                        wp_apu_write(sc, n, APUREG_WAVESPACE,
        !          1268:                            ch->wpwa & 0xff00);
        !          1269:                    else
        !          1270:                        wp_apu_write(sc, n, APUREG_WAVESPACE,
        !          1271:                            (ch->wpwa|(APU_STEREO >> 1)) & 0xff00);
        !          1272:                wp_apu_write(sc, n, APUREG_CURPTR, ch->current);
        !          1273:                wp_apu_write(sc, n, APUREG_ENDPTR, ch->end);
        !          1274:                wp_apu_write(sc, n, APUREG_LOOPLEN, ch->end - ch->start);
        !          1275:                wp_apu_write(sc, n, APUREG_AMPLITUDE, 0xe800);
        !          1276:                wp_apu_write(sc, n, APUREG_POSITION, 0x8f00
        !          1277:                    | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT)
        !          1278:                    | (PAN_RIGHT << APU_PAN_SHIFT));
        !          1279:                wp_apu_write(sc, n, APUREG_FREQ_LOBYTE, APU_plus6dB
        !          1280:                    | ((ch->dv & 0xff) << APU_FREQ_LOBYTE_SHIFT));
        !          1281:                wp_apu_write(sc, n, APUREG_FREQ_HIWORD, ch->dv >> 8);
        !          1282:                wc_ctrl_write(sc, n, wcreg);
        !          1283:                wc_ctrl_write(sc, n+1, wcreg);
        !          1284:                wp_apu_write(sc, n, APUREG_APUTYPE,
        !          1285:                    (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
        !          1286:                wp_apu_write(sc, n+1, APUREG_APUTYPE,
        !          1287:                    (aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf);
        !          1288:        }
        !          1289: }
        !          1290:
        !          1291: int
        !          1292: maestro_trigger_output(hdl, start, end, blksize, intr, arg, param)
        !          1293:        void *hdl;
        !          1294:        void *start, *end;
        !          1295:        int blksize;
        !          1296:        void (*intr)(void *);
        !          1297:        void *arg;
        !          1298:        struct audio_params *param;
        !          1299: {
        !          1300:        struct maestro_softc *sc = (struct maestro_softc *)hdl;
        !          1301:
        !          1302:        u_int offset = ((caddr_t)start - sc->dmabase) >> 1;
        !          1303:        u_int size = ((char *)end - (char *)start) >> 1;
        !          1304:        sc->play.mode |= MAESTRO_RUNNING;
        !          1305:        sc->play.wpwa = APU_USE_SYSMEM | (offset >> 8);
        !          1306:        DPRINTF(("maestro_trigger_output: start=%x, end=%x, blksize=%x ",
        !          1307:                start, end, blksize));
        !          1308:        DPRINTF(("offset = %x, size=%x\n", offset, size));
        !          1309:
        !          1310:        sc->play.intr = intr;
        !          1311:        sc->play.intr_arg = arg;
        !          1312:        sc->play.blocksize = blksize;
        !          1313:        sc->play.end = offset+size;
        !          1314:        sc->play.start = offset;
        !          1315:        sc->play.current = sc->play.start;
        !          1316:        if ((sc->play.mode & (MAESTRO_STEREO | MAESTRO_8BIT)) == MAESTRO_STEREO) {
        !          1317:                sc->play.wpwa >>= 1;
        !          1318:                sc->play.start >>= 1;
        !          1319:                sc->play.end >>= 1;
        !          1320:                sc->play.blocksize >>= 1;
        !          1321:        }
        !          1322:        maestro_channel_start(&sc->play);
        !          1323:
        !          1324:        sc->play.threshold = sc->play.start;
        !          1325:        maestro_update_timer(sc);
        !          1326:
        !          1327:        return 0;
        !          1328: }
        !          1329:
        !          1330: /* -----------------------------
        !          1331:  * Codec interface
        !          1332:  */
        !          1333:
        !          1334: int
        !          1335: maestro_read_codec(self, regno, datap)
        !          1336:        void *self;
        !          1337:        u_int8_t regno;
        !          1338:        u_int16_t *datap;
        !          1339: {
        !          1340:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !          1341:        int t;
        !          1342:
        !          1343:        /* We have to wait for a SAFE time to write addr/data */
        !          1344:        for (t = 0; t < 20; t++) {
        !          1345:                if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
        !          1346:                    & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
        !          1347:                        break;
        !          1348:                DELAY(2);       /* 20.8us / 13 */
        !          1349:        }
        !          1350:        if (t == 20)
        !          1351:                printf("%s: maestro_read_codec() PROGLESS timed out.\n",
        !          1352:                    sc->dev.dv_xname);
        !          1353:                /* XXX return 1 */
        !          1354:
        !          1355:        bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
        !          1356:            CODEC_CMD_READ | regno);
        !          1357:        DELAY(21);      /* AC97 cycle = 20.8usec */
        !          1358:
        !          1359:        /* Wait for data retrieve */
        !          1360:        for (t = 0; t < 20; t++) {
        !          1361:                if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
        !          1362:                    & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE)
        !          1363:                        break;
        !          1364:                DELAY(2);       /* 20.8us / 13 */
        !          1365:        }
        !          1366:        if (t == 20)
        !          1367:                /* Timed out, but perform dummy read. */
        !          1368:                printf("%s: maestro_read_codec() RW_DONE timed out.\n",
        !          1369:                    sc->dev.dv_xname);
        !          1370:
        !          1371:        *datap = bus_space_read_2(sc->iot, sc->ioh, PORT_CODEC_REG);
        !          1372:        return 0;
        !          1373: }
        !          1374:
        !          1375: int
        !          1376: maestro_write_codec(self, regno, data)
        !          1377:        void *self;
        !          1378:        u_int8_t regno;
        !          1379:        u_int16_t data;
        !          1380: {
        !          1381:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !          1382:        int t;
        !          1383:
        !          1384:        /* We have to wait for a SAFE time to write addr/data */
        !          1385:        for (t = 0; t < 20; t++) {
        !          1386:                if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
        !          1387:                    & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS)
        !          1388:                        break;
        !          1389:                DELAY(2);       /* 20.8us / 13 */
        !          1390:        }
        !          1391:        if (t == 20) {
        !          1392:                /* Timed out. Abort writing. */
        !          1393:                printf("%s: maestro_write_codec() PROGLESS timed out.\n",
        !          1394:                    sc->dev.dv_xname);
        !          1395:                return 1;
        !          1396:        }
        !          1397:
        !          1398:        bus_space_write_2(sc->iot, sc->ioh, PORT_CODEC_REG, data);
        !          1399:        bus_space_write_1(sc->iot, sc->ioh, PORT_CODEC_CMD,
        !          1400:            CODEC_CMD_WRITE | regno);
        !          1401:
        !          1402:        return 0;
        !          1403: }
        !          1404:
        !          1405: int
        !          1406: maestro_attach_codec(self, cif)
        !          1407:        void *self;
        !          1408:        struct ac97_codec_if *cif;
        !          1409: {
        !          1410:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !          1411:
        !          1412:        sc->codec_if = cif;
        !          1413:        return 0;
        !          1414: }
        !          1415:
        !          1416: void
        !          1417: maestro_reset_codec(self)
        !          1418:        void *self UNUSED;
        !          1419: {
        !          1420: }
        !          1421:
        !          1422: void
        !          1423: maestro_initcodec(self)
        !          1424:        void *self;
        !          1425: {
        !          1426:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !          1427:        u_int16_t data;
        !          1428:
        !          1429:        if (bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL)
        !          1430:            & RINGBUS_CTRL_ACLINK_ENABLED) {
        !          1431:                bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
        !          1432:                DELAY(104);     /* 20.8us * (4 + 1) */
        !          1433:        }
        !          1434:        /* XXX - 2nd codec should be looked at. */
        !          1435:        bus_space_write_4(sc->iot, sc->ioh,
        !          1436:            PORT_RINGBUS_CTRL, RINGBUS_CTRL_AC97_SWRESET);
        !          1437:        DELAY(2);
        !          1438:        bus_space_write_4(sc->iot, sc->ioh,
        !          1439:            PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
        !          1440:        DELAY(21);
        !          1441:
        !          1442:        maestro_read_codec(sc, 0, &data);
        !          1443:        if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT)
        !          1444:            & CODEC_STAT_MASK) != 0) {
        !          1445:                bus_space_write_4(sc->iot, sc->ioh,
        !          1446:                    PORT_RINGBUS_CTRL, 0);
        !          1447:                DELAY(21);
        !          1448:
        !          1449:                /* Try cold reset. */
        !          1450:                printf("%s: resetting codec\n", sc->dev.dv_xname);
        !          1451:
        !          1452:                data = bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DIR);
        !          1453:                if (pci_conf_read(sc->pc, sc->pt, 0x58) & 1)
        !          1454:                        data |= 0x10;
        !          1455:                data |= 0x009 &
        !          1456:                    ~bus_space_read_2(sc->iot, sc->ioh, PORT_GPIO_DATA);
        !          1457:                bus_space_write_2(sc->iot, sc->ioh,
        !          1458:                    PORT_GPIO_MASK, 0xff6);
        !          1459:                bus_space_write_2(sc->iot, sc->ioh,
        !          1460:                    PORT_GPIO_DIR, data | 0x009);
        !          1461:                bus_space_write_2(sc->iot, sc->ioh,
        !          1462:                    PORT_GPIO_DATA, 0x000);
        !          1463:                DELAY(2);
        !          1464:                bus_space_write_2(sc->iot, sc->ioh,
        !          1465:                    PORT_GPIO_DATA, 0x001);
        !          1466:                DELAY(1);
        !          1467:                bus_space_write_2(sc->iot, sc->ioh,
        !          1468:                    PORT_GPIO_DATA, 0x009);
        !          1469:                DELAY(500000);
        !          1470:                bus_space_write_2(sc->iot, sc->ioh,
        !          1471:                    PORT_GPIO_DIR, data);
        !          1472:                DELAY(84);      /* 20.8us * 4 */
        !          1473:                bus_space_write_4(sc->iot, sc->ioh,
        !          1474:                    PORT_RINGBUS_CTRL, RINGBUS_CTRL_ACLINK_ENABLED);
        !          1475:                DELAY(21);
        !          1476:        }
        !          1477:
        !          1478:        /* Check the codec to see is still busy */
        !          1479:        if ((bus_space_read_1(sc->iot, sc->ioh, PORT_CODEC_STAT) &
        !          1480:            CODEC_STAT_MASK) != 0) {
        !          1481:                printf("%s: codec failure\n", sc->dev.dv_xname);
        !          1482:        }
        !          1483: }
        !          1484:
        !          1485: /* -----------------------------
        !          1486:  * Power management interface
        !          1487:  */
        !          1488:
        !          1489: void
        !          1490: maestro_powerhook(why, self)
        !          1491:        int why;
        !          1492:        void *self;
        !          1493: {
        !          1494:        struct maestro_softc *sc = (struct maestro_softc *)self;
        !          1495:
        !          1496:        if (why != PWR_RESUME) {
        !          1497:                /* Power down device on shutdown. */
        !          1498:                DPRINTF(("maestro: power down\n"));
        !          1499:                sc->suspend = why;
        !          1500:                if (sc->record.mode & MAESTRO_RUNNING) {
        !          1501:                        sc->record.current = wp_apu_read(sc, sc->record.num, APUREG_CURPTR);
        !          1502:                        maestro_channel_stop(&sc->record);
        !          1503:                }
        !          1504:                if (sc->play.mode & MAESTRO_RUNNING) {
        !          1505:                        sc->play.current = wp_apu_read(sc, sc->play.num, APUREG_CURPTR);
        !          1506:                        maestro_channel_stop(&sc->play);
        !          1507:                }
        !          1508:
        !          1509:                wp_stoptimer(sc);
        !          1510:
        !          1511:                /* Power down everything except clock. */
        !          1512:                bus_space_write_2(sc->iot, sc->ioh, PORT_HOSTINT_CTRL, 0);
        !          1513:                maestro_write_codec(sc, AC97_REG_POWER, 0xdf00);
        !          1514:                DELAY(20);
        !          1515:                bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, 0);
        !          1516:                DELAY(1);
        !          1517:                maestro_power(sc, PPMI_D3);
        !          1518:        } else {
        !          1519:                /* Power up device on resume. */
        !          1520:                DPRINTF(("maestro: power resume\n"));
        !          1521:                if (sc->suspend == PWR_RESUME) {
        !          1522:                        printf("%s: resume without suspend?\n",
        !          1523:                            sc->dev.dv_xname);
        !          1524:                        sc->suspend = why;
        !          1525:                        return;
        !          1526:                }
        !          1527:                sc->suspend = why;
        !          1528:                maestro_power(sc, PPMI_D0);
        !          1529:                DELAY(100000);
        !          1530:                maestro_init(sc);
        !          1531:                /* Restore codec settings */
        !          1532:                if (sc->codec_if)
        !          1533:                        sc->codec_if->vtbl->restore_ports(sc->codec_if);
        !          1534:                if (sc->play.mode & MAESTRO_RUNNING)
        !          1535:                        maestro_channel_start(&sc->play);
        !          1536:                if (sc->record.mode & MAESTRO_RUNNING)
        !          1537:                        maestro_channel_start(&sc->record);
        !          1538:                maestro_update_timer(sc);
        !          1539:        }
        !          1540: }
        !          1541:
        !          1542: void
        !          1543: maestro_power(sc, status)
        !          1544:        struct maestro_softc *sc;
        !          1545:        int status;
        !          1546: {
        !          1547:        int data;
        !          1548:
        !          1549:        /* Set the power state of the device. */
        !          1550:        data = pci_conf_read(sc->pc, sc->pt, CONF_PM_PTR);
        !          1551:        data = pci_conf_read(sc->pc, sc->pt, data);
        !          1552:        if (data == PPMI_CID)
        !          1553:                pci_conf_write(sc->pc, sc->pt, data + PM_CTRL, status);
        !          1554: }
        !          1555:
        !          1556: void
        !          1557: maestro_channel_advance_dma(ch)
        !          1558:        struct maestro_channel *ch;
        !          1559: {
        !          1560:        wpreg_t pos;
        !          1561: #ifdef AUDIO_DEBUG
        !          1562:        maestrointr_called++;
        !          1563: #endif
        !          1564:        for (;;) {
        !          1565:                pos = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
        !          1566:                /* Are we still processing the current dma block ? */
        !          1567:                if (pos >= ch->threshold &&
        !          1568:                    pos < ch->threshold + ch->blocksize/2)
        !          1569:                        break;
        !          1570:                ch->threshold += ch->blocksize/2;
        !          1571:                if (ch->threshold >= ch->end)
        !          1572:                        ch->threshold = ch->start;
        !          1573:                (*ch->intr)(ch->intr_arg);
        !          1574: #ifdef AUDIO_DEBUG
        !          1575:                maestrodma_effective++;
        !          1576: #endif
        !          1577:        }
        !          1578:
        !          1579: #ifdef AUDIO_DEBUG
        !          1580:        if (maestrodebug && maestrointr_called % 64 == 0)
        !          1581:                printf("maestro: dma advanced %lu for %lu calls\n",
        !          1582:                        maestrodma_effective, maestrointr_called);
        !          1583: #endif
        !          1584: }
        !          1585:
        !          1586: /* Some maestro makes sometimes get desynchronized in stereo mode. */
        !          1587: void
        !          1588: maestro_channel_suppress_jitter(ch)
        !          1589:        struct maestro_channel *ch;
        !          1590: {
        !          1591:        int cp, diff;
        !          1592:
        !          1593:        /* Verify that both channels are not too far off. */
        !          1594:        cp = wp_apu_read(ch->sc, ch->num, APUREG_CURPTR);
        !          1595:        diff = wp_apu_read(ch->sc, ch->num+1, APUREG_CURPTR) - cp;
        !          1596:        if (diff > 4 || diff < -4)
        !          1597:                /* Otherwise, directly resynch the 2nd channel. */
        !          1598:                bus_space_write_2(ch->sc->iot, ch->sc->ioh,
        !          1599:                    PORT_DSP_DATA, cp);
        !          1600: }
        !          1601:
        !          1602: /* -----------------------------
        !          1603:  * Interrupt handler interface
        !          1604:  */
        !          1605: int
        !          1606: maestro_intr(arg)
        !          1607:        void *arg;
        !          1608: {
        !          1609:        struct maestro_softc *sc = (struct maestro_softc *)arg;
        !          1610:        u_int16_t status;
        !          1611:
        !          1612:        status = bus_space_read_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT);
        !          1613:        if (status == 0)
        !          1614:                return 0;       /* Not for us? */
        !          1615:
        !          1616:        /* Acknowledge all. */
        !          1617:        bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
        !          1618:        bus_space_write_1(sc->iot, sc->ioh, PORT_HOSTINT_STAT, status);
        !          1619:
        !          1620:        /* Hardware volume support */
        !          1621:        if (status & HOSTINT_STAT_HWVOL && sc->codec_if != NULL) {
        !          1622:                int n, i, delta, v;
        !          1623:                mixer_ctrl_t hwvol;
        !          1624:
        !          1625:                n = bus_space_read_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER);
        !          1626:                /* Special case: Mute key */
        !          1627:                if (n & 0x11) {
        !          1628:                        hwvol.type = AUDIO_MIXER_ENUM;
        !          1629:                        hwvol.dev =
        !          1630:                            sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
        !          1631:                                AudioCoutputs, AudioNmaster, AudioNmute);
        !          1632:                        sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
        !          1633:                        hwvol.un.ord = !hwvol.un.ord;
        !          1634:                } else {
        !          1635:                        hwvol.type = AUDIO_MIXER_VALUE;
        !          1636:                        hwvol.un.value.num_channels = 2;
        !          1637:                        hwvol.dev =
        !          1638:                            sc->codec_if->vtbl->get_portnum_by_name(
        !          1639:                                sc->codec_if, AudioCoutputs, AudioNmaster,
        !          1640:                                    NULL);
        !          1641:                        sc->codec_if->vtbl->mixer_get_port(sc->codec_if, &hwvol);
        !          1642:                        /* XXX AC'97 yields five bits for master volume. */
        !          1643:                        delta = (n - MIDDLE_VOLUME)/STEP_VOLUME * 8;
        !          1644:                        for (i = 0; i < hwvol.un.value.num_channels; i++) {
        !          1645:                                v = ((int)hwvol.un.value.level[i]) + delta;
        !          1646:                                if (v < 0)
        !          1647:                                        v = 0;
        !          1648:                                else if (v > 255)
        !          1649:                                        v = 255;
        !          1650:                                hwvol.un.value.level[i] = v;
        !          1651:                        }
        !          1652:                }
        !          1653:                sc->codec_if->vtbl->mixer_set_port(sc->codec_if, &hwvol);
        !          1654:                /* Reset to compute next diffs */
        !          1655:                bus_space_write_1(sc->iot, sc->ioh, PORT_HWVOL_MASTER,
        !          1656:                    MIDDLE_VOLUME);
        !          1657:        }
        !          1658:
        !          1659:        if (sc->play.mode & MAESTRO_RUNNING) {
        !          1660:                maestro_channel_advance_dma(&sc->play);
        !          1661:                if (sc->play.mode & MAESTRO_STEREO)
        !          1662:                        maestro_channel_suppress_jitter(&sc->play);
        !          1663:        }
        !          1664:
        !          1665:        if (sc->record.mode & MAESTRO_RUNNING)
        !          1666:                maestro_channel_advance_dma(&sc->record);
        !          1667:
        !          1668:        return 1;
        !          1669: }
        !          1670:
        !          1671: /* -----------------------------
        !          1672:  * Hardware interface
        !          1673:  */
        !          1674:
        !          1675: /* Codec/Ringbus */
        !          1676:
        !          1677: void
        !          1678: ringbus_setdest(struct maestro_softc *sc, int src, int dest)
        !          1679: {
        !          1680:        u_int32_t       data;
        !          1681:
        !          1682:        data = bus_space_read_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL);
        !          1683:        data &= ~(0xfU << src);
        !          1684:        data |= (0xfU & dest) << src;
        !          1685:        bus_space_write_4(sc->iot, sc->ioh, PORT_RINGBUS_CTRL, data);
        !          1686: }
        !          1687:
        !          1688: /* Wave Processor */
        !          1689:
        !          1690: wpreg_t
        !          1691: wp_reg_read(struct maestro_softc *sc, int reg)
        !          1692: {
        !          1693:        bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
        !          1694:        return bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA);
        !          1695: }
        !          1696:
        !          1697: void
        !          1698: wp_reg_write(struct maestro_softc *sc, int reg, wpreg_t data)
        !          1699: {
        !          1700:        bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_INDEX, reg);
        !          1701:        bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
        !          1702: }
        !          1703:
        !          1704: static void
        !          1705: apu_setindex(struct maestro_softc *sc, int reg)
        !          1706: {
        !          1707:        int t;
        !          1708:
        !          1709:        wp_reg_write(sc, WPREG_CRAM_PTR, reg);
        !          1710:        /* Sometimes WP fails to set apu register index. */
        !          1711:        for (t = 0; t < 1000; t++) {
        !          1712:                if (bus_space_read_2(sc->iot, sc->ioh,
        !          1713:                    PORT_DSP_DATA) == reg)
        !          1714:                        break;
        !          1715:                bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, reg);
        !          1716:        }
        !          1717:        if (t == 1000)
        !          1718:                printf("%s: apu_setindex() timeout\n", sc->dev.dv_xname);
        !          1719: }
        !          1720:
        !          1721: wpreg_t
        !          1722: wp_apu_read(struct maestro_softc *sc, int ch, int reg)
        !          1723: {
        !          1724:        wpreg_t ret;
        !          1725:
        !          1726:        apu_setindex(sc, ((unsigned)ch << 4) + reg);
        !          1727:        ret = wp_reg_read(sc, WPREG_DATA_PORT);
        !          1728:        return ret;
        !          1729: }
        !          1730:
        !          1731: void
        !          1732: wp_apu_write(struct maestro_softc *sc, int ch, int reg, wpreg_t data)
        !          1733: {
        !          1734:        int t;
        !          1735:
        !          1736:        apu_setindex(sc, ((unsigned)ch << 4) + reg);
        !          1737:        wp_reg_write(sc, WPREG_DATA_PORT, data);
        !          1738:        for (t = 0; t < 1000; t++) {
        !          1739:                if (bus_space_read_2(sc->iot, sc->ioh, PORT_DSP_DATA) == data)
        !          1740:                        break;
        !          1741:                bus_space_write_2(sc->iot, sc->ioh, PORT_DSP_DATA, data);
        !          1742:        }
        !          1743:        if (t == 1000)
        !          1744:                printf("%s: wp_apu_write() timeout\n", sc->dev.dv_xname);
        !          1745: }
        !          1746:
        !          1747: void
        !          1748: wp_settimer(struct maestro_softc *sc, u_int freq)
        !          1749: {
        !          1750:        u_int clock = 48000 << 2;
        !          1751:        u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0;
        !          1752:
        !          1753:        if (divide < 4)
        !          1754:                divide = 4;
        !          1755:        else if (divide > 32 << 8)
        !          1756:                divide = 32 << 8;
        !          1757:
        !          1758:        for (; divide > 32 << 1; divide >>= 1)
        !          1759:                prescale++;
        !          1760:        divide = (divide + 1) >> 1;
        !          1761:
        !          1762:        for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1)
        !          1763:                prescale++;
        !          1764:
        !          1765:        wp_reg_write(sc, WPREG_TIMER_ENABLE, 0);
        !          1766:        wp_reg_write(sc, WPREG_TIMER_FREQ,
        !          1767:            (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1));
        !          1768:        wp_reg_write(sc, WPREG_TIMER_ENABLE, 1);
        !          1769: }
        !          1770:
        !          1771: void
        !          1772: wp_starttimer(struct maestro_softc *sc)
        !          1773: {
        !          1774:        wp_reg_write(sc, WPREG_TIMER_START, 1);
        !          1775: }
        !          1776:
        !          1777: void
        !          1778: wp_stoptimer(struct maestro_softc *sc)
        !          1779: {
        !          1780:        wp_reg_write(sc, WPREG_TIMER_START, 0);
        !          1781:        bus_space_write_2(sc->iot, sc->ioh, PORT_INT_STAT, 1);
        !          1782: }
        !          1783:
        !          1784: /* WaveCache */
        !          1785:
        !          1786: wcreg_t
        !          1787: wc_reg_read(struct maestro_softc *sc, int reg)
        !          1788: {
        !          1789:        bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
        !          1790:        return bus_space_read_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA);
        !          1791: }
        !          1792:
        !          1793: void
        !          1794: wc_reg_write(struct maestro_softc *sc, int reg, wcreg_t data)
        !          1795: {
        !          1796:        bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_INDEX, reg);
        !          1797:        bus_space_write_2(sc->iot, sc->ioh, PORT_WAVCACHE_DATA, data);
        !          1798: }
        !          1799:
        !          1800: u_int16_t
        !          1801: wc_ctrl_read(struct maestro_softc *sc, int ch)
        !          1802: {
        !          1803:        return wc_reg_read(sc, ch << 3);
        !          1804: }
        !          1805:
        !          1806: void
        !          1807: wc_ctrl_write(struct maestro_softc *sc, int ch, wcreg_t data)
        !          1808: {
        !          1809:        wc_reg_write(sc, ch << 3, data);
        !          1810: }
        !          1811:
        !          1812: /* -----------------------------
        !          1813:  * Simple zone allocator.
        !          1814:  * (All memory allocated in advance)
        !          1815:  */
        !          1816:
        !          1817: salloc_t
        !          1818: salloc_new(addr, size, nzones)
        !          1819:        caddr_t addr;
        !          1820:        size_t size;
        !          1821:        int nzones;
        !          1822: {
        !          1823:        struct salloc_pool *pool;
        !          1824:        struct salloc_zone *space;
        !          1825:        int i;
        !          1826:
        !          1827:        MALLOC(pool, salloc_t, sizeof *pool + nzones * sizeof pool->zones[0],
        !          1828:            M_TEMP, M_NOWAIT);
        !          1829:        if (pool == NULL)
        !          1830:                return NULL;
        !          1831:        SLIST_INIT(&pool->free);
        !          1832:        SLIST_INIT(&pool->used);
        !          1833:        SLIST_INIT(&pool->spare);
        !          1834:        /* Espie says the following line is obvious */
        !          1835:        pool->zones = (struct salloc_zone *)(pool + 1);
        !          1836:        for (i = 1; i < nzones; i++)
        !          1837:                SLIST_INSERT_HEAD(&pool->spare, &pool->zones[i], link);
        !          1838:        space = &pool->zones[0];
        !          1839:        space->addr = addr;
        !          1840:        space->size = size;
        !          1841:        SLIST_INSERT_HEAD(&pool->free, space, link);
        !          1842:        return pool;
        !          1843: }
        !          1844:
        !          1845: void
        !          1846: salloc_destroy(pool)
        !          1847:        salloc_t pool;
        !          1848: {
        !          1849:        FREE(pool, M_TEMP);
        !          1850: }
        !          1851:
        !          1852: void
        !          1853: salloc_insert(pool, head, zone, merge)
        !          1854:        salloc_t pool;
        !          1855:        struct salloc_head *head;
        !          1856:        struct salloc_zone *zone;
        !          1857:        int merge;
        !          1858: {
        !          1859:        struct salloc_zone *prev, *next;
        !          1860:
        !          1861:        /*
        !          1862:         * Insert a zone into an ordered list of zones, possibly
        !          1863:         * merging adjacent zones.
        !          1864:         */
        !          1865:        prev = NULL;
        !          1866:        SLIST_FOREACH(next, head, link) {
        !          1867:                if (next->addr > zone->addr)
        !          1868:                        break;
        !          1869:                prev = next;
        !          1870:        }
        !          1871:
        !          1872:        if (merge && prev && prev->addr + prev->size == zone->addr) {
        !          1873:                prev->size += zone->size;
        !          1874:                SLIST_INSERT_HEAD(&pool->spare, zone, link);
        !          1875:                zone = prev;
        !          1876:        } else if (prev)
        !          1877:                SLIST_INSERT_AFTER(prev, zone, link);
        !          1878:        else
        !          1879:                SLIST_INSERT_HEAD(head, zone, link);
        !          1880:        if (merge && next && zone->addr + zone->size == next->addr) {
        !          1881:                zone->size += next->size;
        !          1882:                SLIST_REMOVE(head, next, salloc_zone, link);
        !          1883:                SLIST_INSERT_HEAD(&pool->spare, next, link);
        !          1884:        }
        !          1885: }
        !          1886:
        !          1887: caddr_t
        !          1888: salloc_alloc(pool, size)
        !          1889:        salloc_t pool;
        !          1890:        size_t size;
        !          1891: {
        !          1892:        struct salloc_zone *zone, *uzone;
        !          1893:
        !          1894:        SLIST_FOREACH(zone, &pool->free, link)
        !          1895:                if (zone->size >= size)
        !          1896:                        break;
        !          1897:        if (zone == SLIST_END(&pool->free))
        !          1898:                return NULL;
        !          1899:        if (zone->size == size) {
        !          1900:                SLIST_REMOVE(&pool->free, zone, salloc_zone, link);
        !          1901:                uzone = zone;
        !          1902:        } else {
        !          1903:                uzone = SLIST_FIRST(&pool->spare);
        !          1904:                if (uzone == NULL)
        !          1905:                        return NULL;            /* XXX */
        !          1906:                SLIST_REMOVE_HEAD(&pool->spare, link);
        !          1907:                uzone->size = size;
        !          1908:                uzone->addr = zone->addr;
        !          1909:                zone->size -= size;
        !          1910:                zone->addr += size;
        !          1911:        }
        !          1912:        salloc_insert(pool, &pool->used, uzone, 0);
        !          1913:        return uzone->addr;
        !          1914: }
        !          1915:
        !          1916: void
        !          1917: salloc_free(pool, addr)
        !          1918:        salloc_t pool;
        !          1919:        caddr_t addr;
        !          1920: {
        !          1921:        struct salloc_zone *zone;
        !          1922:
        !          1923:        SLIST_FOREACH(zone, &pool->used, link)
        !          1924:                if (zone->addr == addr)
        !          1925:                        break;
        !          1926: #ifdef DIAGNOSTIC
        !          1927:        if (zone == SLIST_END(&pool->used))
        !          1928:                panic("salloc_free: freeing unallocated memory");
        !          1929: #endif
        !          1930:        SLIST_REMOVE(&pool->used, zone, salloc_zone, link);
        !          1931:        salloc_insert(pool, &pool->free, zone, 1);
        !          1932: }

CVSweb