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