Home | History | Annotate | Line # | Download | only in pci
neo.c revision 1.8.4.1
      1  1.8.4.1   thorpej /*	$NetBSD: neo.c,v 1.8.4.1 2001/09/13 01:15:55 thorpej Exp $	*/
      2      1.1   thorpej 
      3      1.1   thorpej /*
      4      1.1   thorpej  * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
      5      1.1   thorpej  * All rights reserved.
      6      1.1   thorpej  *
      7      1.1   thorpej  * Derived from the public domain Linux driver
      8      1.1   thorpej  *
      9      1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     10      1.1   thorpej  * modification, are permitted provided that the following conditions
     11      1.1   thorpej  * are met:
     12      1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     13      1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     14      1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     16      1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     17      1.1   thorpej  *
     18      1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     19      1.1   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20      1.1   thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21      1.1   thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     22      1.1   thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23      1.1   thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24      1.1   thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25      1.1   thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
     26      1.1   thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27      1.1   thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
     28      1.1   thorpej  * SUCH DAMAGE.
     29      1.1   thorpej  *
     30      1.1   thorpej  * FreeBSD: src/sys/dev/sound/pci/neomagic.c,v 1.8 2000/03/20 15:30:50 cg Exp
     31      1.1   thorpej  * OpenBSD: neo.c,v 1.4 2000/07/19 09:04:37 csapuntz Exp
     32      1.1   thorpej  */
     33      1.1   thorpej 
     34      1.1   thorpej #include <sys/param.h>
     35      1.1   thorpej #include <sys/systm.h>
     36      1.1   thorpej #include <sys/kernel.h>
     37      1.1   thorpej #include <sys/malloc.h>
     38      1.1   thorpej #include <sys/device.h>
     39      1.1   thorpej 
     40      1.1   thorpej #include <machine/bus.h>
     41      1.1   thorpej 
     42      1.1   thorpej #include <dev/pci/pcidevs.h>
     43      1.1   thorpej #include <dev/pci/pcivar.h>
     44      1.1   thorpej 
     45      1.1   thorpej #include <dev/pci/neoreg.h>
     46      1.1   thorpej #include <dev/pci/neo-coeff.h>
     47      1.1   thorpej 
     48      1.1   thorpej #include <sys/audioio.h>
     49      1.1   thorpej #include <dev/audio_if.h>
     50      1.1   thorpej #include <dev/mulaw.h>
     51      1.1   thorpej #include <dev/auconv.h>
     52      1.1   thorpej 
     53      1.1   thorpej #include <dev/ic/ac97var.h>
     54      1.1   thorpej 
     55      1.1   thorpej 
     56      1.1   thorpej /* -------------------------------------------------------------------- */
     57      1.1   thorpej /*
     58      1.1   thorpej  * As of 04/13/00, public documentation on the Neomagic 256 is not available.
     59      1.1   thorpej  * These comments were gleaned by looking at the driver carefully.
     60      1.1   thorpej  *
     61      1.1   thorpej  * The Neomagic 256 AV/ZX chips provide both video and audio capabilities
     62      1.1   thorpej  * on one chip. About 2-6 megabytes of memory are associated with
     63      1.1   thorpej  * the chip. Most of this goes to video frame buffers, but some is used for
     64      1.1   thorpej  * audio buffering
     65      1.1   thorpej  *
     66      1.1   thorpej  * Unlike most PCI audio chips, the Neomagic chip does not rely on DMA.
     67      1.1   thorpej  * Instead, the chip allows you to carve out two ring buffers out of its
     68      1.1   thorpej  * memory. However you carve this and how much you can carve seems to be
     69      1.1   thorpej  * voodoo. The algorithm is in nm_init.
     70      1.1   thorpej  *
     71      1.1   thorpej  * Most Neomagic audio chips use the AC-97 codec interface. However, there
     72      1.1   thorpej  * seem to be a select few chips 256AV chips that do not support AC-97.
     73      1.1   thorpej  * This driver does not support them but there are rumors that it
     74      1.1   thorpej  * mgiht work with wss isa drivers. This might require some playing around
     75      1.1   thorpej  * with your BIOS.
     76      1.1   thorpej  *
     77      1.1   thorpej  * The Neomagic 256 AV/ZX have 2 PCI I/O region descriptors. Both of
     78      1.1   thorpej  * them describe a memory region. The frame buffer is the first region
     79      1.1   thorpej  * and the register set is the secodn region.
     80      1.1   thorpej  *
     81      1.1   thorpej  * The register manipulation logic is taken from the Linux driver,
     82      1.1   thorpej  * which is in the public domain.
     83      1.1   thorpej  *
     84      1.1   thorpej  * The Neomagic is even nice enough to map the AC-97 codec registers into
     85      1.1   thorpej  * the register space to allow direct manipulation. Watch out, accessing
     86      1.1   thorpej  * AC-97 registers on the Neomagic requires great delicateness, otherwise
     87      1.1   thorpej  * the thing will hang the PCI bus, rendering your system frozen.
     88      1.1   thorpej  *
     89      1.1   thorpej  * For one, it seems the Neomagic status register that reports AC-97
     90      1.1   thorpej  * readiness should NOT be polled more often than once each 1ms.
     91      1.1   thorpej  *
     92      1.1   thorpej  * Also, writes to the AC-97 register space may take order 40us to
     93      1.1   thorpej  * complete.
     94      1.1   thorpej  *
     95      1.1   thorpej  * Unlike many sound engines, the Neomagic does not support (as fas as
     96      1.1   thorpej  * we know :) the notion of interrupting every n bytes transferred,
     97      1.1   thorpej  * unlike many DMA engines.  Instead, it allows you to specify one
     98      1.1   thorpej  * location in each ring buffer (called the watermark). When the chip
     99      1.1   thorpej  * passes that location while playing, it signals an interrupt.
    100      1.1   thorpej  *
    101      1.1   thorpej  * The ring buffer size is currently 16k. That is about 100ms of audio
    102      1.1   thorpej  * at 44.1khz/stero/16 bit. However, to keep the buffer full, interrupts
    103      1.1   thorpej  * are generated more often than that, so 20-40 interrupts per second
    104      1.1   thorpej  * should not be unexpected. Increasing BUFFSIZE should help minimize
    105      1.1   thorpej  * of glitches due to drivers that spend to much time looping at high
    106      1.1   thorpej  * privelege levels as well as the impact of badly written audio
    107      1.1   thorpej  * interface clients.
    108      1.1   thorpej  *
    109      1.1   thorpej  * TO-DO list:
    110      1.1   thorpej  *    Figure out interaction with video stuff (look at Xfree86 driver?)
    111      1.1   thorpej  *
    112      1.1   thorpej  *    Figure out how to shrink that huge table neo-coeff.h
    113      1.1   thorpej  */
    114      1.1   thorpej 
    115      1.1   thorpej #define	NM_BUFFSIZE	16384
    116      1.1   thorpej 
    117      1.1   thorpej /* device private data */
    118      1.1   thorpej struct neo_softc {
    119      1.1   thorpej 	struct          device dev;
    120      1.1   thorpej 
    121      1.1   thorpej 	bus_space_tag_t bufiot;
    122      1.1   thorpej 	bus_space_handle_t  bufioh;
    123      1.1   thorpej 
    124      1.1   thorpej 	bus_space_tag_t regiot;
    125      1.1   thorpej 	bus_space_handle_t  regioh;
    126      1.1   thorpej 
    127      1.1   thorpej 	u_int32_t 	type;
    128      1.1   thorpej 	void            *ih;
    129      1.1   thorpej 
    130      1.1   thorpej 	void	(*pintr)(void *);	/* dma completion intr handler */
    131      1.1   thorpej 	void	*parg;		/* arg for intr() */
    132      1.1   thorpej 
    133      1.1   thorpej 	void	(*rintr)(void *);	/* dma completion intr handler */
    134      1.1   thorpej 	void	*rarg;		/* arg for intr() */
    135      1.1   thorpej 
    136      1.1   thorpej 	vaddr_t	buf_vaddr;
    137      1.1   thorpej 	vaddr_t	rbuf_vaddr;
    138      1.1   thorpej 	vaddr_t	pbuf_vaddr;
    139      1.1   thorpej 	int	pbuf_allocated;
    140      1.1   thorpej 	int	rbuf_allocated;
    141      1.1   thorpej 
    142      1.3   thorpej 	bus_addr_t buf_pciaddr;
    143      1.3   thorpej 	bus_addr_t rbuf_pciaddr;
    144      1.3   thorpej 	bus_addr_t pbuf_pciaddr;
    145      1.3   thorpej 
    146      1.1   thorpej 	u_int32_t 	ac97_base, ac97_status, ac97_busy;
    147      1.1   thorpej 	u_int32_t	buftop, pbuf, rbuf, cbuf, acbuf;
    148      1.1   thorpej 	u_int32_t	playint, recint, misc1int, misc2int;
    149      1.1   thorpej 	u_int32_t	irsz, badintr;
    150      1.1   thorpej 
    151      1.1   thorpej         u_int32_t       pbufsize;
    152      1.1   thorpej         u_int32_t       rbufsize;
    153      1.1   thorpej 
    154      1.1   thorpej 	u_int32_t       pblksize;
    155      1.1   thorpej 	u_int32_t       rblksize;
    156      1.1   thorpej 
    157      1.1   thorpej         u_int32_t       pwmark;
    158      1.1   thorpej         u_int32_t       rwmark;
    159      1.1   thorpej 
    160      1.1   thorpej 	struct ac97_codec_if *codec_if;
    161      1.5  sommerfe 	struct ac97_host_if host_if;
    162      1.5  sommerfe 
    163      1.5  sommerfe 	void		*powerhook;
    164      1.1   thorpej };
    165      1.1   thorpej 
    166      1.1   thorpej /* -------------------------------------------------------------------- */
    167      1.1   thorpej 
    168      1.1   thorpej /*
    169      1.1   thorpej  * prototypes
    170      1.1   thorpej  */
    171      1.1   thorpej 
    172      1.1   thorpej static int	nm_waitcd(struct neo_softc *sc);
    173      1.1   thorpej static int	nm_loadcoeff(struct neo_softc *sc, int dir, int num);
    174      1.1   thorpej static int	nm_init(struct neo_softc *);
    175      1.1   thorpej 
    176      1.1   thorpej int	neo_match(struct device *, struct cfdata *, void *);
    177      1.1   thorpej void	neo_attach(struct device *, struct device *, void *);
    178      1.1   thorpej int	neo_intr(void *);
    179      1.1   thorpej 
    180      1.1   thorpej int	neo_open(void *, int);
    181      1.1   thorpej void	neo_close(void *);
    182      1.1   thorpej int	neo_query_encoding(void *, struct audio_encoding *);
    183      1.1   thorpej int	neo_set_params(void *, int, int, struct audio_params *,
    184      1.1   thorpej 	    struct audio_params *);
    185      1.1   thorpej int	neo_round_blocksize(void *, int);
    186      1.1   thorpej int	neo_trigger_output(void *, void *, void *, int, void (*)(void *),
    187      1.1   thorpej 	    void *, struct audio_params *);
    188      1.1   thorpej int	neo_trigger_input(void *, void *, void *, int, void (*)(void *),
    189      1.1   thorpej 	    void *, struct audio_params *);
    190      1.1   thorpej int	neo_halt_output(void *);
    191      1.1   thorpej int	neo_halt_input(void *);
    192      1.1   thorpej int	neo_getdev(void *, struct audio_device *);
    193      1.1   thorpej int	neo_mixer_set_port(void *, mixer_ctrl_t *);
    194      1.1   thorpej int	neo_mixer_get_port(void *, mixer_ctrl_t *);
    195      1.1   thorpej int     neo_attach_codec(void *sc, struct ac97_codec_if *);
    196      1.1   thorpej int	neo_read_codec(void *sc, u_int8_t a, u_int16_t *d);
    197      1.1   thorpej int	neo_write_codec(void *sc, u_int8_t a, u_int16_t d);
    198      1.1   thorpej void    neo_reset_codec(void *sc);
    199      1.1   thorpej enum ac97_host_flags neo_flags_codec(void *sc);
    200      1.1   thorpej int	neo_query_devinfo(void *, mixer_devinfo_t *);
    201      1.1   thorpej void   *neo_malloc(void *, int, size_t, int, int);
    202      1.1   thorpej void	neo_free(void *, void *, int);
    203      1.1   thorpej size_t	neo_round_buffersize(void *, int, size_t);
    204      1.3   thorpej paddr_t	neo_mappage(void *, void *, off_t, int);
    205      1.1   thorpej int	neo_get_props(void *);
    206      1.1   thorpej void	neo_set_mixer(struct neo_softc *sc, int a, int d);
    207      1.5  sommerfe void	neo_power(int why, void *arg);
    208      1.1   thorpej 
    209      1.1   thorpej struct cfattach neo_ca = {
    210      1.1   thorpej 	sizeof(struct neo_softc), neo_match, neo_attach
    211      1.1   thorpej };
    212      1.1   thorpej 
    213      1.1   thorpej struct audio_device neo_device = {
    214      1.1   thorpej 	"NeoMagic 256",
    215      1.1   thorpej 	"",
    216      1.1   thorpej 	"neo"
    217      1.1   thorpej };
    218      1.1   thorpej 
    219      1.1   thorpej /* The actual rates supported by the card. */
    220      1.1   thorpej static const int samplerates[9] = {
    221      1.1   thorpej 	8000,
    222      1.1   thorpej 	11025,
    223      1.1   thorpej 	16000,
    224      1.1   thorpej 	22050,
    225      1.1   thorpej 	24000,
    226      1.1   thorpej 	32000,
    227      1.1   thorpej 	44100,
    228      1.1   thorpej 	48000,
    229      1.1   thorpej 	99999999
    230      1.1   thorpej };
    231      1.1   thorpej 
    232      1.1   thorpej /* -------------------------------------------------------------------- */
    233      1.1   thorpej 
    234      1.1   thorpej struct audio_hw_if neo_hw_if = {
    235      1.1   thorpej 	neo_open,
    236      1.1   thorpej 	neo_close,
    237      1.1   thorpej 	NULL,				/* drain */
    238      1.1   thorpej 	neo_query_encoding,
    239      1.1   thorpej 	neo_set_params,
    240      1.1   thorpej 	neo_round_blocksize,
    241      1.1   thorpej 	NULL,				/* commit_setting */
    242      1.1   thorpej 	NULL,				/* init_output */
    243      1.1   thorpej 	NULL,				/* init_input */
    244      1.1   thorpej 	NULL,				/* start_output */
    245      1.1   thorpej 	NULL,				/* start_input */
    246      1.1   thorpej 	neo_halt_output,
    247      1.1   thorpej 	neo_halt_input,
    248      1.1   thorpej 	NULL,				/* speaker_ctl */
    249      1.1   thorpej 	neo_getdev,
    250      1.1   thorpej 	NULL,				/* getfd */
    251      1.1   thorpej 	neo_mixer_set_port,
    252      1.1   thorpej 	neo_mixer_get_port,
    253      1.1   thorpej 	neo_query_devinfo,
    254      1.1   thorpej 	neo_malloc,
    255      1.1   thorpej 	neo_free,
    256      1.1   thorpej 	neo_round_buffersize,
    257      1.3   thorpej 	neo_mappage,
    258      1.1   thorpej 	neo_get_props,
    259      1.1   thorpej 	neo_trigger_output,
    260      1.1   thorpej 	neo_trigger_input,
    261      1.1   thorpej };
    262      1.1   thorpej 
    263      1.1   thorpej /* -------------------------------------------------------------------- */
    264      1.1   thorpej 
    265      1.1   thorpej #define	nm_rd_1(sc, regno)						\
    266      1.1   thorpej 	bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
    267      1.1   thorpej 
    268      1.1   thorpej #define	nm_rd_2(sc, regno)						\
    269      1.1   thorpej 	bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
    270      1.1   thorpej 
    271      1.1   thorpej #define	nm_rd_4(sc, regno)						\
    272      1.1   thorpej 	bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
    273      1.1   thorpej 
    274      1.1   thorpej #define	nm_wr_1(sc, regno, val)						\
    275      1.1   thorpej 	bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
    276      1.1   thorpej 
    277      1.1   thorpej #define	nm_wr_2(sc, regno, val)						\
    278      1.1   thorpej 	bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
    279      1.1   thorpej 
    280      1.1   thorpej #define	nm_wr_4(sc, regno, val)						\
    281      1.1   thorpej 	bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
    282      1.1   thorpej 
    283      1.1   thorpej #define	nm_rdbuf_4(sc, regno)						\
    284      1.1   thorpej 	bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
    285      1.1   thorpej 
    286      1.1   thorpej #define	nm_wrbuf_1(sc, regno, val)					\
    287      1.1   thorpej 	bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
    288      1.1   thorpej 
    289      1.1   thorpej /* ac97 codec */
    290      1.1   thorpej static int
    291      1.1   thorpej nm_waitcd(struct neo_softc *sc)
    292      1.1   thorpej {
    293      1.1   thorpej 	int cnt = 10;
    294      1.1   thorpej 	int fail = 1;
    295      1.1   thorpej 
    296      1.1   thorpej 	while (cnt-- > 0) {
    297      1.1   thorpej 		if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
    298      1.1   thorpej 			DELAY(100);
    299      1.1   thorpej 		else {
    300      1.1   thorpej 		        fail = 0;
    301      1.1   thorpej 			break;
    302      1.1   thorpej 		}
    303      1.1   thorpej 	}
    304      1.1   thorpej 	return (fail);
    305      1.1   thorpej }
    306      1.1   thorpej 
    307      1.1   thorpej 
    308      1.1   thorpej static void
    309      1.1   thorpej nm_ackint(struct neo_softc *sc, u_int32_t num)
    310      1.1   thorpej {
    311      1.1   thorpej 
    312      1.1   thorpej 	switch (sc->type) {
    313      1.1   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    314      1.1   thorpej 		nm_wr_2(sc, NM_INT_REG, num << 1);
    315      1.1   thorpej 		break;
    316      1.1   thorpej 
    317      1.1   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    318      1.1   thorpej 		nm_wr_4(sc, NM_INT_REG, num);
    319      1.1   thorpej 		break;
    320      1.1   thorpej 	}
    321      1.1   thorpej }
    322      1.1   thorpej 
    323      1.1   thorpej static int
    324      1.1   thorpej nm_loadcoeff(struct neo_softc *sc, int dir, int num)
    325      1.1   thorpej {
    326      1.1   thorpej 	int ofs, sz, i;
    327      1.1   thorpej 	u_int32_t addr;
    328      1.1   thorpej 
    329      1.1   thorpej 	addr = (dir == AUMODE_PLAY)? 0x01c : 0x21c;
    330      1.1   thorpej 	if (dir == AUMODE_RECORD)
    331      1.1   thorpej 		num += 8;
    332      1.1   thorpej 	sz = coefficientSizes[num];
    333      1.1   thorpej 	ofs = 0;
    334      1.1   thorpej 	while (num-- > 0)
    335      1.1   thorpej 		ofs+= coefficientSizes[num];
    336      1.1   thorpej 	for (i = 0; i < sz; i++)
    337      1.1   thorpej 		nm_wrbuf_1(sc, sc->cbuf + i, coefficients[ofs + i]);
    338      1.1   thorpej 	nm_wr_4(sc, addr, sc->cbuf);
    339      1.1   thorpej 	if (dir == AUMODE_PLAY)
    340      1.1   thorpej 		sz--;
    341      1.1   thorpej 	nm_wr_4(sc, addr + 4, sc->cbuf + sz);
    342      1.1   thorpej 	return 0;
    343      1.1   thorpej }
    344      1.1   thorpej 
    345      1.1   thorpej /* The interrupt handler */
    346      1.1   thorpej int
    347      1.1   thorpej neo_intr(void *p)
    348      1.1   thorpej {
    349      1.1   thorpej 	struct neo_softc *sc = (struct neo_softc *)p;
    350      1.1   thorpej 	int status, x, active;
    351      1.1   thorpej 	int rv = 0;
    352      1.1   thorpej 
    353      1.1   thorpej 	active = (sc->pintr || sc->rintr);
    354      1.1   thorpej 	status = (sc->irsz == 2) ?
    355      1.1   thorpej 	    nm_rd_2(sc, NM_INT_REG) :
    356      1.1   thorpej 	    nm_rd_4(sc, NM_INT_REG);
    357      1.1   thorpej 
    358      1.1   thorpej 	if (status & sc->playint) {
    359      1.1   thorpej 		status &= ~sc->playint;
    360      1.1   thorpej 
    361      1.1   thorpej 		sc->pwmark += sc->pblksize;
    362      1.1   thorpej 		sc->pwmark %= sc->pbufsize;
    363      1.1   thorpej 
    364      1.1   thorpej 		nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
    365      1.1   thorpej 
    366      1.1   thorpej 		nm_ackint(sc, sc->playint);
    367      1.1   thorpej 
    368      1.1   thorpej 		if (sc->pintr)
    369      1.1   thorpej 			(*sc->pintr)(sc->parg);
    370      1.1   thorpej 
    371      1.1   thorpej 		rv = 1;
    372      1.1   thorpej 	}
    373      1.1   thorpej 	if (status & sc->recint) {
    374      1.1   thorpej 		status &= ~sc->recint;
    375      1.1   thorpej 
    376      1.1   thorpej 		sc->rwmark += sc->rblksize;
    377      1.1   thorpej 		sc->rwmark %= sc->rbufsize;
    378      1.1   thorpej 
    379      1.1   thorpej 		nm_ackint(sc, sc->recint);
    380      1.1   thorpej 		if (sc->rintr)
    381      1.1   thorpej 			(*sc->rintr)(sc->rarg);
    382      1.1   thorpej 
    383      1.1   thorpej 		rv = 1;
    384      1.1   thorpej 	}
    385      1.1   thorpej 	if (status & sc->misc1int) {
    386      1.1   thorpej 		status &= ~sc->misc1int;
    387      1.1   thorpej 		nm_ackint(sc, sc->misc1int);
    388      1.1   thorpej 		x = nm_rd_1(sc, 0x400);
    389      1.1   thorpej 		nm_wr_1(sc, 0x400, x | 2);
    390      1.1   thorpej 		printf("%s: misc int 1\n", sc->dev.dv_xname);
    391      1.1   thorpej 		rv = 1;
    392      1.1   thorpej 	}
    393      1.1   thorpej 	if (status & sc->misc2int) {
    394      1.1   thorpej 		status &= ~sc->misc2int;
    395      1.1   thorpej 		nm_ackint(sc, sc->misc2int);
    396      1.1   thorpej 		x = nm_rd_1(sc, 0x400);
    397      1.1   thorpej 		nm_wr_1(sc, 0x400, x & ~2);
    398      1.1   thorpej 		printf("%s: misc int 2\n", sc->dev.dv_xname);
    399      1.1   thorpej 		rv = 1;
    400      1.1   thorpej 	}
    401      1.1   thorpej 	if (status) {
    402      1.1   thorpej 		status &= ~sc->misc2int;
    403      1.1   thorpej 		nm_ackint(sc, sc->misc2int);
    404      1.1   thorpej 		printf("%s: unknown int\n", sc->dev.dv_xname);
    405      1.1   thorpej 		rv = 1;
    406      1.1   thorpej 	}
    407      1.1   thorpej 
    408      1.1   thorpej 	return (rv);
    409      1.1   thorpej }
    410      1.1   thorpej 
    411      1.1   thorpej /* -------------------------------------------------------------------- */
    412      1.1   thorpej 
    413      1.1   thorpej /*
    414      1.1   thorpej  * Probe and attach the card
    415      1.1   thorpej  */
    416      1.1   thorpej 
    417      1.1   thorpej static int
    418      1.1   thorpej nm_init(struct neo_softc *sc)
    419      1.1   thorpej {
    420      1.1   thorpej 	u_int32_t ofs, i;
    421      1.1   thorpej 
    422      1.1   thorpej 	switch (sc->type) {
    423      1.1   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    424      1.1   thorpej 		sc->ac97_base = NM_MIXER_OFFSET;
    425      1.1   thorpej 		sc->ac97_status = NM_MIXER_STATUS_OFFSET;
    426      1.1   thorpej 		sc->ac97_busy = NM_MIXER_READY_MASK;
    427      1.1   thorpej 
    428      1.1   thorpej 		sc->buftop = 2560 * 1024;
    429      1.1   thorpej 
    430      1.1   thorpej 		sc->irsz = 2;
    431      1.1   thorpej 		sc->playint = NM_PLAYBACK_INT;
    432      1.1   thorpej 		sc->recint = NM_RECORD_INT;
    433      1.1   thorpej 		sc->misc1int = NM_MISC_INT_1;
    434      1.1   thorpej 		sc->misc2int = NM_MISC_INT_2;
    435      1.1   thorpej 		break;
    436      1.1   thorpej 
    437      1.1   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    438      1.1   thorpej 		sc->ac97_base = NM_MIXER_OFFSET;
    439      1.1   thorpej 		sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
    440      1.1   thorpej 		sc->ac97_busy = NM2_MIXER_READY_MASK;
    441      1.1   thorpej 
    442      1.1   thorpej 		sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
    443      1.1   thorpej 
    444      1.1   thorpej 		sc->irsz = 4;
    445      1.1   thorpej 		sc->playint = NM2_PLAYBACK_INT;
    446      1.1   thorpej 		sc->recint = NM2_RECORD_INT;
    447      1.1   thorpej 		sc->misc1int = NM2_MISC_INT_1;
    448      1.1   thorpej 		sc->misc2int = NM2_MISC_INT_2;
    449      1.1   thorpej 		break;
    450      1.1   thorpej #ifdef DIAGNOSTIC
    451      1.1   thorpej 	default:
    452      1.1   thorpej 		panic("nm_init: impossible");
    453      1.1   thorpej #endif
    454      1.1   thorpej 	}
    455      1.1   thorpej 
    456      1.1   thorpej 	sc->badintr = 0;
    457      1.1   thorpej 	ofs = sc->buftop - 0x0400;
    458      1.1   thorpej 	sc->buftop -= 0x1400;
    459      1.1   thorpej 
    460      1.1   thorpej  	if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
    461      1.1   thorpej 		i = nm_rdbuf_4(sc, ofs + 4);
    462      1.1   thorpej 		if (i != 0 && i != 0xffffffff)
    463      1.1   thorpej 			sc->buftop = i;
    464      1.1   thorpej 	}
    465      1.1   thorpej 
    466      1.1   thorpej 	sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
    467      1.1   thorpej 	sc->rbuf = sc->cbuf - NM_BUFFSIZE;
    468      1.1   thorpej 	sc->pbuf = sc->rbuf - NM_BUFFSIZE;
    469      1.1   thorpej 	sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
    470      1.1   thorpej 
    471      1.1   thorpej 	sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
    472      1.1   thorpej 	sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
    473      1.1   thorpej 	sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
    474      1.1   thorpej 
    475      1.3   thorpej 	sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
    476      1.3   thorpej 	sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
    477      1.3   thorpej 
    478      1.1   thorpej 	nm_wr_1(sc, 0, 0x11);
    479      1.1   thorpej 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
    480      1.1   thorpej 	nm_wr_2(sc, 0x214, 0);
    481      1.1   thorpej 
    482      1.1   thorpej 	return 0;
    483      1.1   thorpej }
    484      1.1   thorpej 
    485      1.2   thorpej int
    486      1.2   thorpej neo_match(struct device *parent, struct cfdata *match, void *aux)
    487      1.2   thorpej {
    488      1.2   thorpej 	struct pci_attach_args *pa = aux;
    489      1.2   thorpej 	pcireg_t subdev;
    490      1.2   thorpej 
    491      1.2   thorpej 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
    492      1.2   thorpej 		return (0);
    493      1.2   thorpej 
    494      1.2   thorpej 	subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
    495      1.2   thorpej 
    496      1.2   thorpej 	switch (PCI_PRODUCT(pa->pa_id)) {
    497      1.2   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    498      1.2   thorpej 		/*
    499      1.2   thorpej 		 * We have to weed-out the non-AC'97 versions of
    500      1.2   thorpej 		 * the chip (i.e. the ones that are known to work
    501      1.2   thorpej 		 * in WSS emulation mode), as they won't work with
    502      1.2   thorpej 		 * this driver.
    503      1.2   thorpej 		 */
    504      1.2   thorpej 		switch (PCI_VENDOR(subdev)) {
    505      1.2   thorpej 		case PCI_VENDOR_DELL:
    506      1.2   thorpej 			switch (PCI_PRODUCT(subdev)) {
    507      1.2   thorpej 			case 0x008f:
    508      1.2   thorpej 				return (0);
    509      1.2   thorpej 			}
    510      1.2   thorpej 			break;
    511      1.2   thorpej 
    512      1.2   thorpej 		case PCI_VENDOR_HP:
    513      1.2   thorpej 			switch (PCI_PRODUCT(subdev)) {
    514      1.2   thorpej 			case 0x0007:
    515      1.2   thorpej 				return (0);
    516      1.2   thorpej 			}
    517      1.8  drochner 			break;
    518      1.8  drochner 
    519      1.8  drochner 		case PCI_VENDOR_IBM:
    520      1.8  drochner 			switch (PCI_PRODUCT(subdev)) {
    521      1.8  drochner 			case 0x00dd:
    522      1.8  drochner 				return (0);
    523      1.8  drochner 			}
    524      1.8  drochner 			break;
    525      1.2   thorpej 		}
    526      1.2   thorpej 		return (1);
    527      1.2   thorpej 
    528      1.2   thorpej 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    529      1.2   thorpej 		return (1);
    530      1.2   thorpej 	}
    531      1.2   thorpej 
    532      1.2   thorpej 	return (0);
    533      1.2   thorpej }
    534      1.2   thorpej 
    535      1.1   thorpej void
    536      1.5  sommerfe neo_power(int why, void *addr)
    537      1.5  sommerfe {
    538      1.5  sommerfe 	struct neo_softc *sc = (struct neo_softc *)addr;
    539      1.5  sommerfe 
    540      1.5  sommerfe 	if (why == PWR_RESUME) {
    541      1.5  sommerfe 		nm_init(sc);
    542      1.5  sommerfe 		(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
    543      1.5  sommerfe 	}
    544      1.5  sommerfe }
    545      1.5  sommerfe 
    546      1.5  sommerfe void
    547      1.1   thorpej neo_attach(struct device *parent, struct device *self, void *aux)
    548      1.1   thorpej {
    549      1.1   thorpej 	struct neo_softc *sc = (struct neo_softc *)self;
    550      1.1   thorpej 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
    551      1.1   thorpej 	pci_chipset_tag_t pc = pa->pa_pc;
    552      1.1   thorpej 	char const *intrstr;
    553      1.1   thorpej 	pci_intr_handle_t ih;
    554      1.1   thorpej 	pcireg_t csr;
    555      1.1   thorpej 	int error;
    556      1.1   thorpej 
    557      1.1   thorpej 	sc->type = PCI_PRODUCT(pa->pa_id);
    558      1.1   thorpej 
    559      1.1   thorpej 	printf(": NeoMagic 256%s audio\n",
    560      1.1   thorpej 	    sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
    561      1.1   thorpej 
    562      1.1   thorpej 	/* Map I/O register */
    563      1.1   thorpej 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
    564      1.3   thorpej 			   &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
    565      1.1   thorpej 		printf("%s: can't map buffer\n", sc->dev.dv_xname);
    566      1.1   thorpej 		return;
    567      1.1   thorpej 	}
    568      1.1   thorpej 
    569      1.1   thorpej 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM, 0,
    570      1.1   thorpej 			   &sc->regiot, &sc->regioh, NULL, NULL)) {
    571      1.1   thorpej 		printf("%s: can't map registers\n", sc->dev.dv_xname);
    572      1.1   thorpej 		return;
    573      1.1   thorpej 	}
    574      1.1   thorpej 
    575      1.1   thorpej 	/* Map and establish the interrupt. */
    576      1.7  sommerfe 	if (pci_intr_map(pa, &ih)) {
    577      1.1   thorpej 		printf("%s: couldn't map interrupt\n", sc->dev.dv_xname);
    578      1.1   thorpej 		return;
    579      1.1   thorpej 	}
    580      1.1   thorpej 
    581      1.1   thorpej 	intrstr = pci_intr_string(pc, ih);
    582      1.1   thorpej 	sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
    583      1.1   thorpej 
    584      1.1   thorpej 	if (sc->ih == NULL) {
    585      1.1   thorpej 		printf("%s: couldn't establish interrupt",
    586      1.1   thorpej 		       sc->dev.dv_xname);
    587      1.1   thorpej 		if (intrstr != NULL)
    588      1.1   thorpej 			printf(" at %s", intrstr);
    589      1.1   thorpej 		printf("\n");
    590      1.1   thorpej 		return;
    591      1.1   thorpej 	}
    592      1.1   thorpej 	printf("%s: interruping at %s\n", sc->dev.dv_xname, intrstr);
    593      1.1   thorpej 
    594      1.1   thorpej 	if ((error = nm_init(sc)) != 0)
    595      1.1   thorpej 		return;
    596      1.1   thorpej 
    597      1.1   thorpej 	/* Enable the device. */
    598      1.1   thorpej 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
    599      1.1   thorpej 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    600      1.1   thorpej 		       csr | PCI_COMMAND_MASTER_ENABLE);
    601      1.1   thorpej 
    602      1.1   thorpej 	sc->host_if.arg = sc;
    603      1.1   thorpej 
    604      1.1   thorpej 	sc->host_if.attach = neo_attach_codec;
    605      1.1   thorpej 	sc->host_if.read   = neo_read_codec;
    606      1.1   thorpej 	sc->host_if.write  = neo_write_codec;
    607      1.1   thorpej 	sc->host_if.reset  = neo_reset_codec;
    608      1.1   thorpej 	sc->host_if.flags  = neo_flags_codec;
    609      1.1   thorpej 
    610      1.1   thorpej 	if ((error = ac97_attach(&sc->host_if)) != 0)
    611      1.1   thorpej 		return;
    612      1.5  sommerfe 
    613      1.5  sommerfe 	sc->powerhook = powerhook_establish(neo_power, sc);
    614      1.1   thorpej 
    615      1.1   thorpej 	audio_attach_mi(&neo_hw_if, sc, &sc->dev);
    616      1.1   thorpej }
    617      1.1   thorpej 
    618      1.1   thorpej int
    619      1.1   thorpej neo_read_codec(void *v, u_int8_t a, u_int16_t *d)
    620      1.1   thorpej {
    621      1.1   thorpej 	struct neo_softc *sc = v;
    622      1.1   thorpej 
    623      1.1   thorpej 	if (!nm_waitcd(sc)) {
    624      1.1   thorpej 		*d = nm_rd_2(sc, sc->ac97_base + a);
    625      1.1   thorpej 		DELAY(1000);
    626      1.1   thorpej 		return 0;
    627      1.1   thorpej 	}
    628      1.1   thorpej 
    629      1.1   thorpej 	return (ENXIO);
    630      1.1   thorpej }
    631      1.1   thorpej 
    632      1.1   thorpej 
    633      1.1   thorpej int
    634      1.1   thorpej neo_write_codec(void *v, u_int8_t a, u_int16_t d)
    635      1.1   thorpej {
    636      1.1   thorpej 	struct neo_softc *sc = v;
    637      1.1   thorpej 	int cnt = 3;
    638      1.1   thorpej 
    639      1.1   thorpej 	if (!nm_waitcd(sc)) {
    640      1.1   thorpej 		while (cnt-- > 0) {
    641      1.1   thorpej 			nm_wr_2(sc, sc->ac97_base + a, d);
    642      1.1   thorpej 			if (!nm_waitcd(sc)) {
    643      1.1   thorpej 				DELAY(1000);
    644      1.1   thorpej 				return (0);
    645      1.1   thorpej 			}
    646      1.1   thorpej 		}
    647      1.1   thorpej 	}
    648      1.1   thorpej 
    649      1.1   thorpej         return (ENXIO);
    650      1.1   thorpej }
    651      1.1   thorpej 
    652      1.1   thorpej int
    653      1.1   thorpej neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
    654      1.1   thorpej {
    655      1.1   thorpej 	struct neo_softc *sc = v;
    656      1.1   thorpej 
    657      1.1   thorpej 	sc->codec_if = codec_if;
    658      1.1   thorpej 	return (0);
    659      1.1   thorpej }
    660      1.1   thorpej 
    661      1.1   thorpej void
    662      1.1   thorpej neo_reset_codec(void *v)
    663      1.1   thorpej {
    664      1.1   thorpej 	struct neo_softc *sc = v;
    665      1.1   thorpej 
    666      1.1   thorpej 	nm_wr_1(sc, 0x6c0, 0x01);
    667      1.1   thorpej 	nm_wr_1(sc, 0x6cc, 0x87);
    668      1.1   thorpej 	nm_wr_1(sc, 0x6cc, 0x80);
    669      1.1   thorpej 	nm_wr_1(sc, 0x6cc, 0x00);
    670      1.1   thorpej }
    671      1.1   thorpej 
    672      1.1   thorpej enum ac97_host_flags
    673      1.1   thorpej neo_flags_codec(void *v)
    674      1.1   thorpej {
    675      1.1   thorpej 
    676      1.1   thorpej 	return (AC97_HOST_DONT_READ);
    677      1.1   thorpej }
    678      1.1   thorpej 
    679      1.1   thorpej int
    680      1.1   thorpej neo_open(void *addr, int flags)
    681      1.1   thorpej {
    682      1.1   thorpej 
    683      1.1   thorpej 	return (0);
    684      1.1   thorpej }
    685      1.1   thorpej 
    686      1.1   thorpej /*
    687      1.1   thorpej  * Close function is called at splaudio().
    688      1.1   thorpej  */
    689      1.1   thorpej void
    690      1.1   thorpej neo_close(void *addr)
    691      1.1   thorpej {
    692      1.1   thorpej 	struct neo_softc *sc = addr;
    693      1.1   thorpej 
    694      1.1   thorpej 	neo_halt_output(sc);
    695      1.1   thorpej 	neo_halt_input(sc);
    696      1.1   thorpej 
    697      1.1   thorpej 	sc->pintr = 0;
    698      1.1   thorpej 	sc->rintr = 0;
    699      1.1   thorpej }
    700      1.1   thorpej 
    701      1.1   thorpej int
    702      1.1   thorpej neo_query_encoding(void *addr, struct audio_encoding *fp)
    703      1.1   thorpej {
    704      1.1   thorpej 
    705      1.1   thorpej 	switch (fp->index) {
    706      1.1   thorpej 	case 0:
    707      1.1   thorpej 		strcpy(fp->name, AudioEulinear);
    708      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_ULINEAR;
    709      1.1   thorpej 		fp->precision = 8;
    710      1.1   thorpej 		fp->flags = 0;
    711      1.1   thorpej 		return (0);
    712      1.1   thorpej 	case 1:
    713      1.1   thorpej 		strcpy(fp->name, AudioEmulaw);
    714      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_ULAW;
    715      1.1   thorpej 		fp->precision = 8;
    716      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    717      1.1   thorpej 		return (0);
    718      1.1   thorpej 	case 2:
    719      1.1   thorpej 		strcpy(fp->name, AudioEalaw);
    720      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_ALAW;
    721      1.1   thorpej 		fp->precision = 8;
    722      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    723      1.1   thorpej 		return (0);
    724      1.1   thorpej 	case 3:
    725      1.1   thorpej 		strcpy(fp->name, AudioEslinear);
    726      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_SLINEAR;
    727      1.1   thorpej 		fp->precision = 8;
    728      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    729      1.1   thorpej 		return (0);
    730      1.1   thorpej 	case 4:
    731      1.1   thorpej 		strcpy(fp->name, AudioEslinear_le);
    732      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
    733      1.1   thorpej 		fp->precision = 16;
    734      1.1   thorpej 		fp->flags = 0;
    735      1.1   thorpej 		return (0);
    736      1.1   thorpej 	case 5:
    737      1.1   thorpej 		strcpy(fp->name, AudioEulinear_le);
    738      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
    739      1.1   thorpej 		fp->precision = 16;
    740      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    741      1.1   thorpej 		return (0);
    742      1.1   thorpej 	case 6:
    743      1.1   thorpej 		strcpy(fp->name, AudioEslinear_be);
    744      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
    745      1.1   thorpej 		fp->precision = 16;
    746      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    747      1.1   thorpej 		return (0);
    748      1.1   thorpej 	case 7:
    749      1.1   thorpej 		strcpy(fp->name, AudioEulinear_be);
    750      1.1   thorpej 		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
    751      1.1   thorpej 		fp->precision = 16;
    752      1.1   thorpej 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    753      1.1   thorpej 		return (0);
    754      1.1   thorpej 	default:
    755      1.1   thorpej 		return (EINVAL);
    756      1.1   thorpej 	}
    757      1.1   thorpej }
    758      1.1   thorpej 
    759      1.1   thorpej /* Todo: don't commit settings to card until we've verified all parameters */
    760      1.1   thorpej int
    761      1.1   thorpej neo_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
    762      1.1   thorpej     struct audio_params *rec)
    763      1.1   thorpej {
    764      1.1   thorpej 	struct neo_softc *sc = addr;
    765      1.1   thorpej 	u_int32_t base;
    766      1.1   thorpej 	u_int8_t x;
    767      1.1   thorpej 	int mode;
    768      1.1   thorpej 	struct audio_params *p;
    769      1.1   thorpej 
    770      1.1   thorpej 	for (mode = AUMODE_RECORD; mode != -1;
    771      1.1   thorpej 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
    772      1.1   thorpej 		if ((setmode & mode) == 0)
    773      1.1   thorpej 			continue;
    774      1.1   thorpej 
    775      1.1   thorpej 		p = mode == AUMODE_PLAY ? play : rec;
    776      1.1   thorpej 
    777      1.1   thorpej 		if (p == NULL) continue;
    778      1.1   thorpej 
    779      1.1   thorpej 		for (x = 0; x < 8; x++) {
    780      1.1   thorpej 			if (p->sample_rate <
    781      1.1   thorpej 			    (samplerates[x] + samplerates[x + 1]) / 2)
    782      1.1   thorpej 				break;
    783      1.1   thorpej 		}
    784      1.1   thorpej 		if (x == 8)
    785      1.1   thorpej 			return (EINVAL);
    786      1.1   thorpej 
    787      1.1   thorpej 		p->sample_rate = samplerates[x];
    788      1.1   thorpej 		nm_loadcoeff(sc, mode, x);
    789      1.1   thorpej 
    790      1.1   thorpej 		x <<= 4;
    791      1.1   thorpej 		x &= NM_RATE_MASK;
    792      1.1   thorpej 		if (p->precision == 16)
    793      1.1   thorpej 			x |= NM_RATE_BITS_16;
    794      1.1   thorpej 		if (p->channels == 2)
    795      1.1   thorpej 			x |= NM_RATE_STEREO;
    796      1.1   thorpej 
    797      1.1   thorpej 		base = (mode == AUMODE_PLAY)?
    798      1.1   thorpej 		    NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
    799      1.1   thorpej 		nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
    800      1.1   thorpej 
    801      1.1   thorpej 		p->factor = 1;
    802      1.1   thorpej 		p->sw_code = 0;
    803      1.1   thorpej 		switch (p->encoding) {
    804      1.1   thorpej 		case AUDIO_ENCODING_SLINEAR_BE:
    805      1.1   thorpej 			if (p->precision == 16)
    806      1.1   thorpej 				p->sw_code = swap_bytes;
    807      1.1   thorpej 			else
    808      1.1   thorpej 				p->sw_code = change_sign8;
    809      1.1   thorpej 			break;
    810      1.1   thorpej 		case AUDIO_ENCODING_SLINEAR_LE:
    811      1.1   thorpej 			if (p->precision != 16)
    812      1.1   thorpej 				p->sw_code = change_sign8;
    813      1.1   thorpej 			break;
    814      1.1   thorpej 		case AUDIO_ENCODING_ULINEAR_BE:
    815      1.1   thorpej 			if (p->precision == 16) {
    816      1.1   thorpej 				if (mode == AUMODE_PLAY)
    817      1.1   thorpej 					p->sw_code =
    818      1.1   thorpej 					    swap_bytes_change_sign16_le;
    819      1.1   thorpej 				else
    820      1.1   thorpej 					p->sw_code =
    821      1.1   thorpej 					    change_sign16_swap_bytes_le;
    822      1.1   thorpej 			}
    823      1.1   thorpej 			break;
    824      1.1   thorpej 		case AUDIO_ENCODING_ULINEAR_LE:
    825      1.1   thorpej 			if (p->precision == 16)
    826      1.1   thorpej 				p->sw_code = change_sign16_le;
    827      1.1   thorpej 			break;
    828      1.1   thorpej 		case AUDIO_ENCODING_ULAW:
    829      1.1   thorpej 			if (mode == AUMODE_PLAY) {
    830      1.1   thorpej 				p->factor = 2;
    831      1.1   thorpej 				p->sw_code = mulaw_to_slinear16_le;
    832      1.1   thorpej 			} else
    833      1.1   thorpej 				p->sw_code = ulinear8_to_mulaw;
    834      1.1   thorpej 			break;
    835      1.1   thorpej 		case AUDIO_ENCODING_ALAW:
    836      1.1   thorpej 			if (mode == AUMODE_PLAY) {
    837      1.1   thorpej 				p->factor = 2;
    838      1.1   thorpej 				p->sw_code = alaw_to_slinear16_le;
    839      1.1   thorpej 			} else
    840      1.1   thorpej 				p->sw_code = ulinear8_to_alaw;
    841      1.1   thorpej 			break;
    842      1.1   thorpej 		default:
    843      1.1   thorpej 			return (EINVAL);
    844      1.1   thorpej 		}
    845      1.1   thorpej 	}
    846      1.1   thorpej 
    847      1.1   thorpej 
    848      1.1   thorpej 	return (0);
    849      1.1   thorpej }
    850      1.1   thorpej 
    851      1.1   thorpej int
    852      1.1   thorpej neo_round_blocksize(void *addr, int blk)
    853      1.1   thorpej {
    854      1.1   thorpej 
    855      1.1   thorpej 	return (NM_BUFFSIZE / 2);
    856      1.1   thorpej }
    857      1.1   thorpej 
    858      1.1   thorpej int
    859      1.1   thorpej neo_trigger_output(void *addr, void *start, void *end, int blksize,
    860      1.1   thorpej     void (*intr)(void *), void *arg, struct audio_params *param)
    861      1.1   thorpej {
    862      1.1   thorpej 	struct neo_softc *sc = addr;
    863      1.1   thorpej 	int ssz;
    864      1.1   thorpej 
    865      1.1   thorpej 	sc->pintr = intr;
    866      1.1   thorpej 	sc->parg = arg;
    867      1.1   thorpej 
    868      1.1   thorpej 	ssz = (param->precision * param->factor == 16) ? 2 : 1;
    869      1.1   thorpej 	if (param->channels == 2)
    870      1.1   thorpej 		ssz <<= 1;
    871      1.1   thorpej 
    872      1.1   thorpej 	sc->pbufsize = ((char*)end - (char *)start);
    873      1.1   thorpej 	sc->pblksize = blksize;
    874      1.1   thorpej 	sc->pwmark = blksize;
    875      1.1   thorpej 
    876      1.1   thorpej 	nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
    877      1.1   thorpej 	nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
    878      1.1   thorpej 	nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
    879      1.1   thorpej 	nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
    880      1.1   thorpej 	nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
    881      1.1   thorpej 	    NM_PLAYBACK_ENABLE_FLAG);
    882      1.1   thorpej 	nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
    883      1.1   thorpej 
    884      1.1   thorpej 	return (0);
    885      1.1   thorpej }
    886      1.1   thorpej 
    887      1.1   thorpej int
    888      1.1   thorpej neo_trigger_input(void *addr, void *start, void *end, int blksize,
    889      1.1   thorpej     void (*intr)(void *), void *arg, struct audio_params *param)
    890      1.1   thorpej {
    891      1.1   thorpej 	struct neo_softc *sc = addr;
    892      1.1   thorpej 	int ssz;
    893      1.1   thorpej 
    894      1.1   thorpej 	sc->rintr = intr;
    895      1.1   thorpej 	sc->rarg = arg;
    896      1.1   thorpej 
    897      1.1   thorpej 	ssz = (param->precision * param->factor == 16) ? 2 : 1;
    898      1.1   thorpej 	if (param->channels == 2)
    899      1.1   thorpej 		ssz <<= 1;
    900      1.1   thorpej 
    901      1.1   thorpej 	sc->rbufsize = ((char*)end - (char *)start);
    902      1.1   thorpej 	sc->rblksize = blksize;
    903      1.1   thorpej 	sc->rwmark = blksize;
    904      1.1   thorpej 
    905      1.1   thorpej 	nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
    906      1.1   thorpej 	nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
    907      1.1   thorpej 	nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
    908      1.1   thorpej 	nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
    909      1.1   thorpej 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
    910      1.1   thorpej 	    NM_RECORD_ENABLE_FLAG);
    911      1.1   thorpej 
    912      1.1   thorpej 	return (0);
    913      1.1   thorpej }
    914      1.1   thorpej 
    915      1.1   thorpej int
    916      1.1   thorpej neo_halt_output(void *addr)
    917      1.1   thorpej {
    918      1.1   thorpej 	struct neo_softc *sc = (struct neo_softc *)addr;
    919      1.1   thorpej 
    920      1.1   thorpej 	nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
    921      1.1   thorpej 	nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
    922      1.1   thorpej 
    923      1.1   thorpej 	return (0);
    924      1.1   thorpej }
    925      1.1   thorpej 
    926      1.1   thorpej int
    927      1.1   thorpej neo_halt_input(void *addr)
    928      1.1   thorpej {
    929      1.1   thorpej 	struct neo_softc *sc = (struct neo_softc *)addr;
    930      1.1   thorpej 
    931      1.1   thorpej 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
    932      1.1   thorpej 
    933      1.1   thorpej 	return (0);
    934      1.1   thorpej }
    935      1.1   thorpej 
    936      1.1   thorpej int
    937      1.1   thorpej neo_getdev(void *addr, struct audio_device *retp)
    938      1.1   thorpej {
    939      1.1   thorpej 
    940      1.1   thorpej 	*retp = neo_device;
    941      1.1   thorpej 	return (0);
    942      1.1   thorpej }
    943      1.1   thorpej 
    944      1.1   thorpej int
    945      1.1   thorpej neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
    946      1.1   thorpej {
    947      1.1   thorpej 	struct neo_softc *sc = addr;
    948      1.1   thorpej 
    949      1.1   thorpej 	return ((sc->codec_if->vtbl->mixer_set_port)(sc->codec_if, cp));
    950      1.1   thorpej }
    951      1.1   thorpej 
    952      1.1   thorpej int
    953      1.1   thorpej neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
    954      1.1   thorpej {
    955      1.1   thorpej 	struct neo_softc *sc = addr;
    956      1.1   thorpej 
    957      1.1   thorpej 	return ((sc->codec_if->vtbl->mixer_get_port)(sc->codec_if, cp));
    958      1.1   thorpej }
    959      1.1   thorpej 
    960      1.1   thorpej int
    961      1.1   thorpej neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
    962      1.1   thorpej {
    963      1.1   thorpej 	struct neo_softc *sc = addr;
    964      1.1   thorpej 
    965      1.1   thorpej 	return ((sc->codec_if->vtbl->query_devinfo)(sc->codec_if, dip));
    966      1.1   thorpej }
    967      1.1   thorpej 
    968      1.1   thorpej void *
    969      1.1   thorpej neo_malloc(void *addr, int direction, size_t size, int pool, int flags)
    970      1.1   thorpej {
    971      1.1   thorpej 	struct neo_softc *sc = addr;
    972      1.1   thorpej 	void *rv = NULL;
    973      1.1   thorpej 
    974      1.1   thorpej 	switch (direction) {
    975      1.1   thorpej 	case AUMODE_PLAY:
    976      1.1   thorpej 		if (sc->pbuf_allocated == 0) {
    977      1.1   thorpej 			rv = (void *) sc->pbuf_vaddr;
    978      1.1   thorpej 			sc->pbuf_allocated = 1;
    979      1.1   thorpej 		}
    980      1.1   thorpej 		break;
    981      1.1   thorpej 
    982      1.1   thorpej 	case AUMODE_RECORD:
    983      1.1   thorpej 		if (sc->rbuf_allocated == 0) {
    984      1.1   thorpej 			rv = (void *) sc->rbuf_vaddr;
    985      1.1   thorpej 			sc->rbuf_allocated = 1;
    986      1.1   thorpej 		}
    987      1.1   thorpej 		break;
    988      1.1   thorpej 	}
    989      1.1   thorpej 
    990      1.1   thorpej 	return (rv);
    991      1.1   thorpej }
    992      1.1   thorpej 
    993      1.1   thorpej void
    994      1.1   thorpej neo_free(void *addr, void *ptr, int pool)
    995      1.1   thorpej {
    996      1.1   thorpej 	struct neo_softc *sc = addr;
    997      1.1   thorpej 	vaddr_t v = (vaddr_t) ptr;
    998      1.1   thorpej 
    999      1.1   thorpej 	if (v == sc->pbuf_vaddr)
   1000      1.1   thorpej 		sc->pbuf_allocated = 0;
   1001      1.1   thorpej 	else if (v == sc->rbuf_vaddr)
   1002      1.1   thorpej 		sc->rbuf_allocated = 0;
   1003      1.1   thorpej 	else
   1004      1.1   thorpej 		printf("neo_free: bad address %p\n", ptr);
   1005      1.1   thorpej }
   1006      1.1   thorpej 
   1007      1.1   thorpej size_t
   1008      1.1   thorpej neo_round_buffersize(void *addr, int direction, size_t size)
   1009      1.1   thorpej {
   1010      1.1   thorpej 
   1011      1.1   thorpej 	return (NM_BUFFSIZE);
   1012      1.1   thorpej }
   1013      1.1   thorpej 
   1014      1.3   thorpej paddr_t
   1015      1.3   thorpej neo_mappage(void *addr, void *mem, off_t off, int prot)
   1016      1.3   thorpej {
   1017      1.3   thorpej 	struct neo_softc *sc = addr;
   1018      1.3   thorpej 	vaddr_t v = (vaddr_t) mem;
   1019      1.3   thorpej 	bus_addr_t pciaddr;
   1020      1.3   thorpej 
   1021      1.3   thorpej 	if (v == sc->pbuf_vaddr)
   1022      1.3   thorpej 		pciaddr = sc->pbuf_pciaddr;
   1023      1.3   thorpej 	else if (v == sc->rbuf_vaddr)
   1024      1.3   thorpej 		pciaddr = sc->rbuf_pciaddr;
   1025      1.3   thorpej 	else
   1026      1.3   thorpej 		return (-1);
   1027      1.3   thorpej 
   1028  1.8.4.1   thorpej 	return (bus_space_mmap(sc->bufiot, pciaddr, off, prot,
   1029  1.8.4.1   thorpej 	    BUS_SPACE_MAP_LINEAR));
   1030      1.3   thorpej }
   1031      1.1   thorpej 
   1032      1.1   thorpej int
   1033      1.1   thorpej neo_get_props(void *addr)
   1034      1.1   thorpej {
   1035      1.1   thorpej 
   1036      1.3   thorpej 	return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
   1037      1.1   thorpej                 AUDIO_PROP_FULLDUPLEX);
   1038      1.1   thorpej }
   1039