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