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