Home | History | Annotate | Line # | Download | only in pci
neo.c revision 1.4.2.2
      1  1.4.2.2  bouyer /*	$NetBSD: neo.c,v 1.4.2.2 2000/11/22 16:04:11 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  *    Power management (neoactivate)
    113  1.4.2.2  bouyer  *
    114  1.4.2.2  bouyer  *    Figure out how to shrink that huge table neo-coeff.h
    115  1.4.2.2  bouyer  */
    116  1.4.2.2  bouyer 
    117  1.4.2.2  bouyer #define	NM_BUFFSIZE	16384
    118  1.4.2.2  bouyer 
    119  1.4.2.2  bouyer /* device private data */
    120  1.4.2.2  bouyer struct neo_softc {
    121  1.4.2.2  bouyer 	struct          device dev;
    122  1.4.2.2  bouyer 
    123  1.4.2.2  bouyer 	bus_space_tag_t bufiot;
    124  1.4.2.2  bouyer 	bus_space_handle_t  bufioh;
    125  1.4.2.2  bouyer 
    126  1.4.2.2  bouyer 	bus_space_tag_t regiot;
    127  1.4.2.2  bouyer 	bus_space_handle_t  regioh;
    128  1.4.2.2  bouyer 
    129  1.4.2.2  bouyer 	u_int32_t 	type;
    130  1.4.2.2  bouyer 	void            *ih;
    131  1.4.2.2  bouyer 
    132  1.4.2.2  bouyer 	void	(*pintr)(void *);	/* dma completion intr handler */
    133  1.4.2.2  bouyer 	void	*parg;		/* arg for intr() */
    134  1.4.2.2  bouyer 
    135  1.4.2.2  bouyer 	void	(*rintr)(void *);	/* dma completion intr handler */
    136  1.4.2.2  bouyer 	void	*rarg;		/* arg for intr() */
    137  1.4.2.2  bouyer 
    138  1.4.2.2  bouyer 	vaddr_t	buf_vaddr;
    139  1.4.2.2  bouyer 	vaddr_t	rbuf_vaddr;
    140  1.4.2.2  bouyer 	vaddr_t	pbuf_vaddr;
    141  1.4.2.2  bouyer 	int	pbuf_allocated;
    142  1.4.2.2  bouyer 	int	rbuf_allocated;
    143  1.4.2.2  bouyer 
    144  1.4.2.2  bouyer 	bus_addr_t buf_pciaddr;
    145  1.4.2.2  bouyer 	bus_addr_t rbuf_pciaddr;
    146  1.4.2.2  bouyer 	bus_addr_t pbuf_pciaddr;
    147  1.4.2.2  bouyer 
    148  1.4.2.2  bouyer 	u_int32_t 	ac97_base, ac97_status, ac97_busy;
    149  1.4.2.2  bouyer 	u_int32_t	buftop, pbuf, rbuf, cbuf, acbuf;
    150  1.4.2.2  bouyer 	u_int32_t	playint, recint, misc1int, misc2int;
    151  1.4.2.2  bouyer 	u_int32_t	irsz, badintr;
    152  1.4.2.2  bouyer 
    153  1.4.2.2  bouyer         u_int32_t       pbufsize;
    154  1.4.2.2  bouyer         u_int32_t       rbufsize;
    155  1.4.2.2  bouyer 
    156  1.4.2.2  bouyer 	u_int32_t       pblksize;
    157  1.4.2.2  bouyer 	u_int32_t       rblksize;
    158  1.4.2.2  bouyer 
    159  1.4.2.2  bouyer         u_int32_t       pwmark;
    160  1.4.2.2  bouyer         u_int32_t       rwmark;
    161  1.4.2.2  bouyer 
    162  1.4.2.2  bouyer 	struct ac97_codec_if *codec_if;
    163  1.4.2.2  bouyer 	struct ac97_host_if host_if;
    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.2  bouyer 
    208  1.4.2.2  bouyer struct cfattach neo_ca = {
    209  1.4.2.2  bouyer 	sizeof(struct neo_softc), neo_match, neo_attach
    210  1.4.2.2  bouyer };
    211  1.4.2.2  bouyer 
    212  1.4.2.2  bouyer struct audio_device neo_device = {
    213  1.4.2.2  bouyer 	"NeoMagic 256",
    214  1.4.2.2  bouyer 	"",
    215  1.4.2.2  bouyer 	"neo"
    216  1.4.2.2  bouyer };
    217  1.4.2.2  bouyer 
    218  1.4.2.2  bouyer /* The actual rates supported by the card. */
    219  1.4.2.2  bouyer static const int samplerates[9] = {
    220  1.4.2.2  bouyer 	8000,
    221  1.4.2.2  bouyer 	11025,
    222  1.4.2.2  bouyer 	16000,
    223  1.4.2.2  bouyer 	22050,
    224  1.4.2.2  bouyer 	24000,
    225  1.4.2.2  bouyer 	32000,
    226  1.4.2.2  bouyer 	44100,
    227  1.4.2.2  bouyer 	48000,
    228  1.4.2.2  bouyer 	99999999
    229  1.4.2.2  bouyer };
    230  1.4.2.2  bouyer 
    231  1.4.2.2  bouyer /* -------------------------------------------------------------------- */
    232  1.4.2.2  bouyer 
    233  1.4.2.2  bouyer struct audio_hw_if neo_hw_if = {
    234  1.4.2.2  bouyer 	neo_open,
    235  1.4.2.2  bouyer 	neo_close,
    236  1.4.2.2  bouyer 	NULL,				/* drain */
    237  1.4.2.2  bouyer 	neo_query_encoding,
    238  1.4.2.2  bouyer 	neo_set_params,
    239  1.4.2.2  bouyer 	neo_round_blocksize,
    240  1.4.2.2  bouyer 	NULL,				/* commit_setting */
    241  1.4.2.2  bouyer 	NULL,				/* init_output */
    242  1.4.2.2  bouyer 	NULL,				/* init_input */
    243  1.4.2.2  bouyer 	NULL,				/* start_output */
    244  1.4.2.2  bouyer 	NULL,				/* start_input */
    245  1.4.2.2  bouyer 	neo_halt_output,
    246  1.4.2.2  bouyer 	neo_halt_input,
    247  1.4.2.2  bouyer 	NULL,				/* speaker_ctl */
    248  1.4.2.2  bouyer 	neo_getdev,
    249  1.4.2.2  bouyer 	NULL,				/* getfd */
    250  1.4.2.2  bouyer 	neo_mixer_set_port,
    251  1.4.2.2  bouyer 	neo_mixer_get_port,
    252  1.4.2.2  bouyer 	neo_query_devinfo,
    253  1.4.2.2  bouyer 	neo_malloc,
    254  1.4.2.2  bouyer 	neo_free,
    255  1.4.2.2  bouyer 	neo_round_buffersize,
    256  1.4.2.2  bouyer 	neo_mappage,
    257  1.4.2.2  bouyer 	neo_get_props,
    258  1.4.2.2  bouyer 	neo_trigger_output,
    259  1.4.2.2  bouyer 	neo_trigger_input,
    260  1.4.2.2  bouyer };
    261  1.4.2.2  bouyer 
    262  1.4.2.2  bouyer /* -------------------------------------------------------------------- */
    263  1.4.2.2  bouyer 
    264  1.4.2.2  bouyer #define	nm_rd_1(sc, regno)						\
    265  1.4.2.2  bouyer 	bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
    266  1.4.2.2  bouyer 
    267  1.4.2.2  bouyer #define	nm_rd_2(sc, regno)						\
    268  1.4.2.2  bouyer 	bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
    269  1.4.2.2  bouyer 
    270  1.4.2.2  bouyer #define	nm_rd_4(sc, regno)						\
    271  1.4.2.2  bouyer 	bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
    272  1.4.2.2  bouyer 
    273  1.4.2.2  bouyer #define	nm_wr_1(sc, regno, val)						\
    274  1.4.2.2  bouyer 	bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
    275  1.4.2.2  bouyer 
    276  1.4.2.2  bouyer #define	nm_wr_2(sc, regno, val)						\
    277  1.4.2.2  bouyer 	bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
    278  1.4.2.2  bouyer 
    279  1.4.2.2  bouyer #define	nm_wr_4(sc, regno, val)						\
    280  1.4.2.2  bouyer 	bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
    281  1.4.2.2  bouyer 
    282  1.4.2.2  bouyer #define	nm_rdbuf_4(sc, regno)						\
    283  1.4.2.2  bouyer 	bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
    284  1.4.2.2  bouyer 
    285  1.4.2.2  bouyer #define	nm_wrbuf_1(sc, regno, val)					\
    286  1.4.2.2  bouyer 	bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
    287  1.4.2.2  bouyer 
    288  1.4.2.2  bouyer /* ac97 codec */
    289  1.4.2.2  bouyer static int
    290  1.4.2.2  bouyer nm_waitcd(struct neo_softc *sc)
    291  1.4.2.2  bouyer {
    292  1.4.2.2  bouyer 	int cnt = 10;
    293  1.4.2.2  bouyer 	int fail = 1;
    294  1.4.2.2  bouyer 
    295  1.4.2.2  bouyer 	while (cnt-- > 0) {
    296  1.4.2.2  bouyer 		if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
    297  1.4.2.2  bouyer 			DELAY(100);
    298  1.4.2.2  bouyer 		else {
    299  1.4.2.2  bouyer 		        fail = 0;
    300  1.4.2.2  bouyer 			break;
    301  1.4.2.2  bouyer 		}
    302  1.4.2.2  bouyer 	}
    303  1.4.2.2  bouyer 	return (fail);
    304  1.4.2.2  bouyer }
    305  1.4.2.2  bouyer 
    306  1.4.2.2  bouyer 
    307  1.4.2.2  bouyer static void
    308  1.4.2.2  bouyer nm_ackint(struct neo_softc *sc, u_int32_t num)
    309  1.4.2.2  bouyer {
    310  1.4.2.2  bouyer 
    311  1.4.2.2  bouyer 	switch (sc->type) {
    312  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    313  1.4.2.2  bouyer 		nm_wr_2(sc, NM_INT_REG, num << 1);
    314  1.4.2.2  bouyer 		break;
    315  1.4.2.2  bouyer 
    316  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    317  1.4.2.2  bouyer 		nm_wr_4(sc, NM_INT_REG, num);
    318  1.4.2.2  bouyer 		break;
    319  1.4.2.2  bouyer 	}
    320  1.4.2.2  bouyer }
    321  1.4.2.2  bouyer 
    322  1.4.2.2  bouyer static int
    323  1.4.2.2  bouyer nm_loadcoeff(struct neo_softc *sc, int dir, int num)
    324  1.4.2.2  bouyer {
    325  1.4.2.2  bouyer 	int ofs, sz, i;
    326  1.4.2.2  bouyer 	u_int32_t addr;
    327  1.4.2.2  bouyer 
    328  1.4.2.2  bouyer 	addr = (dir == AUMODE_PLAY)? 0x01c : 0x21c;
    329  1.4.2.2  bouyer 	if (dir == AUMODE_RECORD)
    330  1.4.2.2  bouyer 		num += 8;
    331  1.4.2.2  bouyer 	sz = coefficientSizes[num];
    332  1.4.2.2  bouyer 	ofs = 0;
    333  1.4.2.2  bouyer 	while (num-- > 0)
    334  1.4.2.2  bouyer 		ofs+= coefficientSizes[num];
    335  1.4.2.2  bouyer 	for (i = 0; i < sz; i++)
    336  1.4.2.2  bouyer 		nm_wrbuf_1(sc, sc->cbuf + i, coefficients[ofs + i]);
    337  1.4.2.2  bouyer 	nm_wr_4(sc, addr, sc->cbuf);
    338  1.4.2.2  bouyer 	if (dir == AUMODE_PLAY)
    339  1.4.2.2  bouyer 		sz--;
    340  1.4.2.2  bouyer 	nm_wr_4(sc, addr + 4, sc->cbuf + sz);
    341  1.4.2.2  bouyer 	return 0;
    342  1.4.2.2  bouyer }
    343  1.4.2.2  bouyer 
    344  1.4.2.2  bouyer /* The interrupt handler */
    345  1.4.2.2  bouyer int
    346  1.4.2.2  bouyer neo_intr(void *p)
    347  1.4.2.2  bouyer {
    348  1.4.2.2  bouyer 	struct neo_softc *sc = (struct neo_softc *)p;
    349  1.4.2.2  bouyer 	int status, x, active;
    350  1.4.2.2  bouyer 	int rv = 0;
    351  1.4.2.2  bouyer 
    352  1.4.2.2  bouyer 	active = (sc->pintr || sc->rintr);
    353  1.4.2.2  bouyer 	status = (sc->irsz == 2) ?
    354  1.4.2.2  bouyer 	    nm_rd_2(sc, NM_INT_REG) :
    355  1.4.2.2  bouyer 	    nm_rd_4(sc, NM_INT_REG);
    356  1.4.2.2  bouyer 
    357  1.4.2.2  bouyer 	if (status & sc->playint) {
    358  1.4.2.2  bouyer 		status &= ~sc->playint;
    359  1.4.2.2  bouyer 
    360  1.4.2.2  bouyer 		sc->pwmark += sc->pblksize;
    361  1.4.2.2  bouyer 		sc->pwmark %= sc->pbufsize;
    362  1.4.2.2  bouyer 
    363  1.4.2.2  bouyer 		nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
    364  1.4.2.2  bouyer 
    365  1.4.2.2  bouyer 		nm_ackint(sc, sc->playint);
    366  1.4.2.2  bouyer 
    367  1.4.2.2  bouyer 		if (sc->pintr)
    368  1.4.2.2  bouyer 			(*sc->pintr)(sc->parg);
    369  1.4.2.2  bouyer 
    370  1.4.2.2  bouyer 		rv = 1;
    371  1.4.2.2  bouyer 	}
    372  1.4.2.2  bouyer 	if (status & sc->recint) {
    373  1.4.2.2  bouyer 		status &= ~sc->recint;
    374  1.4.2.2  bouyer 
    375  1.4.2.2  bouyer 		sc->rwmark += sc->rblksize;
    376  1.4.2.2  bouyer 		sc->rwmark %= sc->rbufsize;
    377  1.4.2.2  bouyer 
    378  1.4.2.2  bouyer 		nm_ackint(sc, sc->recint);
    379  1.4.2.2  bouyer 		if (sc->rintr)
    380  1.4.2.2  bouyer 			(*sc->rintr)(sc->rarg);
    381  1.4.2.2  bouyer 
    382  1.4.2.2  bouyer 		rv = 1;
    383  1.4.2.2  bouyer 	}
    384  1.4.2.2  bouyer 	if (status & sc->misc1int) {
    385  1.4.2.2  bouyer 		status &= ~sc->misc1int;
    386  1.4.2.2  bouyer 		nm_ackint(sc, sc->misc1int);
    387  1.4.2.2  bouyer 		x = nm_rd_1(sc, 0x400);
    388  1.4.2.2  bouyer 		nm_wr_1(sc, 0x400, x | 2);
    389  1.4.2.2  bouyer 		printf("%s: misc int 1\n", sc->dev.dv_xname);
    390  1.4.2.2  bouyer 		rv = 1;
    391  1.4.2.2  bouyer 	}
    392  1.4.2.2  bouyer 	if (status & sc->misc2int) {
    393  1.4.2.2  bouyer 		status &= ~sc->misc2int;
    394  1.4.2.2  bouyer 		nm_ackint(sc, sc->misc2int);
    395  1.4.2.2  bouyer 		x = nm_rd_1(sc, 0x400);
    396  1.4.2.2  bouyer 		nm_wr_1(sc, 0x400, x & ~2);
    397  1.4.2.2  bouyer 		printf("%s: misc int 2\n", sc->dev.dv_xname);
    398  1.4.2.2  bouyer 		rv = 1;
    399  1.4.2.2  bouyer 	}
    400  1.4.2.2  bouyer 	if (status) {
    401  1.4.2.2  bouyer 		status &= ~sc->misc2int;
    402  1.4.2.2  bouyer 		nm_ackint(sc, sc->misc2int);
    403  1.4.2.2  bouyer 		printf("%s: unknown int\n", sc->dev.dv_xname);
    404  1.4.2.2  bouyer 		rv = 1;
    405  1.4.2.2  bouyer 	}
    406  1.4.2.2  bouyer 
    407  1.4.2.2  bouyer 	return (rv);
    408  1.4.2.2  bouyer }
    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  * Probe and attach the card
    414  1.4.2.2  bouyer  */
    415  1.4.2.2  bouyer 
    416  1.4.2.2  bouyer static int
    417  1.4.2.2  bouyer nm_init(struct neo_softc *sc)
    418  1.4.2.2  bouyer {
    419  1.4.2.2  bouyer 	u_int32_t ofs, i;
    420  1.4.2.2  bouyer 
    421  1.4.2.2  bouyer 	switch (sc->type) {
    422  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    423  1.4.2.2  bouyer 		sc->ac97_base = NM_MIXER_OFFSET;
    424  1.4.2.2  bouyer 		sc->ac97_status = NM_MIXER_STATUS_OFFSET;
    425  1.4.2.2  bouyer 		sc->ac97_busy = NM_MIXER_READY_MASK;
    426  1.4.2.2  bouyer 
    427  1.4.2.2  bouyer 		sc->buftop = 2560 * 1024;
    428  1.4.2.2  bouyer 
    429  1.4.2.2  bouyer 		sc->irsz = 2;
    430  1.4.2.2  bouyer 		sc->playint = NM_PLAYBACK_INT;
    431  1.4.2.2  bouyer 		sc->recint = NM_RECORD_INT;
    432  1.4.2.2  bouyer 		sc->misc1int = NM_MISC_INT_1;
    433  1.4.2.2  bouyer 		sc->misc2int = NM_MISC_INT_2;
    434  1.4.2.2  bouyer 		break;
    435  1.4.2.2  bouyer 
    436  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    437  1.4.2.2  bouyer 		sc->ac97_base = NM_MIXER_OFFSET;
    438  1.4.2.2  bouyer 		sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
    439  1.4.2.2  bouyer 		sc->ac97_busy = NM2_MIXER_READY_MASK;
    440  1.4.2.2  bouyer 
    441  1.4.2.2  bouyer 		sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
    442  1.4.2.2  bouyer 
    443  1.4.2.2  bouyer 		sc->irsz = 4;
    444  1.4.2.2  bouyer 		sc->playint = NM2_PLAYBACK_INT;
    445  1.4.2.2  bouyer 		sc->recint = NM2_RECORD_INT;
    446  1.4.2.2  bouyer 		sc->misc1int = NM2_MISC_INT_1;
    447  1.4.2.2  bouyer 		sc->misc2int = NM2_MISC_INT_2;
    448  1.4.2.2  bouyer 		break;
    449  1.4.2.2  bouyer #ifdef DIAGNOSTIC
    450  1.4.2.2  bouyer 	default:
    451  1.4.2.2  bouyer 		panic("nm_init: impossible");
    452  1.4.2.2  bouyer #endif
    453  1.4.2.2  bouyer 	}
    454  1.4.2.2  bouyer 
    455  1.4.2.2  bouyer 	sc->badintr = 0;
    456  1.4.2.2  bouyer 	ofs = sc->buftop - 0x0400;
    457  1.4.2.2  bouyer 	sc->buftop -= 0x1400;
    458  1.4.2.2  bouyer 
    459  1.4.2.2  bouyer  	if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
    460  1.4.2.2  bouyer 		i = nm_rdbuf_4(sc, ofs + 4);
    461  1.4.2.2  bouyer 		if (i != 0 && i != 0xffffffff)
    462  1.4.2.2  bouyer 			sc->buftop = i;
    463  1.4.2.2  bouyer 	}
    464  1.4.2.2  bouyer 
    465  1.4.2.2  bouyer 	sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
    466  1.4.2.2  bouyer 	sc->rbuf = sc->cbuf - NM_BUFFSIZE;
    467  1.4.2.2  bouyer 	sc->pbuf = sc->rbuf - NM_BUFFSIZE;
    468  1.4.2.2  bouyer 	sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
    469  1.4.2.2  bouyer 
    470  1.4.2.2  bouyer 	sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
    471  1.4.2.2  bouyer 	sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
    472  1.4.2.2  bouyer 	sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
    473  1.4.2.2  bouyer 
    474  1.4.2.2  bouyer 	sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
    475  1.4.2.2  bouyer 	sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
    476  1.4.2.2  bouyer 
    477  1.4.2.2  bouyer 	nm_wr_1(sc, 0, 0x11);
    478  1.4.2.2  bouyer 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
    479  1.4.2.2  bouyer 	nm_wr_2(sc, 0x214, 0);
    480  1.4.2.2  bouyer 
    481  1.4.2.2  bouyer 	return 0;
    482  1.4.2.2  bouyer }
    483  1.4.2.2  bouyer 
    484  1.4.2.2  bouyer int
    485  1.4.2.2  bouyer neo_match(struct device *parent, struct cfdata *match, void *aux)
    486  1.4.2.2  bouyer {
    487  1.4.2.2  bouyer 	struct pci_attach_args *pa = aux;
    488  1.4.2.2  bouyer 	pcireg_t subdev;
    489  1.4.2.2  bouyer 
    490  1.4.2.2  bouyer 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
    491  1.4.2.2  bouyer 		return (0);
    492  1.4.2.2  bouyer 
    493  1.4.2.2  bouyer 	subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
    494  1.4.2.2  bouyer 
    495  1.4.2.2  bouyer 	switch (PCI_PRODUCT(pa->pa_id)) {
    496  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
    497  1.4.2.2  bouyer 		/*
    498  1.4.2.2  bouyer 		 * We have to weed-out the non-AC'97 versions of
    499  1.4.2.2  bouyer 		 * the chip (i.e. the ones that are known to work
    500  1.4.2.2  bouyer 		 * in WSS emulation mode), as they won't work with
    501  1.4.2.2  bouyer 		 * this driver.
    502  1.4.2.2  bouyer 		 */
    503  1.4.2.2  bouyer 		switch (PCI_VENDOR(subdev)) {
    504  1.4.2.2  bouyer 		case PCI_VENDOR_DELL:
    505  1.4.2.2  bouyer 			switch (PCI_PRODUCT(subdev)) {
    506  1.4.2.2  bouyer 			case 0x008f:
    507  1.4.2.2  bouyer 				return (0);
    508  1.4.2.2  bouyer 			}
    509  1.4.2.2  bouyer 			break;
    510  1.4.2.2  bouyer 
    511  1.4.2.2  bouyer 		case PCI_VENDOR_HP:
    512  1.4.2.2  bouyer 			switch (PCI_PRODUCT(subdev)) {
    513  1.4.2.2  bouyer 			case 0x0007:
    514  1.4.2.2  bouyer 				return (0);
    515  1.4.2.2  bouyer 			}
    516  1.4.2.2  bouyer 		}
    517  1.4.2.2  bouyer 		return (1);
    518  1.4.2.2  bouyer 
    519  1.4.2.2  bouyer 	case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
    520  1.4.2.2  bouyer 		return (1);
    521  1.4.2.2  bouyer 	}
    522  1.4.2.2  bouyer 
    523  1.4.2.2  bouyer 	return (0);
    524  1.4.2.2  bouyer }
    525  1.4.2.2  bouyer 
    526  1.4.2.2  bouyer void
    527  1.4.2.2  bouyer neo_attach(struct device *parent, struct device *self, void *aux)
    528  1.4.2.2  bouyer {
    529  1.4.2.2  bouyer 	struct neo_softc *sc = (struct neo_softc *)self;
    530  1.4.2.2  bouyer 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
    531  1.4.2.2  bouyer 	pci_chipset_tag_t pc = pa->pa_pc;
    532  1.4.2.2  bouyer 	char const *intrstr;
    533  1.4.2.2  bouyer 	pci_intr_handle_t ih;
    534  1.4.2.2  bouyer 	pcireg_t csr;
    535  1.4.2.2  bouyer 	int error;
    536  1.4.2.2  bouyer 
    537  1.4.2.2  bouyer 	sc->type = PCI_PRODUCT(pa->pa_id);
    538  1.4.2.2  bouyer 
    539  1.4.2.2  bouyer 	printf(": NeoMagic 256%s audio\n",
    540  1.4.2.2  bouyer 	    sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
    541  1.4.2.2  bouyer 
    542  1.4.2.2  bouyer 	/* Map I/O register */
    543  1.4.2.2  bouyer 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
    544  1.4.2.2  bouyer 			   &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
    545  1.4.2.2  bouyer 		printf("%s: can't map buffer\n", sc->dev.dv_xname);
    546  1.4.2.2  bouyer 		return;
    547  1.4.2.2  bouyer 	}
    548  1.4.2.2  bouyer 
    549  1.4.2.2  bouyer 	if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM, 0,
    550  1.4.2.2  bouyer 			   &sc->regiot, &sc->regioh, NULL, NULL)) {
    551  1.4.2.2  bouyer 		printf("%s: can't map registers\n", sc->dev.dv_xname);
    552  1.4.2.2  bouyer 		return;
    553  1.4.2.2  bouyer 	}
    554  1.4.2.2  bouyer 
    555  1.4.2.2  bouyer 	/* Map and establish the interrupt. */
    556  1.4.2.2  bouyer 	if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
    557  1.4.2.2  bouyer 			 pa->pa_intrline, &ih)) {
    558  1.4.2.2  bouyer 		printf("%s: couldn't map interrupt\n", sc->dev.dv_xname);
    559  1.4.2.2  bouyer 		return;
    560  1.4.2.2  bouyer 	}
    561  1.4.2.2  bouyer 
    562  1.4.2.2  bouyer 	intrstr = pci_intr_string(pc, ih);
    563  1.4.2.2  bouyer 	sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
    564  1.4.2.2  bouyer 
    565  1.4.2.2  bouyer 	if (sc->ih == NULL) {
    566  1.4.2.2  bouyer 		printf("%s: couldn't establish interrupt",
    567  1.4.2.2  bouyer 		       sc->dev.dv_xname);
    568  1.4.2.2  bouyer 		if (intrstr != NULL)
    569  1.4.2.2  bouyer 			printf(" at %s", intrstr);
    570  1.4.2.2  bouyer 		printf("\n");
    571  1.4.2.2  bouyer 		return;
    572  1.4.2.2  bouyer 	}
    573  1.4.2.2  bouyer 	printf("%s: interruping at %s\n", sc->dev.dv_xname, intrstr);
    574  1.4.2.2  bouyer 
    575  1.4.2.2  bouyer 	if ((error = nm_init(sc)) != 0)
    576  1.4.2.2  bouyer 		return;
    577  1.4.2.2  bouyer 
    578  1.4.2.2  bouyer 	/* Enable the device. */
    579  1.4.2.2  bouyer 	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
    580  1.4.2.2  bouyer 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
    581  1.4.2.2  bouyer 		       csr | PCI_COMMAND_MASTER_ENABLE);
    582  1.4.2.2  bouyer 
    583  1.4.2.2  bouyer 	sc->host_if.arg = sc;
    584  1.4.2.2  bouyer 
    585  1.4.2.2  bouyer 	sc->host_if.attach = neo_attach_codec;
    586  1.4.2.2  bouyer 	sc->host_if.read   = neo_read_codec;
    587  1.4.2.2  bouyer 	sc->host_if.write  = neo_write_codec;
    588  1.4.2.2  bouyer 	sc->host_if.reset  = neo_reset_codec;
    589  1.4.2.2  bouyer 	sc->host_if.flags  = neo_flags_codec;
    590  1.4.2.2  bouyer 
    591  1.4.2.2  bouyer 	if ((error = ac97_attach(&sc->host_if)) != 0)
    592  1.4.2.2  bouyer 		return;
    593  1.4.2.2  bouyer 
    594  1.4.2.2  bouyer 	audio_attach_mi(&neo_hw_if, sc, &sc->dev);
    595  1.4.2.2  bouyer }
    596  1.4.2.2  bouyer 
    597  1.4.2.2  bouyer int
    598  1.4.2.2  bouyer neo_read_codec(void *v, u_int8_t a, u_int16_t *d)
    599  1.4.2.2  bouyer {
    600  1.4.2.2  bouyer 	struct neo_softc *sc = v;
    601  1.4.2.2  bouyer 
    602  1.4.2.2  bouyer 	if (!nm_waitcd(sc)) {
    603  1.4.2.2  bouyer 		*d = nm_rd_2(sc, sc->ac97_base + a);
    604  1.4.2.2  bouyer 		DELAY(1000);
    605  1.4.2.2  bouyer 		return 0;
    606  1.4.2.2  bouyer 	}
    607  1.4.2.2  bouyer 
    608  1.4.2.2  bouyer 	return (ENXIO);
    609  1.4.2.2  bouyer }
    610  1.4.2.2  bouyer 
    611  1.4.2.2  bouyer 
    612  1.4.2.2  bouyer int
    613  1.4.2.2  bouyer neo_write_codec(void *v, u_int8_t a, u_int16_t d)
    614  1.4.2.2  bouyer {
    615  1.4.2.2  bouyer 	struct neo_softc *sc = v;
    616  1.4.2.2  bouyer 	int cnt = 3;
    617  1.4.2.2  bouyer 
    618  1.4.2.2  bouyer 	if (!nm_waitcd(sc)) {
    619  1.4.2.2  bouyer 		while (cnt-- > 0) {
    620  1.4.2.2  bouyer 			nm_wr_2(sc, sc->ac97_base + a, d);
    621  1.4.2.2  bouyer 			if (!nm_waitcd(sc)) {
    622  1.4.2.2  bouyer 				DELAY(1000);
    623  1.4.2.2  bouyer 				return (0);
    624  1.4.2.2  bouyer 			}
    625  1.4.2.2  bouyer 		}
    626  1.4.2.2  bouyer 	}
    627  1.4.2.2  bouyer 
    628  1.4.2.2  bouyer         return (ENXIO);
    629  1.4.2.2  bouyer }
    630  1.4.2.2  bouyer 
    631  1.4.2.2  bouyer int
    632  1.4.2.2  bouyer neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
    633  1.4.2.2  bouyer {
    634  1.4.2.2  bouyer 	struct neo_softc *sc = v;
    635  1.4.2.2  bouyer 
    636  1.4.2.2  bouyer 	sc->codec_if = codec_if;
    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 void
    641  1.4.2.2  bouyer neo_reset_codec(void *v)
    642  1.4.2.2  bouyer {
    643  1.4.2.2  bouyer 	struct neo_softc *sc = v;
    644  1.4.2.2  bouyer 
    645  1.4.2.2  bouyer 	nm_wr_1(sc, 0x6c0, 0x01);
    646  1.4.2.2  bouyer 	nm_wr_1(sc, 0x6cc, 0x87);
    647  1.4.2.2  bouyer 	nm_wr_1(sc, 0x6cc, 0x80);
    648  1.4.2.2  bouyer 	nm_wr_1(sc, 0x6cc, 0x00);
    649  1.4.2.2  bouyer }
    650  1.4.2.2  bouyer 
    651  1.4.2.2  bouyer enum ac97_host_flags
    652  1.4.2.2  bouyer neo_flags_codec(void *v)
    653  1.4.2.2  bouyer {
    654  1.4.2.2  bouyer 
    655  1.4.2.2  bouyer 	return (AC97_HOST_DONT_READ);
    656  1.4.2.2  bouyer }
    657  1.4.2.2  bouyer 
    658  1.4.2.2  bouyer int
    659  1.4.2.2  bouyer neo_open(void *addr, int flags)
    660  1.4.2.2  bouyer {
    661  1.4.2.2  bouyer 
    662  1.4.2.2  bouyer 	return (0);
    663  1.4.2.2  bouyer }
    664  1.4.2.2  bouyer 
    665  1.4.2.2  bouyer /*
    666  1.4.2.2  bouyer  * Close function is called at splaudio().
    667  1.4.2.2  bouyer  */
    668  1.4.2.2  bouyer void
    669  1.4.2.2  bouyer neo_close(void *addr)
    670  1.4.2.2  bouyer {
    671  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    672  1.4.2.2  bouyer 
    673  1.4.2.2  bouyer 	neo_halt_output(sc);
    674  1.4.2.2  bouyer 	neo_halt_input(sc);
    675  1.4.2.2  bouyer 
    676  1.4.2.2  bouyer 	sc->pintr = 0;
    677  1.4.2.2  bouyer 	sc->rintr = 0;
    678  1.4.2.2  bouyer }
    679  1.4.2.2  bouyer 
    680  1.4.2.2  bouyer int
    681  1.4.2.2  bouyer neo_query_encoding(void *addr, struct audio_encoding *fp)
    682  1.4.2.2  bouyer {
    683  1.4.2.2  bouyer 
    684  1.4.2.2  bouyer 	switch (fp->index) {
    685  1.4.2.2  bouyer 	case 0:
    686  1.4.2.2  bouyer 		strcpy(fp->name, AudioEulinear);
    687  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_ULINEAR;
    688  1.4.2.2  bouyer 		fp->precision = 8;
    689  1.4.2.2  bouyer 		fp->flags = 0;
    690  1.4.2.2  bouyer 		return (0);
    691  1.4.2.2  bouyer 	case 1:
    692  1.4.2.2  bouyer 		strcpy(fp->name, AudioEmulaw);
    693  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_ULAW;
    694  1.4.2.2  bouyer 		fp->precision = 8;
    695  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    696  1.4.2.2  bouyer 		return (0);
    697  1.4.2.2  bouyer 	case 2:
    698  1.4.2.2  bouyer 		strcpy(fp->name, AudioEalaw);
    699  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_ALAW;
    700  1.4.2.2  bouyer 		fp->precision = 8;
    701  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    702  1.4.2.2  bouyer 		return (0);
    703  1.4.2.2  bouyer 	case 3:
    704  1.4.2.2  bouyer 		strcpy(fp->name, AudioEslinear);
    705  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_SLINEAR;
    706  1.4.2.2  bouyer 		fp->precision = 8;
    707  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    708  1.4.2.2  bouyer 		return (0);
    709  1.4.2.2  bouyer 	case 4:
    710  1.4.2.2  bouyer 		strcpy(fp->name, AudioEslinear_le);
    711  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
    712  1.4.2.2  bouyer 		fp->precision = 16;
    713  1.4.2.2  bouyer 		fp->flags = 0;
    714  1.4.2.2  bouyer 		return (0);
    715  1.4.2.2  bouyer 	case 5:
    716  1.4.2.2  bouyer 		strcpy(fp->name, AudioEulinear_le);
    717  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
    718  1.4.2.2  bouyer 		fp->precision = 16;
    719  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    720  1.4.2.2  bouyer 		return (0);
    721  1.4.2.2  bouyer 	case 6:
    722  1.4.2.2  bouyer 		strcpy(fp->name, AudioEslinear_be);
    723  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
    724  1.4.2.2  bouyer 		fp->precision = 16;
    725  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    726  1.4.2.2  bouyer 		return (0);
    727  1.4.2.2  bouyer 	case 7:
    728  1.4.2.2  bouyer 		strcpy(fp->name, AudioEulinear_be);
    729  1.4.2.2  bouyer 		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
    730  1.4.2.2  bouyer 		fp->precision = 16;
    731  1.4.2.2  bouyer 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
    732  1.4.2.2  bouyer 		return (0);
    733  1.4.2.2  bouyer 	default:
    734  1.4.2.2  bouyer 		return (EINVAL);
    735  1.4.2.2  bouyer 	}
    736  1.4.2.2  bouyer }
    737  1.4.2.2  bouyer 
    738  1.4.2.2  bouyer /* Todo: don't commit settings to card until we've verified all parameters */
    739  1.4.2.2  bouyer int
    740  1.4.2.2  bouyer neo_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
    741  1.4.2.2  bouyer     struct audio_params *rec)
    742  1.4.2.2  bouyer {
    743  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    744  1.4.2.2  bouyer 	u_int32_t base;
    745  1.4.2.2  bouyer 	u_int8_t x;
    746  1.4.2.2  bouyer 	int mode;
    747  1.4.2.2  bouyer 	struct audio_params *p;
    748  1.4.2.2  bouyer 
    749  1.4.2.2  bouyer 	for (mode = AUMODE_RECORD; mode != -1;
    750  1.4.2.2  bouyer 	     mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
    751  1.4.2.2  bouyer 		if ((setmode & mode) == 0)
    752  1.4.2.2  bouyer 			continue;
    753  1.4.2.2  bouyer 
    754  1.4.2.2  bouyer 		p = mode == AUMODE_PLAY ? play : rec;
    755  1.4.2.2  bouyer 
    756  1.4.2.2  bouyer 		if (p == NULL) continue;
    757  1.4.2.2  bouyer 
    758  1.4.2.2  bouyer 		for (x = 0; x < 8; x++) {
    759  1.4.2.2  bouyer 			if (p->sample_rate <
    760  1.4.2.2  bouyer 			    (samplerates[x] + samplerates[x + 1]) / 2)
    761  1.4.2.2  bouyer 				break;
    762  1.4.2.2  bouyer 		}
    763  1.4.2.2  bouyer 		if (x == 8)
    764  1.4.2.2  bouyer 			return (EINVAL);
    765  1.4.2.2  bouyer 
    766  1.4.2.2  bouyer 		p->sample_rate = samplerates[x];
    767  1.4.2.2  bouyer 		nm_loadcoeff(sc, mode, x);
    768  1.4.2.2  bouyer 
    769  1.4.2.2  bouyer 		x <<= 4;
    770  1.4.2.2  bouyer 		x &= NM_RATE_MASK;
    771  1.4.2.2  bouyer 		if (p->precision == 16)
    772  1.4.2.2  bouyer 			x |= NM_RATE_BITS_16;
    773  1.4.2.2  bouyer 		if (p->channels == 2)
    774  1.4.2.2  bouyer 			x |= NM_RATE_STEREO;
    775  1.4.2.2  bouyer 
    776  1.4.2.2  bouyer 		base = (mode == AUMODE_PLAY)?
    777  1.4.2.2  bouyer 		    NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
    778  1.4.2.2  bouyer 		nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
    779  1.4.2.2  bouyer 
    780  1.4.2.2  bouyer 		p->factor = 1;
    781  1.4.2.2  bouyer 		p->sw_code = 0;
    782  1.4.2.2  bouyer 		switch (p->encoding) {
    783  1.4.2.2  bouyer 		case AUDIO_ENCODING_SLINEAR_BE:
    784  1.4.2.2  bouyer 			if (p->precision == 16)
    785  1.4.2.2  bouyer 				p->sw_code = swap_bytes;
    786  1.4.2.2  bouyer 			else
    787  1.4.2.2  bouyer 				p->sw_code = change_sign8;
    788  1.4.2.2  bouyer 			break;
    789  1.4.2.2  bouyer 		case AUDIO_ENCODING_SLINEAR_LE:
    790  1.4.2.2  bouyer 			if (p->precision != 16)
    791  1.4.2.2  bouyer 				p->sw_code = change_sign8;
    792  1.4.2.2  bouyer 			break;
    793  1.4.2.2  bouyer 		case AUDIO_ENCODING_ULINEAR_BE:
    794  1.4.2.2  bouyer 			if (p->precision == 16) {
    795  1.4.2.2  bouyer 				if (mode == AUMODE_PLAY)
    796  1.4.2.2  bouyer 					p->sw_code =
    797  1.4.2.2  bouyer 					    swap_bytes_change_sign16_le;
    798  1.4.2.2  bouyer 				else
    799  1.4.2.2  bouyer 					p->sw_code =
    800  1.4.2.2  bouyer 					    change_sign16_swap_bytes_le;
    801  1.4.2.2  bouyer 			}
    802  1.4.2.2  bouyer 			break;
    803  1.4.2.2  bouyer 		case AUDIO_ENCODING_ULINEAR_LE:
    804  1.4.2.2  bouyer 			if (p->precision == 16)
    805  1.4.2.2  bouyer 				p->sw_code = change_sign16_le;
    806  1.4.2.2  bouyer 			break;
    807  1.4.2.2  bouyer 		case AUDIO_ENCODING_ULAW:
    808  1.4.2.2  bouyer 			if (mode == AUMODE_PLAY) {
    809  1.4.2.2  bouyer 				p->factor = 2;
    810  1.4.2.2  bouyer 				p->sw_code = mulaw_to_slinear16_le;
    811  1.4.2.2  bouyer 			} else
    812  1.4.2.2  bouyer 				p->sw_code = ulinear8_to_mulaw;
    813  1.4.2.2  bouyer 			break;
    814  1.4.2.2  bouyer 		case AUDIO_ENCODING_ALAW:
    815  1.4.2.2  bouyer 			if (mode == AUMODE_PLAY) {
    816  1.4.2.2  bouyer 				p->factor = 2;
    817  1.4.2.2  bouyer 				p->sw_code = alaw_to_slinear16_le;
    818  1.4.2.2  bouyer 			} else
    819  1.4.2.2  bouyer 				p->sw_code = ulinear8_to_alaw;
    820  1.4.2.2  bouyer 			break;
    821  1.4.2.2  bouyer 		default:
    822  1.4.2.2  bouyer 			return (EINVAL);
    823  1.4.2.2  bouyer 		}
    824  1.4.2.2  bouyer 	}
    825  1.4.2.2  bouyer 
    826  1.4.2.2  bouyer 
    827  1.4.2.2  bouyer 	return (0);
    828  1.4.2.2  bouyer }
    829  1.4.2.2  bouyer 
    830  1.4.2.2  bouyer int
    831  1.4.2.2  bouyer neo_round_blocksize(void *addr, int blk)
    832  1.4.2.2  bouyer {
    833  1.4.2.2  bouyer 
    834  1.4.2.2  bouyer 	return (NM_BUFFSIZE / 2);
    835  1.4.2.2  bouyer }
    836  1.4.2.2  bouyer 
    837  1.4.2.2  bouyer int
    838  1.4.2.2  bouyer neo_trigger_output(void *addr, void *start, void *end, int blksize,
    839  1.4.2.2  bouyer     void (*intr)(void *), void *arg, struct audio_params *param)
    840  1.4.2.2  bouyer {
    841  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    842  1.4.2.2  bouyer 	int ssz;
    843  1.4.2.2  bouyer 
    844  1.4.2.2  bouyer 	sc->pintr = intr;
    845  1.4.2.2  bouyer 	sc->parg = arg;
    846  1.4.2.2  bouyer 
    847  1.4.2.2  bouyer 	ssz = (param->precision * param->factor == 16) ? 2 : 1;
    848  1.4.2.2  bouyer 	if (param->channels == 2)
    849  1.4.2.2  bouyer 		ssz <<= 1;
    850  1.4.2.2  bouyer 
    851  1.4.2.2  bouyer 	sc->pbufsize = ((char*)end - (char *)start);
    852  1.4.2.2  bouyer 	sc->pblksize = blksize;
    853  1.4.2.2  bouyer 	sc->pwmark = blksize;
    854  1.4.2.2  bouyer 
    855  1.4.2.2  bouyer 	nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
    856  1.4.2.2  bouyer 	nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
    857  1.4.2.2  bouyer 	nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
    858  1.4.2.2  bouyer 	nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
    859  1.4.2.2  bouyer 	nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
    860  1.4.2.2  bouyer 	    NM_PLAYBACK_ENABLE_FLAG);
    861  1.4.2.2  bouyer 	nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
    862  1.4.2.2  bouyer 
    863  1.4.2.2  bouyer 	return (0);
    864  1.4.2.2  bouyer }
    865  1.4.2.2  bouyer 
    866  1.4.2.2  bouyer int
    867  1.4.2.2  bouyer neo_trigger_input(void *addr, void *start, void *end, int blksize,
    868  1.4.2.2  bouyer     void (*intr)(void *), void *arg, struct audio_params *param)
    869  1.4.2.2  bouyer {
    870  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    871  1.4.2.2  bouyer 	int ssz;
    872  1.4.2.2  bouyer 
    873  1.4.2.2  bouyer 	sc->rintr = intr;
    874  1.4.2.2  bouyer 	sc->rarg = arg;
    875  1.4.2.2  bouyer 
    876  1.4.2.2  bouyer 	ssz = (param->precision * param->factor == 16) ? 2 : 1;
    877  1.4.2.2  bouyer 	if (param->channels == 2)
    878  1.4.2.2  bouyer 		ssz <<= 1;
    879  1.4.2.2  bouyer 
    880  1.4.2.2  bouyer 	sc->rbufsize = ((char*)end - (char *)start);
    881  1.4.2.2  bouyer 	sc->rblksize = blksize;
    882  1.4.2.2  bouyer 	sc->rwmark = blksize;
    883  1.4.2.2  bouyer 
    884  1.4.2.2  bouyer 	nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
    885  1.4.2.2  bouyer 	nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
    886  1.4.2.2  bouyer 	nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
    887  1.4.2.2  bouyer 	nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
    888  1.4.2.2  bouyer 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
    889  1.4.2.2  bouyer 	    NM_RECORD_ENABLE_FLAG);
    890  1.4.2.2  bouyer 
    891  1.4.2.2  bouyer 	return (0);
    892  1.4.2.2  bouyer }
    893  1.4.2.2  bouyer 
    894  1.4.2.2  bouyer int
    895  1.4.2.2  bouyer neo_halt_output(void *addr)
    896  1.4.2.2  bouyer {
    897  1.4.2.2  bouyer 	struct neo_softc *sc = (struct neo_softc *)addr;
    898  1.4.2.2  bouyer 
    899  1.4.2.2  bouyer 	nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
    900  1.4.2.2  bouyer 	nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
    901  1.4.2.2  bouyer 
    902  1.4.2.2  bouyer 	return (0);
    903  1.4.2.2  bouyer }
    904  1.4.2.2  bouyer 
    905  1.4.2.2  bouyer int
    906  1.4.2.2  bouyer neo_halt_input(void *addr)
    907  1.4.2.2  bouyer {
    908  1.4.2.2  bouyer 	struct neo_softc *sc = (struct neo_softc *)addr;
    909  1.4.2.2  bouyer 
    910  1.4.2.2  bouyer 	nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
    911  1.4.2.2  bouyer 
    912  1.4.2.2  bouyer 	return (0);
    913  1.4.2.2  bouyer }
    914  1.4.2.2  bouyer 
    915  1.4.2.2  bouyer int
    916  1.4.2.2  bouyer neo_getdev(void *addr, struct audio_device *retp)
    917  1.4.2.2  bouyer {
    918  1.4.2.2  bouyer 
    919  1.4.2.2  bouyer 	*retp = neo_device;
    920  1.4.2.2  bouyer 	return (0);
    921  1.4.2.2  bouyer }
    922  1.4.2.2  bouyer 
    923  1.4.2.2  bouyer int
    924  1.4.2.2  bouyer neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
    925  1.4.2.2  bouyer {
    926  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    927  1.4.2.2  bouyer 
    928  1.4.2.2  bouyer 	return ((sc->codec_if->vtbl->mixer_set_port)(sc->codec_if, cp));
    929  1.4.2.2  bouyer }
    930  1.4.2.2  bouyer 
    931  1.4.2.2  bouyer int
    932  1.4.2.2  bouyer neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
    933  1.4.2.2  bouyer {
    934  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    935  1.4.2.2  bouyer 
    936  1.4.2.2  bouyer 	return ((sc->codec_if->vtbl->mixer_get_port)(sc->codec_if, cp));
    937  1.4.2.2  bouyer }
    938  1.4.2.2  bouyer 
    939  1.4.2.2  bouyer int
    940  1.4.2.2  bouyer neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
    941  1.4.2.2  bouyer {
    942  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    943  1.4.2.2  bouyer 
    944  1.4.2.2  bouyer 	return ((sc->codec_if->vtbl->query_devinfo)(sc->codec_if, dip));
    945  1.4.2.2  bouyer }
    946  1.4.2.2  bouyer 
    947  1.4.2.2  bouyer void *
    948  1.4.2.2  bouyer neo_malloc(void *addr, int direction, size_t size, int pool, int flags)
    949  1.4.2.2  bouyer {
    950  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    951  1.4.2.2  bouyer 	void *rv = NULL;
    952  1.4.2.2  bouyer 
    953  1.4.2.2  bouyer 	switch (direction) {
    954  1.4.2.2  bouyer 	case AUMODE_PLAY:
    955  1.4.2.2  bouyer 		if (sc->pbuf_allocated == 0) {
    956  1.4.2.2  bouyer 			rv = (void *) sc->pbuf_vaddr;
    957  1.4.2.2  bouyer 			sc->pbuf_allocated = 1;
    958  1.4.2.2  bouyer 		}
    959  1.4.2.2  bouyer 		break;
    960  1.4.2.2  bouyer 
    961  1.4.2.2  bouyer 	case AUMODE_RECORD:
    962  1.4.2.2  bouyer 		if (sc->rbuf_allocated == 0) {
    963  1.4.2.2  bouyer 			rv = (void *) sc->rbuf_vaddr;
    964  1.4.2.2  bouyer 			sc->rbuf_allocated = 1;
    965  1.4.2.2  bouyer 		}
    966  1.4.2.2  bouyer 		break;
    967  1.4.2.2  bouyer 	}
    968  1.4.2.2  bouyer 
    969  1.4.2.2  bouyer 	return (rv);
    970  1.4.2.2  bouyer }
    971  1.4.2.2  bouyer 
    972  1.4.2.2  bouyer void
    973  1.4.2.2  bouyer neo_free(void *addr, void *ptr, int pool)
    974  1.4.2.2  bouyer {
    975  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    976  1.4.2.2  bouyer 	vaddr_t v = (vaddr_t) ptr;
    977  1.4.2.2  bouyer 
    978  1.4.2.2  bouyer 	if (v == sc->pbuf_vaddr)
    979  1.4.2.2  bouyer 		sc->pbuf_allocated = 0;
    980  1.4.2.2  bouyer 	else if (v == sc->rbuf_vaddr)
    981  1.4.2.2  bouyer 		sc->rbuf_allocated = 0;
    982  1.4.2.2  bouyer 	else
    983  1.4.2.2  bouyer 		printf("neo_free: bad address %p\n", ptr);
    984  1.4.2.2  bouyer }
    985  1.4.2.2  bouyer 
    986  1.4.2.2  bouyer size_t
    987  1.4.2.2  bouyer neo_round_buffersize(void *addr, int direction, size_t size)
    988  1.4.2.2  bouyer {
    989  1.4.2.2  bouyer 
    990  1.4.2.2  bouyer 	return (NM_BUFFSIZE);
    991  1.4.2.2  bouyer }
    992  1.4.2.2  bouyer 
    993  1.4.2.2  bouyer paddr_t
    994  1.4.2.2  bouyer neo_mappage(void *addr, void *mem, off_t off, int prot)
    995  1.4.2.2  bouyer {
    996  1.4.2.2  bouyer 	struct neo_softc *sc = addr;
    997  1.4.2.2  bouyer 	vaddr_t v = (vaddr_t) mem;
    998  1.4.2.2  bouyer 	bus_addr_t pciaddr;
    999  1.4.2.2  bouyer 
   1000  1.4.2.2  bouyer 	/* XXX Need new mapping code. */
   1001  1.4.2.2  bouyer 
   1002  1.4.2.2  bouyer 	if (v == sc->pbuf_vaddr)
   1003  1.4.2.2  bouyer 		pciaddr = sc->pbuf_pciaddr;
   1004  1.4.2.2  bouyer 	else if (v == sc->rbuf_vaddr)
   1005  1.4.2.2  bouyer 		pciaddr = sc->rbuf_pciaddr;
   1006  1.4.2.2  bouyer 	else
   1007  1.4.2.2  bouyer 		return (-1);
   1008  1.4.2.2  bouyer 
   1009  1.4.2.2  bouyer #ifdef __i386__
   1010  1.4.2.2  bouyer 	return (i386_btop(pciaddr + off));
   1011  1.4.2.2  bouyer #else
   1012  1.4.2.2  bouyer 	return (-1);
   1013  1.4.2.2  bouyer #endif
   1014  1.4.2.2  bouyer }
   1015  1.4.2.2  bouyer 
   1016  1.4.2.2  bouyer int
   1017  1.4.2.2  bouyer neo_get_props(void *addr)
   1018  1.4.2.2  bouyer {
   1019  1.4.2.2  bouyer 
   1020  1.4.2.2  bouyer 	return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
   1021  1.4.2.2  bouyer                 AUDIO_PROP_FULLDUPLEX);
   1022  1.4.2.2  bouyer }
   1023