171901Sscottl/*-
271901Sscottl * Copyright (c) 2001 Scott Long <scottl@freebsd.org>
371901Sscottl * Copyright (c) 2001 Darrell Anderson <anderson@cs.duke.edu>
471901Sscottl * All rights reserved.
571901Sscottl *
671901Sscottl * Redistribution and use in source and binary forms, with or without
771901Sscottl * modification, are permitted provided that the following conditions
871901Sscottl * are met:
971901Sscottl * 1. Redistributions of source code must retain the above copyright
1071901Sscottl *    notice, this list of conditions and the following disclaimer.
1171901Sscottl * 2. Redistributions in binary form must reproduce the above copyright
1271901Sscottl *    notice, this list of conditions and the following disclaimer in the
1371901Sscottl *    documentation and/or other materials provided with the distribution.
1471901Sscottl *
1571901Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1671901Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1771901Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1871901Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1971901Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2071901Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2171901Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2271901Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2371901Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2471901Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2571901Sscottl * SUCH DAMAGE.
2671901Sscottl */
2771901Sscottl
2871901Sscottl/*
2971901Sscottl * Maestro-3/Allegro FreeBSD pcm sound driver
3071901Sscottl *
3171901Sscottl * executive status summary:
3271901Sscottl * (+) /dev/dsp multiple concurrent play channels.
3371901Sscottl * (+) /dev/dsp config (speed, mono/stereo, 8/16 bit).
3471901Sscottl * (+) /dev/mixer sets left/right volumes.
3571901Sscottl * (+) /dev/dsp recording works.  Tested successfully with the cdrom channel
3671901Sscottl * (+) apm suspend/resume works, and works properly!.
3771901Sscottl * (-) hardware volme controls don't work =-(
3871901Sscottl * (-) setblocksize() does nothing.
3971901Sscottl *
4071901Sscottl * The real credit goes to:
4171901Sscottl *
4271901Sscottl * Zach Brown for his Linux driver core and helpful technical comments.
4371901Sscottl * <zab@zabbo.net>, http://www.zabbo.net/maestro3
4471901Sscottl *
4571901Sscottl * Cameron Grant created the pcm framework used here nearly verbatim.
4671901Sscottl * <cg@freebsd.org>, http://people.freebsd.org/~cg/template.c
4771901Sscottl *
4871901Sscottl * Taku YAMAMOTO for his Maestro-1/2 FreeBSD driver and sanity reference.
4971901Sscottl * <taku@cent.saitama-u.ac.jp>
5074797Scg *
5171901Sscottl * ESS docs explained a few magic registers and numbers.
5274797Scg * http://virgo.caltech.edu/~dmoore/maestro3.pdf.gz
5371901Sscottl */
5471901Sscottl
55193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
56193640Sariff#include "opt_snd.h"
57193640Sariff#endif
58193640Sariff
5971901Sscottl#include <dev/sound/pcm/sound.h>
6071901Sscottl#include <dev/sound/pcm/ac97.h>
6171901Sscottl
62119287Simp#include <dev/pci/pcireg.h>
63119287Simp#include <dev/pci/pcivar.h>
6471901Sscottl
65230985Spfg#define M3_MODEL 1
6671901Sscottl
67230985Spfg#include <dev/sound/pci/allegro_reg.h>
68230985Spfg#include <dev/sound/pci/allegro_code.h>
69230985Spfg
7082180ScgSND_DECLARE_FILE("$FreeBSD$");
7182180Scg
7271901Sscottl/* -------------------------------------------------------------------- */
7371901Sscottl
7471901Sscottlenum {CHANGE=0, CALL=1, INTR=2, BORING=3, NONE=-1};
7571901Sscottl#ifndef M3_DEBUG_LEVEL
7671901Sscottl#define M3_DEBUG_LEVEL NONE
7771901Sscottl#endif
7871901Sscottl#define M3_DEBUG(level, _msg) {if ((level) <= M3_DEBUG_LEVEL) {printf _msg;}}
7971901Sscottl
8071901Sscottl/* -------------------------------------------------------------------- */
8171901Sscottlenum {
8271901Sscottl	ESS_ALLEGRO_1,
8371901Sscottl	ESS_MAESTRO3
8471901Sscottl};
8571901Sscottl
8671901Sscottlstatic struct m3_card_type {
8771901Sscottl	u_int32_t pci_id; int which; int delay1; int delay2; char *name;
8871901Sscottl} m3_card_types[] = {
8971901Sscottl	{ 0x1988125d, ESS_ALLEGRO_1, 50, 800, "ESS Technology Allegro-1" },
9071901Sscottl	{ 0x1998125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" },
9171901Sscottl	{ 0x199a125d, ESS_MAESTRO3, 20, 500, "ESS Technology Maestro3" },
9271901Sscottl	{ 0, 0, 0, 0, NULL }
9371901Sscottl};
9471901Sscottl
95167355Sariff#define M3_BUFSIZE_MIN	4096
96146514Syongari#define M3_BUFSIZE_MAX	65536
9784731Sscottl#define M3_BUFSIZE_DEFAULT 4096
9884926Sscottl#define M3_PCHANS 4 /* create /dev/dsp0.[0-N] to use more than one */
9971901Sscottl#define M3_RCHANS 1
10080003Sscottl#define M3_MAXADDR ((1 << 27) - 1)
101230985Spfg#define M3_DEFAULT_VOL 0x6800
10271901Sscottl
10371901Sscottlstruct sc_info;
10471901Sscottl
10571901Sscottlstruct sc_pchinfo {
10671901Sscottl	u_int32_t	spd;
10771901Sscottl	u_int32_t	fmt;
10874763Scg	struct snd_dbuf	*buffer;
10974763Scg	struct pcm_channel	*channel;
11071901Sscottl	struct sc_info	*parent;
11171901Sscottl	u_int32_t	bufsize;
11271901Sscottl	u_int32_t	dac_data;
11371901Sscottl	u_int32_t	dac_idx;
11471901Sscottl	u_int32_t	active;
115167355Sariff	u_int32_t	ptr;
116167355Sariff	u_int32_t	prevptr;
11771901Sscottl};
11871901Sscottl
11971901Sscottlstruct sc_rchinfo {
12071901Sscottl	u_int32_t	spd;
12171901Sscottl	u_int32_t	fmt;
12274763Scg	struct snd_dbuf	*buffer;
12374763Scg	struct pcm_channel	*channel;
12471901Sscottl	struct sc_info	*parent;
12571901Sscottl	u_int32_t	bufsize;
12671901Sscottl	u_int32_t	adc_data;
12771901Sscottl	u_int32_t	adc_idx;
12871901Sscottl	u_int32_t	active;
129167355Sariff	u_int32_t	ptr;
130167355Sariff	u_int32_t	prevptr;
13171901Sscottl};
13271901Sscottl
13371901Sscottlstruct sc_info {
13471901Sscottl	device_t		dev;
13571901Sscottl	u_int32_t		type;
13671901Sscottl	int			which;
13771901Sscottl	int			delay1;
13871901Sscottl	int			delay2;
13971901Sscottl
14071901Sscottl	bus_space_tag_t		st;
14171901Sscottl	bus_space_handle_t	 sh;
14271901Sscottl	bus_dma_tag_t		parent_dmat;
14371901Sscottl
14471901Sscottl	struct resource		*reg;
14571901Sscottl	struct resource		*irq;
14671901Sscottl	int			regtype;
14771901Sscottl	int			regid;
14871901Sscottl	int			irqid;
14971901Sscottl	void			*ih;
15071901Sscottl
15171901Sscottl	struct sc_pchinfo	pch[M3_PCHANS];
15271901Sscottl	struct sc_rchinfo	rch[M3_RCHANS];
15371901Sscottl	int			pch_cnt;
15471901Sscottl	int			rch_cnt;
15571901Sscottl	int			pch_active_cnt;
15684731Sscottl	unsigned int		bufsz;
15771901Sscottl	u_int16_t		*savemem;
158146514Syongari
159146514Syongari	struct mtx		*sc_lock;
16071901Sscottl};
16171901Sscottl
162146514Syongari#define M3_LOCK(_sc)		snd_mtxlock((_sc)->sc_lock)
163146514Syongari#define M3_UNLOCK(_sc)		snd_mtxunlock((_sc)->sc_lock)
164146514Syongari#define M3_LOCK_ASSERT(_sc)	snd_mtxassert((_sc)->sc_lock)
165146514Syongari
16671901Sscottl/* -------------------------------------------------------------------- */
16771901Sscottl
16871901Sscottl/* play channel interface */
16974763Scgstatic void *m3_pchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
17071901Sscottlstatic int m3_pchan_free(kobj_t, void *);
17171901Sscottlstatic int m3_pchan_setformat(kobj_t, void *, u_int32_t);
172193640Sariffstatic u_int32_t m3_pchan_setspeed(kobj_t, void *, u_int32_t);
173193640Sariffstatic u_int32_t m3_pchan_setblocksize(kobj_t, void *, u_int32_t);
17471901Sscottlstatic int m3_pchan_trigger(kobj_t, void *, int);
175146514Syongaristatic int m3_pchan_trigger_locked(kobj_t, void *, int);
176167355Sariffstatic u_int32_t m3_pchan_getptr_internal(struct sc_pchinfo *);
177167355Sariffstatic u_int32_t m3_pchan_getptr(kobj_t, void *);
17874763Scgstatic struct pcmchan_caps *m3_pchan_getcaps(kobj_t, void *);
17971901Sscottl
18071901Sscottl/* record channel interface */
18174763Scgstatic void *m3_rchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
18271901Sscottlstatic int m3_rchan_free(kobj_t, void *);
18371901Sscottlstatic int m3_rchan_setformat(kobj_t, void *, u_int32_t);
184193640Sariffstatic u_int32_t m3_rchan_setspeed(kobj_t, void *, u_int32_t);
185193640Sariffstatic u_int32_t m3_rchan_setblocksize(kobj_t, void *, u_int32_t);
18671901Sscottlstatic int m3_rchan_trigger(kobj_t, void *, int);
187146514Syongaristatic int m3_rchan_trigger_locked(kobj_t, void *, int);
188167355Sariffstatic u_int32_t m3_rchan_getptr_internal(struct sc_rchinfo *);
189167355Sariffstatic u_int32_t m3_rchan_getptr(kobj_t, void *);
19074763Scgstatic struct pcmchan_caps *m3_rchan_getcaps(kobj_t, void *);
19171901Sscottl
192167355Sariffstatic int m3_chan_active(struct sc_info *);
193167355Sariff
19471901Sscottl/* talk to the codec - called from ac97.c */
195193640Sariffstatic u_int32_t m3_initcd(kobj_t, void *);
19671901Sscottlstatic int	 m3_rdcd(kobj_t, void *, int);
19771901Sscottlstatic int  	 m3_wrcd(kobj_t, void *, int, u_int32_t);
19871901Sscottl
19971901Sscottl/* stuff */
20071901Sscottlstatic void      m3_intr(void *);
20171901Sscottlstatic int       m3_power(struct sc_info *, int);
20271901Sscottlstatic int       m3_init(struct sc_info *);
20371901Sscottlstatic int       m3_uninit(struct sc_info *);
20471901Sscottlstatic u_int8_t	 m3_assp_halt(struct sc_info *);
20571901Sscottlstatic void	 m3_config(struct sc_info *);
20671901Sscottlstatic void	 m3_amp_enable(struct sc_info *);
20771901Sscottlstatic void	 m3_enable_ints(struct sc_info *);
20871901Sscottlstatic void	 m3_codec_reset(struct sc_info *);
20971901Sscottl
21071901Sscottl/* -------------------------------------------------------------------- */
21171901Sscottl/* Codec descriptor */
21271901Sscottlstatic kobj_method_t m3_codec_methods[] = {
21371901Sscottl	KOBJMETHOD(ac97_init,	m3_initcd),
21471901Sscottl	KOBJMETHOD(ac97_read,	m3_rdcd),
21571901Sscottl	KOBJMETHOD(ac97_write,	m3_wrcd),
216193640Sariff	KOBJMETHOD_END
21771901Sscottl};
21871901SscottlAC97_DECLARE(m3_codec);
21971901Sscottl
22071901Sscottl/* -------------------------------------------------------------------- */
22171901Sscottl/* channel descriptors */
22271901Sscottl
22371901Sscottlstatic u_int32_t m3_playfmt[] = {
224193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
225193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
226193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
227193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
22871901Sscottl	0
22971901Sscottl};
23074763Scgstatic struct pcmchan_caps m3_playcaps = {8000, 48000, m3_playfmt, 0};
23171901Sscottl
23271901Sscottlstatic kobj_method_t m3_pch_methods[] = {
23371901Sscottl	KOBJMETHOD(channel_init,		m3_pchan_init),
23471901Sscottl	KOBJMETHOD(channel_setformat,		m3_pchan_setformat),
23571901Sscottl	KOBJMETHOD(channel_setspeed,		m3_pchan_setspeed),
23671901Sscottl	KOBJMETHOD(channel_setblocksize,	m3_pchan_setblocksize),
23771901Sscottl	KOBJMETHOD(channel_trigger,		m3_pchan_trigger),
23871901Sscottl	KOBJMETHOD(channel_getptr,		m3_pchan_getptr),
23971901Sscottl	KOBJMETHOD(channel_getcaps,		m3_pchan_getcaps),
24071901Sscottl	KOBJMETHOD(channel_free,		m3_pchan_free),
241193640Sariff	KOBJMETHOD_END
24271901Sscottl};
24371901SscottlCHANNEL_DECLARE(m3_pch);
24471901Sscottl
24571901Sscottlstatic u_int32_t m3_recfmt[] = {
246193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
247193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
248193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
249193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
25071901Sscottl	0
25171901Sscottl};
25274763Scgstatic struct pcmchan_caps m3_reccaps = {8000, 48000, m3_recfmt, 0};
25371901Sscottl
25471901Sscottlstatic kobj_method_t m3_rch_methods[] = {
25571901Sscottl	KOBJMETHOD(channel_init,		m3_rchan_init),
25671901Sscottl	KOBJMETHOD(channel_setformat,		m3_rchan_setformat),
25771901Sscottl	KOBJMETHOD(channel_setspeed,		m3_rchan_setspeed),
25871901Sscottl	KOBJMETHOD(channel_setblocksize,	m3_rchan_setblocksize),
25971901Sscottl	KOBJMETHOD(channel_trigger,		m3_rchan_trigger),
26071901Sscottl	KOBJMETHOD(channel_getptr,		m3_rchan_getptr),
26171901Sscottl	KOBJMETHOD(channel_getcaps,		m3_rchan_getcaps),
26271901Sscottl	KOBJMETHOD(channel_free,		m3_rchan_free),
263193640Sariff	KOBJMETHOD_END
26471901Sscottl};
26571901SscottlCHANNEL_DECLARE(m3_rch);
26671901Sscottl
26771901Sscottl/* -------------------------------------------------------------------- */
26871901Sscottl/* some i/o convenience functions */
26971901Sscottl
27071901Sscottl#define m3_rd_1(sc, regno) bus_space_read_1(sc->st, sc->sh, regno)
27171901Sscottl#define m3_rd_2(sc, regno) bus_space_read_2(sc->st, sc->sh, regno)
27271901Sscottl#define m3_rd_4(sc, regno) bus_space_read_4(sc->st, sc->sh, regno)
27371901Sscottl#define m3_wr_1(sc, regno, data) bus_space_write_1(sc->st, sc->sh, regno, data)
27471901Sscottl#define m3_wr_2(sc, regno, data) bus_space_write_2(sc->st, sc->sh, regno, data)
27571901Sscottl#define m3_wr_4(sc, regno, data) bus_space_write_4(sc->st, sc->sh, regno, data)
27671901Sscottl#define m3_rd_assp_code(sc, index) \
27771901Sscottl        m3_rd_assp(sc, MEMTYPE_INTERNAL_CODE, index)
27871901Sscottl#define m3_wr_assp_code(sc, index, data) \
27971901Sscottl        m3_wr_assp(sc, MEMTYPE_INTERNAL_CODE, index, data)
28071901Sscottl#define m3_rd_assp_data(sc, index) \
28171901Sscottl        m3_rd_assp(sc, MEMTYPE_INTERNAL_DATA, index)
28271901Sscottl#define m3_wr_assp_data(sc, index, data) \
28371901Sscottl        m3_wr_assp(sc, MEMTYPE_INTERNAL_DATA, index, data)
28471901Sscottl
28571901Sscottlstatic __inline u_int16_t
28671901Sscottlm3_rd_assp(struct sc_info *sc, u_int16_t region, u_int16_t index)
28771901Sscottl{
28871901Sscottl        m3_wr_2(sc, DSP_PORT_MEMORY_TYPE, region & MEMTYPE_MASK);
28971901Sscottl        m3_wr_2(sc, DSP_PORT_MEMORY_INDEX, index);
29071901Sscottl        return m3_rd_2(sc, DSP_PORT_MEMORY_DATA);
29171901Sscottl}
29271901Sscottl
29371901Sscottlstatic __inline void
29474797Scgm3_wr_assp(struct sc_info *sc, u_int16_t region, u_int16_t index,
29571901Sscottl	   u_int16_t data)
29671901Sscottl{
29771901Sscottl        m3_wr_2(sc, DSP_PORT_MEMORY_TYPE, region & MEMTYPE_MASK);
29871901Sscottl        m3_wr_2(sc, DSP_PORT_MEMORY_INDEX, index);
29971901Sscottl        m3_wr_2(sc, DSP_PORT_MEMORY_DATA, data);
30071901Sscottl}
30171901Sscottl
30271901Sscottlstatic __inline int
30371901Sscottlm3_wait(struct sc_info *sc)
30471901Sscottl{
30571901Sscottl	int i;
30671901Sscottl
30771901Sscottl	for (i=0 ; i<20 ; i++) {
30871901Sscottl		if ((m3_rd_1(sc, CODEC_STATUS) & 1) == 0) {
30971901Sscottl			return 0;
31071901Sscottl		}
31171901Sscottl		DELAY(2);
31271901Sscottl	}
31371901Sscottl	return -1;
31471901Sscottl}
31571901Sscottl
31671901Sscottl/* -------------------------------------------------------------------- */
31771901Sscottl/* ac97 codec */
31871901Sscottl
319193640Sariffstatic u_int32_t
32071901Sscottlm3_initcd(kobj_t kobj, void *devinfo)
32171901Sscottl{
32271901Sscottl	struct sc_info *sc = (struct sc_info *)devinfo;
32371901Sscottl	u_int32_t data;
32471901Sscottl
32571901Sscottl	M3_DEBUG(CALL, ("m3_initcd\n"));
32671901Sscottl
32771901Sscottl	/* init ac-link */
32871901Sscottl
32971901Sscottl	data = m3_rd_1(sc, CODEC_COMMAND);
33071901Sscottl	return ((data & 0x1) ? 0 : 1);
33171901Sscottl}
33271901Sscottl
33371901Sscottlstatic int
33471901Sscottlm3_rdcd(kobj_t kobj, void *devinfo, int regno)
33571901Sscottl{
33671901Sscottl	struct sc_info *sc = (struct sc_info *)devinfo;
33771901Sscottl	u_int32_t data;
33871901Sscottl
33971901Sscottl	if (m3_wait(sc)) {
34071901Sscottl		device_printf(sc->dev, "m3_rdcd timed out.\n");
34171901Sscottl		return -1;
34271901Sscottl	}
34371901Sscottl	m3_wr_1(sc, CODEC_COMMAND, (regno & 0x7f) | 0x80);
34474763Scg	DELAY(50); /* ac97 cycle = 20.8 usec */
34571901Sscottl	if (m3_wait(sc)) {
34671901Sscottl		device_printf(sc->dev, "m3_rdcd timed out.\n");
34771901Sscottl		return -1;
34871901Sscottl	}
34971901Sscottl	data = m3_rd_2(sc, CODEC_DATA);
35071901Sscottl	return data;
35171901Sscottl}
35271901Sscottl
35371901Sscottlstatic int
35471901Sscottlm3_wrcd(kobj_t kobj, void *devinfo, int regno, u_int32_t data)
35571901Sscottl{
35671901Sscottl	struct sc_info *sc = (struct sc_info *)devinfo;
35771901Sscottl	if (m3_wait(sc)) {
35871901Sscottl		device_printf(sc->dev, "m3_wrcd timed out.\n");
359201758Smbr		return -1;
36071901Sscottl	}
36171901Sscottl	m3_wr_2(sc, CODEC_DATA, data);
36271901Sscottl	m3_wr_1(sc, CODEC_COMMAND, regno & 0x7f);
36374763Scg	DELAY(50); /* ac97 cycle = 20.8 usec */
36471901Sscottl	return 0;
36571901Sscottl}
36671901Sscottl
36771901Sscottl/* -------------------------------------------------------------------- */
36871901Sscottl/* play channel interface */
36971901Sscottl
37071901Sscottl#define LO(x) (((x) & 0x0000ffff)      )
37171901Sscottl#define HI(x) (((x) & 0xffff0000) >> 16)
37271901Sscottl
37371901Sscottlstatic void *
37474763Scgm3_pchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
37571901Sscottl{
37671901Sscottl	struct sc_info *sc = devinfo;
37771901Sscottl	struct sc_pchinfo *ch;
37871901Sscottl	u_int32_t bus_addr, i;
379146514Syongari	int idx, data_bytes, dac_data;
380146514Syongari	int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf;
38171901Sscottl
382230985Spfg	struct data_word {
383230985Spfg	    u_int16_t addr, val;
384230985Spfg	} pv[] = {
385230985Spfg	    {CDATA_LEFT_VOLUME, M3_DEFAULT_VOL},
386230985Spfg	    {CDATA_RIGHT_VOLUME, M3_DEFAULT_VOL},
387230985Spfg	    {SRC3_DIRECTION_OFFSET, 0} ,
388230985Spfg	    {SRC3_DIRECTION_OFFSET + 3, 0x0000},
389230985Spfg	    {SRC3_DIRECTION_OFFSET + 4, 0},
390230985Spfg	    {SRC3_DIRECTION_OFFSET + 5, 0},
391230985Spfg	    {SRC3_DIRECTION_OFFSET + 6, 0},
392230985Spfg	    {SRC3_DIRECTION_OFFSET + 7, 0},
393230985Spfg	    {SRC3_DIRECTION_OFFSET + 8, 0},
394230985Spfg	    {SRC3_DIRECTION_OFFSET + 9, 0},
395230985Spfg	    {SRC3_DIRECTION_OFFSET + 10, 0x8000},
396230985Spfg	    {SRC3_DIRECTION_OFFSET + 11, 0xFF00},
397230985Spfg	    {SRC3_DIRECTION_OFFSET + 13, 0},
398230985Spfg	    {SRC3_DIRECTION_OFFSET + 14, 0},
399230985Spfg	    {SRC3_DIRECTION_OFFSET + 15, 0},
400230985Spfg	    {SRC3_DIRECTION_OFFSET + 16, 8},
401230985Spfg	    {SRC3_DIRECTION_OFFSET + 17, 50*2},
402230985Spfg	    {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1},
403230985Spfg	    {SRC3_DIRECTION_OFFSET + 20, 0},
404230985Spfg	    {SRC3_DIRECTION_OFFSET + 21, 0}
405230985Spfg	};
406230985Spfg
407146514Syongari	M3_LOCK(sc);
408146514Syongari	idx = sc->pch_cnt; /* dac instance number, no active reuse! */
40971901Sscottl        M3_DEBUG(CHANGE, ("m3_pchan_init(dac=%d)\n", idx));
41071901Sscottl
41171901Sscottl	if (dir != PCMDIR_PLAY) {
412146514Syongari		M3_UNLOCK(sc);
41371901Sscottl		device_printf(sc->dev, "m3_pchan_init not PCMDIR_PLAY\n");
414146514Syongari		return (NULL);
41571901Sscottl	}
416146514Syongari
417146514Syongari	data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
418146514Syongari			   (MINISRC_IN_BUFFER_SIZE & ~1) +
419146514Syongari			   (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
420146514Syongari	dac_data = 0x1100 + (data_bytes * idx);
421146514Syongari
422146514Syongari	dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
423146514Syongari	dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
424146514Syongari	dsp_in_buf = dac_data + (MINISRC_TMP_BUFFER_SIZE/2);
425146514Syongari	dsp_out_buf = dsp_in_buf + (dsp_in_size/2) + 1;
426146514Syongari
42771901Sscottl	ch = &sc->pch[idx];
42871901Sscottl	ch->dac_idx = idx;
42971901Sscottl	ch->dac_data = dac_data;
43071901Sscottl	if (ch->dac_data + data_bytes/2 >= 0x1c00) {
431146514Syongari		M3_UNLOCK(sc);
43271901Sscottl		device_printf(sc->dev, "m3_pchan_init: revb mem exhausted\n");
433146514Syongari		return (NULL);
43471901Sscottl	}
43571901Sscottl
43671901Sscottl	ch->buffer = b;
43771901Sscottl	ch->parent = sc;
43871901Sscottl	ch->channel = c;
439193640Sariff	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
44071901Sscottl	ch->spd = DSP_DEFAULT_SPEED;
441146514Syongari	M3_UNLOCK(sc); /* XXX */
442168847Sariff	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) {
44371901Sscottl		device_printf(sc->dev, "m3_pchan_init chn_allocbuf failed\n");
444146514Syongari		return (NULL);
44571901Sscottl	}
446146514Syongari	M3_LOCK(sc);
44771901Sscottl	ch->bufsize = sndbuf_getsize(ch->buffer);
44871901Sscottl
44971901Sscottl	/* host dma buffer pointers */
450111183Scognet	bus_addr = sndbuf_getbufaddr(ch->buffer);
45171901Sscottl	if (bus_addr & 3) {
45271901Sscottl		device_printf(sc->dev, "m3_pchan_init unaligned bus_addr\n");
45371901Sscottl		bus_addr = (bus_addr + 4) & ~3;
45471901Sscottl	}
45571901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr));
45671901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr));
45774797Scg	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1L,
45871901Sscottl			LO(bus_addr + ch->bufsize));
45974797Scg	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_END_PLUS_1H,
46071901Sscottl			HI(bus_addr + ch->bufsize));
46174797Scg	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL,
46271901Sscottl			LO(bus_addr));
46374797Scg	m3_wr_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH,
46471901Sscottl			HI(bus_addr));
46571901Sscottl
46671901Sscottl	/* dsp buffers */
46771901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_BEGIN, dsp_in_buf);
46871901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_END_PLUS_1,
46971901Sscottl			dsp_in_buf + dsp_in_size/2);
47071901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_HEAD, dsp_in_buf);
47171901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_IN_BUF_TAIL, dsp_in_buf);
47271901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf);
47371901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_END_PLUS_1,
47471901Sscottl			dsp_out_buf + dsp_out_size/2);
47571901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_HEAD, dsp_out_buf);
47671901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_OUT_BUF_TAIL, dsp_out_buf);
47771901Sscottl
47871901Sscottl	/* some per client initializers */
47974797Scg	m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 12,
48071901Sscottl			ch->dac_data + 40 + 8);
48171901Sscottl	m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 19,
48271901Sscottl			0x400 + MINISRC_COEF_LOC);
48371901Sscottl	/* enable or disable low pass filter? (0xff if rate> 45000) */
48471901Sscottl	m3_wr_assp_data(sc, ch->dac_data + SRC3_DIRECTION_OFFSET + 22, 0);
48571901Sscottl	/* tell it which way dma is going? */
48671901Sscottl	m3_wr_assp_data(sc, ch->dac_data + CDATA_DMA_CONTROL,
48774797Scg			DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR +
48871901Sscottl			DMAC_BLOCKF_SELECTOR);
48971901Sscottl
49071901Sscottl	/* set an armload of static initializers */
49171901Sscottl	for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) {
49271901Sscottl		m3_wr_assp_data(sc, ch->dac_data + pv[i].addr, pv[i].val);
49371901Sscottl	}
49471901Sscottl
49571901Sscottl	/* put us in the packed task lists */
49674797Scg	m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC +
49774797Scg			(sc->pch_cnt + sc->rch_cnt),
49871901Sscottl			ch->dac_data >> DP_SHIFT_COUNT);
49974797Scg	m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt),
50071901Sscottl			ch->dac_data >> DP_SHIFT_COUNT);
50174797Scg	m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + sc->pch_cnt,
50271901Sscottl			ch->dac_data >> DP_SHIFT_COUNT);
50371901Sscottl
504146514Syongari	/* gotta start before stop */
505146514Syongari	m3_pchan_trigger_locked(NULL, ch, PCMTRIG_START);
506146514Syongari	/* silence noise on load */
507146514Syongari	m3_pchan_trigger_locked(NULL, ch, PCMTRIG_STOP);
50871901Sscottl
50971901Sscottl	sc->pch_cnt++;
510146514Syongari	M3_UNLOCK(sc);
511146514Syongari
512146514Syongari	return (ch);
51371901Sscottl}
51471901Sscottl
51571901Sscottlstatic int
51671901Sscottlm3_pchan_free(kobj_t kobj, void *chdata)
51771901Sscottl{
51871901Sscottl	struct sc_pchinfo *ch = chdata;
51971901Sscottl	struct sc_info *sc = ch->parent;
52071901Sscottl
521146514Syongari	M3_LOCK(sc);
52271901Sscottl        M3_DEBUG(CHANGE, ("m3_pchan_free(dac=%d)\n", ch->dac_idx));
52371901Sscottl
52471901Sscottl	/*
52571901Sscottl	 * should remove this exact instance from the packed lists, but all
52671901Sscottl	 * are released at once (and in a stopped state) so this is ok.
52771901Sscottl	 */
52874797Scg	m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC +
52971901Sscottl			(sc->pch_cnt - 1) + sc->rch_cnt, 0);
53074797Scg	m3_wr_assp_data(sc, KDATA_DMA_XFER0 +
53171901Sscottl			(sc->pch_cnt - 1) + sc->rch_cnt, 0);
53271901Sscottl	m3_wr_assp_data(sc, KDATA_MIXER_XFER0 + (sc->pch_cnt-1), 0);
533146514Syongari	sc->pch_cnt--;
534146514Syongari	M3_UNLOCK(sc);
53571901Sscottl
536146514Syongari	return (0);
53771901Sscottl}
53871901Sscottl
53971901Sscottlstatic int
54071901Sscottlm3_pchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
54171901Sscottl{
54271901Sscottl	struct sc_pchinfo *ch = chdata;
54371901Sscottl	struct sc_info *sc = ch->parent;
54471901Sscottl	u_int32_t data;
54574797Scg
546146514Syongari	M3_LOCK(sc);
54774797Scg	M3_DEBUG(CHANGE,
54874797Scg		 ("m3_pchan_setformat(dac=%d, format=0x%x{%s-%s})\n",
54971901Sscottl		  ch->dac_idx, format,
55071901Sscottl		  format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit",
551193640Sariff		  (AFMT_CHANNEL(format) > 1) ? "STEREO":"MONO"));
55274797Scg
55371901Sscottl	/* mono word */
554193640Sariff        data = (AFMT_CHANNEL(format) > 1)? 0 : 1;
55571901Sscottl        m3_wr_assp_data(sc, ch->dac_data + SRC3_MODE_OFFSET, data);
55674797Scg
55771901Sscottl        /* 8bit word */
55871901Sscottl        data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0;
55971901Sscottl        m3_wr_assp_data(sc, ch->dac_data + SRC3_WORD_LENGTH_OFFSET, data);
56074797Scg
56171901Sscottl        ch->fmt = format;
562146514Syongari	M3_UNLOCK(sc);
563146514Syongari
564146514Syongari        return (0);
56571901Sscottl}
56671901Sscottl
567193640Sariffstatic u_int32_t
56871901Sscottlm3_pchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
56971901Sscottl{
57071901Sscottl	struct sc_pchinfo *ch = chdata;
57171901Sscottl	struct sc_info *sc = ch->parent;
57271901Sscottl	u_int32_t freq;
57371901Sscottl
574146514Syongari	M3_LOCK(sc);
57574797Scg	M3_DEBUG(CHANGE, ("m3_pchan_setspeed(dac=%d, speed=%d)\n",
57671901Sscottl			  ch->dac_idx, speed));
57771901Sscottl
57871901Sscottl        if ((freq = ((speed << 15) + 24000) / 48000) != 0) {
57971901Sscottl                freq--;
58071901Sscottl        }
58171901Sscottl
58271901Sscottl        m3_wr_assp_data(sc, ch->dac_data + CDATA_FREQUENCY, freq);
583146514Syongari	ch->spd = speed;
584146514Syongari	M3_UNLOCK(sc);
58571901Sscottl
586146514Syongari	/* return closest possible speed */
587146514Syongari	return (speed);
58871901Sscottl}
58971901Sscottl
590193640Sariffstatic u_int32_t
59171901Sscottlm3_pchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
59271901Sscottl{
59371901Sscottl	struct sc_pchinfo *ch = chdata;
59471901Sscottl
59574797Scg	M3_DEBUG(CHANGE, ("m3_pchan_setblocksize(dac=%d, blocksize=%d)\n",
59671901Sscottl			  ch->dac_idx, blocksize));
59771901Sscottl
598167355Sariff	return (sndbuf_getblksz(ch->buffer));
59971901Sscottl}
60071901Sscottl
60171901Sscottlstatic int
60271901Sscottlm3_pchan_trigger(kobj_t kobj, void *chdata, int go)
60371901Sscottl{
60471901Sscottl	struct sc_pchinfo *ch = chdata;
60571901Sscottl	struct sc_info *sc = ch->parent;
606146514Syongari	int ret;
607146514Syongari
608170521Sariff	if (!PCMTRIG_COMMON(go))
609170521Sariff		return (0);
610170521Sariff
611146514Syongari	M3_LOCK(sc);
612146514Syongari	ret = m3_pchan_trigger_locked(kobj, chdata, go);
613146514Syongari	M3_UNLOCK(sc);
614146514Syongari
615146514Syongari	return (ret);
616146514Syongari}
617146514Syongari
618146514Syongaristatic int
619167355Sariffm3_chan_active(struct sc_info *sc)
620167355Sariff{
621167355Sariff	int i, ret;
622167355Sariff
623167355Sariff	ret = 0;
624167355Sariff
625167355Sariff	for (i = 0; i < sc->pch_cnt; i++)
626167355Sariff		ret += sc->pch[i].active;
627167355Sariff
628167355Sariff	for (i = 0; i < sc->rch_cnt; i++)
629167355Sariff		ret += sc->rch[i].active;
630167355Sariff
631167355Sariff	return (ret);
632167355Sariff}
633167355Sariff
634167355Sariffstatic int
635146514Syongarim3_pchan_trigger_locked(kobj_t kobj, void *chdata, int go)
636146514Syongari{
637146514Syongari	struct sc_pchinfo *ch = chdata;
638146514Syongari	struct sc_info *sc = ch->parent;
63971901Sscottl	u_int32_t data;
64074797Scg
641146514Syongari	M3_LOCK_ASSERT(sc);
64271901Sscottl	M3_DEBUG(go == PCMTRIG_START ? CHANGE :
64371901Sscottl		 go == PCMTRIG_STOP ? CHANGE :
64471901Sscottl		 go == PCMTRIG_ABORT ? CHANGE :
64571901Sscottl		 CALL,
64671901Sscottl		 ("m3_pchan_trigger(dac=%d, go=0x%x{%s})\n", ch->dac_idx, go,
64771901Sscottl		  go == PCMTRIG_START ? "PCMTRIG_START" :
64871901Sscottl		  go == PCMTRIG_STOP ? "PCMTRIG_STOP" :
64971901Sscottl		  go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore"));
65071901Sscottl
65171901Sscottl	switch(go) {
65271901Sscottl	case PCMTRIG_START:
65371901Sscottl		if (ch->active) {
65471901Sscottl			return 0;
65571901Sscottl		}
65671901Sscottl		ch->active = 1;
657167355Sariff		ch->ptr = 0;
658167355Sariff		ch->prevptr = 0;
65971901Sscottl		sc->pch_active_cnt++;
66074797Scg
66171901Sscottl		/*[[inc_timer_users]]*/
662167355Sariff		if (m3_chan_active(sc) == 1) {
663167355Sariff	                m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
664167355Sariff        	        m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
665167355Sariff	                data = m3_rd_2(sc, HOST_INT_CTRL);
666167355Sariff        	        m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
667167355Sariff		}
66874797Scg
66971901Sscottl                m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 1);
67074797Scg                m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER,
67171901Sscottl				sc->pch_active_cnt);
67271901Sscottl		break;
67371901Sscottl
67471901Sscottl	case PCMTRIG_STOP:
67571901Sscottl	case PCMTRIG_ABORT:
67671901Sscottl		if (ch->active == 0) {
67771901Sscottl			return 0;
67871901Sscottl		}
67971901Sscottl		ch->active = 0;
68071901Sscottl		sc->pch_active_cnt--;
68171901Sscottl
68271901Sscottl		/* XXX should the channel be drained? */
68371901Sscottl		/*[[dec_timer_users]]*/
684167355Sariff		if (m3_chan_active(sc) == 0) {
685167355Sariff	                m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
686167355Sariff        	        m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
687167355Sariff                	data = m3_rd_2(sc, HOST_INT_CTRL);
688167355Sariff	                m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
689167355Sariff		}
69074797Scg
69171901Sscottl                m3_wr_assp_data(sc, ch->dac_data + CDATA_INSTANCE_READY, 0);
69274797Scg                m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER,
69371901Sscottl				sc->pch_active_cnt);
69471901Sscottl		break;
69571901Sscottl
69671901Sscottl	case PCMTRIG_EMLDMAWR:
69771901Sscottl		/* got play irq, transfer next buffer - ignore if using dma */
69871901Sscottl	case PCMTRIG_EMLDMARD:
69971901Sscottl		/* got rec irq, transfer next buffer - ignore if using dma */
70071901Sscottl	default:
70171901Sscottl		break;
70271901Sscottl	}
70371901Sscottl	return 0;
70471901Sscottl}
70571901Sscottl
706167355Sariffstatic u_int32_t
707167355Sariffm3_pchan_getptr_internal(struct sc_pchinfo *ch)
70871901Sscottl{
70971901Sscottl	struct sc_info *sc = ch->parent;
710146514Syongari	u_int32_t hi, lo, bus_base, bus_crnt;
71171901Sscottl
712146514Syongari	bus_base = sndbuf_getbufaddr(ch->buffer);
71371901Sscottl	hi = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTH);
71471901Sscottl        lo = m3_rd_assp_data(sc, ch->dac_data + CDATA_HOST_SRC_CURRENTL);
71571901Sscottl        bus_crnt = lo | (hi << 16);
71671901Sscottl
71774797Scg	M3_DEBUG(CALL, ("m3_pchan_getptr(dac=%d) result=%d\n",
71871901Sscottl			ch->dac_idx, bus_crnt - bus_base));
71971901Sscottl
72071901Sscottl	return (bus_crnt - bus_base); /* current byte offset of channel */
72171901Sscottl}
72271901Sscottl
723167355Sariffstatic u_int32_t
724167355Sariffm3_pchan_getptr(kobj_t kobj, void *chdata)
725167355Sariff{
726167355Sariff	struct sc_pchinfo *ch = chdata;
727167355Sariff	struct sc_info *sc = ch->parent;
728167355Sariff	u_int32_t ptr;
729167355Sariff
730167355Sariff	M3_LOCK(sc);
731167355Sariff	ptr = ch->ptr;
732167355Sariff	M3_UNLOCK(sc);
733167355Sariff
734167355Sariff	return (ptr);
735167355Sariff}
736167355Sariff
73774763Scgstatic struct pcmchan_caps *
73871901Sscottlm3_pchan_getcaps(kobj_t kobj, void *chdata)
73971901Sscottl{
74071901Sscottl	struct sc_pchinfo *ch = chdata;
74171901Sscottl
74271901Sscottl        M3_DEBUG(CALL, ("m3_pchan_getcaps(dac=%d)\n", ch->dac_idx));
74371901Sscottl
74471901Sscottl	return &m3_playcaps;
74571901Sscottl}
74671901Sscottl
74771901Sscottl/* -------------------------------------------------------------------- */
74871901Sscottl/* rec channel interface */
74971901Sscottl
75071901Sscottlstatic void *
75174763Scgm3_rchan_init(kobj_t kobj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
75271901Sscottl{
75371901Sscottl	struct sc_info *sc = devinfo;
75471901Sscottl	struct sc_rchinfo *ch;
75571901Sscottl	u_int32_t bus_addr, i;
75671901Sscottl
757146514Syongari	int idx, data_bytes, adc_data;
758146514Syongari	int dsp_in_size, dsp_out_size, dsp_in_buf, dsp_out_buf;
75971901Sscottl
760230985Spfg	struct data_word {
761230985Spfg	u_int16_t addr, val;
762230985Spfg	} rv[] = {
763230985Spfg	    {CDATA_LEFT_VOLUME, M3_DEFAULT_VOL},
764230985Spfg	    {CDATA_RIGHT_VOLUME, M3_DEFAULT_VOL},
765230985Spfg	    {SRC3_DIRECTION_OFFSET, 1},
766230985Spfg	    {SRC3_DIRECTION_OFFSET + 3, 0x0000},
767230985Spfg	    {SRC3_DIRECTION_OFFSET + 4, 0},
768230985Spfg	    {SRC3_DIRECTION_OFFSET + 5, 0},
769230985Spfg	    {SRC3_DIRECTION_OFFSET + 6, 0},
770230985Spfg	    {SRC3_DIRECTION_OFFSET + 7, 0},
771230985Spfg	    {SRC3_DIRECTION_OFFSET + 8, 0},
772230985Spfg	    {SRC3_DIRECTION_OFFSET + 9, 0},
773230985Spfg	    {SRC3_DIRECTION_OFFSET + 10, 0x8000},
774230985Spfg	    {SRC3_DIRECTION_OFFSET + 11, 0xFF00},
775230985Spfg	    {SRC3_DIRECTION_OFFSET + 13, 0},
776230985Spfg	    {SRC3_DIRECTION_OFFSET + 14, 0},
777230985Spfg	    {SRC3_DIRECTION_OFFSET + 15, 0},
778230985Spfg	    {SRC3_DIRECTION_OFFSET + 16, 50},
779230985Spfg	    {SRC3_DIRECTION_OFFSET + 17, 8},
780230985Spfg	    {SRC3_DIRECTION_OFFSET + 18, 0},
781230985Spfg	    {SRC3_DIRECTION_OFFSET + 19, 0},
782230985Spfg	    {SRC3_DIRECTION_OFFSET + 20, 0},
783230985Spfg	    {SRC3_DIRECTION_OFFSET + 21, 0},
784230985Spfg	    {SRC3_DIRECTION_OFFSET + 22, 0xff}
785230985Spfg	};
786230985Spfg
787146514Syongari	M3_LOCK(sc);
788146514Syongari	idx = sc->rch_cnt; /* adc instance number, no active reuse! */
78971901Sscottl        M3_DEBUG(CHANGE, ("m3_rchan_init(adc=%d)\n", idx));
79071901Sscottl
79171901Sscottl	if (dir != PCMDIR_REC) {
792146514Syongari		M3_UNLOCK(sc);
79371901Sscottl		device_printf(sc->dev, "m3_pchan_init not PCMDIR_REC\n");
794146514Syongari		return (NULL);
79571901Sscottl	}
796146514Syongari
797146514Syongari	data_bytes = (((MINISRC_TMP_BUFFER_SIZE & ~1) +
798146514Syongari			   (MINISRC_IN_BUFFER_SIZE & ~1) +
799146514Syongari			   (MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255) &~ 255;
800146514Syongari	adc_data = 0x1100 + (data_bytes * idx) + data_bytes/2;
801146514Syongari	dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
802146514Syongari	dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
803146514Syongari	dsp_in_buf = adc_data + (MINISRC_TMP_BUFFER_SIZE / 2);
804146514Syongari	dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1;
805146514Syongari
80671901Sscottl	ch = &sc->rch[idx];
80771901Sscottl	ch->adc_idx = idx;
80871901Sscottl	ch->adc_data = adc_data;
80971901Sscottl	if (ch->adc_data + data_bytes/2 >= 0x1c00) {
810146514Syongari		M3_UNLOCK(sc);
81171901Sscottl		device_printf(sc->dev, "m3_rchan_init: revb mem exhausted\n");
812146514Syongari		return (NULL);
81371901Sscottl	}
81471901Sscottl
81571901Sscottl	ch->buffer = b;
81671901Sscottl	ch->parent = sc;
81771901Sscottl	ch->channel = c;
818193640Sariff	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
81971901Sscottl	ch->spd = DSP_DEFAULT_SPEED;
820146514Syongari	M3_UNLOCK(sc); /* XXX */
821168847Sariff	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) {
82271901Sscottl		device_printf(sc->dev, "m3_rchan_init chn_allocbuf failed\n");
823146514Syongari		return (NULL);
82471901Sscottl	}
825146514Syongari	M3_LOCK(sc);
82671901Sscottl	ch->bufsize = sndbuf_getsize(ch->buffer);
82774797Scg
82871901Sscottl	/* host dma buffer pointers */
829111183Scognet	bus_addr = sndbuf_getbufaddr(ch->buffer);
83071901Sscottl	if (bus_addr & 3) {
83171901Sscottl		device_printf(sc->dev, "m3_rchan_init unaligned bus_addr\n");
83271901Sscottl		bus_addr = (bus_addr + 4) & ~3;
83371901Sscottl	}
83471901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRL, LO(bus_addr));
83571901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_ADDRH, HI(bus_addr));
83674797Scg	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1L,
83771901Sscottl			LO(bus_addr + ch->bufsize));
83874797Scg	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_END_PLUS_1H,
83971901Sscottl			HI(bus_addr + ch->bufsize));
84074797Scg	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL,
84171901Sscottl			LO(bus_addr));
84274797Scg	m3_wr_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH,
84371901Sscottl			HI(bus_addr));
84471901Sscottl
84571901Sscottl	/* dsp buffers */
84671901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_BEGIN, dsp_in_buf);
84771901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_END_PLUS_1,
84871901Sscottl			dsp_in_buf + dsp_in_size/2);
84971901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_HEAD, dsp_in_buf);
85071901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_IN_BUF_TAIL, dsp_in_buf);
85171901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_BEGIN, dsp_out_buf);
85271901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_END_PLUS_1,
85371901Sscottl			dsp_out_buf + dsp_out_size/2);
85471901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_HEAD, dsp_out_buf);
85571901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_OUT_BUF_TAIL, dsp_out_buf);
85671901Sscottl
85771901Sscottl	/* some per client initializers */
85874797Scg	m3_wr_assp_data(sc, ch->adc_data + SRC3_DIRECTION_OFFSET + 12,
85971901Sscottl			ch->adc_data + 40 + 8);
86071901Sscottl	m3_wr_assp_data(sc, ch->adc_data + CDATA_DMA_CONTROL,
86174797Scg			DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
86271901Sscottl			DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
86371901Sscottl
86471901Sscottl	/* set an armload of static initializers */
86571901Sscottl	for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) {
86671901Sscottl		m3_wr_assp_data(sc, ch->adc_data + rv[i].addr, rv[i].val);
86771901Sscottl	}
86871901Sscottl
86971901Sscottl	/* put us in the packed task lists */
87074797Scg	m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC +
87174797Scg			(sc->pch_cnt + sc->rch_cnt),
87271901Sscottl			ch->adc_data >> DP_SHIFT_COUNT);
87371901Sscottl	m3_wr_assp_data(sc, KDATA_DMA_XFER0 + (sc->pch_cnt + sc->rch_cnt),
87471901Sscottl			ch->adc_data >> DP_SHIFT_COUNT);
87574797Scg	m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + sc->rch_cnt,
87671901Sscottl			ch->adc_data >> DP_SHIFT_COUNT);
87771901Sscottl
878146514Syongari	/* gotta start before stop */
879146514Syongari	m3_rchan_trigger_locked(NULL, ch, PCMTRIG_START);
880146514Syongari	/* stop on init */
881146514Syongari	m3_rchan_trigger_locked(NULL, ch, PCMTRIG_STOP);
88274797Scg
88371901Sscottl	sc->rch_cnt++;
884146514Syongari	M3_UNLOCK(sc);
885146514Syongari
886146514Syongari	return (ch);
88771901Sscottl}
88871901Sscottl
88971901Sscottlstatic int
89071901Sscottlm3_rchan_free(kobj_t kobj, void *chdata)
89171901Sscottl{
89271901Sscottl	struct sc_rchinfo *ch = chdata;
89371901Sscottl	struct sc_info *sc = ch->parent;
89471901Sscottl
895146514Syongari	M3_LOCK(sc);
89671901Sscottl        M3_DEBUG(CHANGE, ("m3_rchan_free(adc=%d)\n", ch->adc_idx));
89771901Sscottl
89871901Sscottl	/*
89971901Sscottl	 * should remove this exact instance from the packed lists, but all
90071901Sscottl	 * are released at once (and in a stopped state) so this is ok.
90171901Sscottl	 */
90274797Scg	m3_wr_assp_data(sc, KDATA_INSTANCE0_MINISRC +
90371901Sscottl			(sc->rch_cnt - 1) + sc->pch_cnt, 0);
90474797Scg	m3_wr_assp_data(sc, KDATA_DMA_XFER0 +
90571901Sscottl			(sc->rch_cnt - 1) + sc->pch_cnt, 0);
90671901Sscottl	m3_wr_assp_data(sc, KDATA_ADC1_XFER0 + (sc->rch_cnt - 1), 0);
907146514Syongari	sc->rch_cnt--;
908146514Syongari	M3_UNLOCK(sc);
90971901Sscottl
910146514Syongari	return (0);
91171901Sscottl}
91271901Sscottl
91371901Sscottlstatic int
91471901Sscottlm3_rchan_setformat(kobj_t kobj, void *chdata, u_int32_t format)
91571901Sscottl{
91671901Sscottl	struct sc_rchinfo *ch = chdata;
91771901Sscottl	struct sc_info *sc = ch->parent;
91871901Sscottl	u_int32_t data;
91974797Scg
920146514Syongari	M3_LOCK(sc);
92174797Scg	M3_DEBUG(CHANGE,
92274797Scg		 ("m3_rchan_setformat(dac=%d, format=0x%x{%s-%s})\n",
92371901Sscottl		  ch->adc_idx, format,
92471901Sscottl		  format & (AFMT_U8|AFMT_S8) ? "8bit":"16bit",
925193640Sariff		  (AFMT_CHANNEL(format) > 1) ? "STEREO":"MONO"));
92674797Scg
92771901Sscottl	/* mono word */
928193640Sariff        data = (AFMT_CHANNEL(format) > 1) ? 0 : 1;
92971901Sscottl        m3_wr_assp_data(sc, ch->adc_data + SRC3_MODE_OFFSET, data);
93074797Scg
93171901Sscottl        /* 8bit word */
93271901Sscottl        data = ((format & AFMT_U8) || (format & AFMT_S8)) ? 1 : 0;
93371901Sscottl        m3_wr_assp_data(sc, ch->adc_data + SRC3_WORD_LENGTH_OFFSET, data);
934146514Syongari        ch->fmt = format;
935146514Syongari	M3_UNLOCK(sc);
93674797Scg
937146514Syongari        return (0);
93871901Sscottl}
93971901Sscottl
940193640Sariffstatic u_int32_t
94171901Sscottlm3_rchan_setspeed(kobj_t kobj, void *chdata, u_int32_t speed)
94271901Sscottl{
94371901Sscottl	struct sc_rchinfo *ch = chdata;
94471901Sscottl	struct sc_info *sc = ch->parent;
94571901Sscottl	u_int32_t freq;
94674797Scg
947146514Syongari	M3_LOCK(sc);
94874797Scg	M3_DEBUG(CHANGE, ("m3_rchan_setspeed(adc=%d, speed=%d)\n",
94971901Sscottl			  ch->adc_idx, speed));
95071901Sscottl
95171901Sscottl        if ((freq = ((speed << 15) + 24000) / 48000) != 0) {
95271901Sscottl                freq--;
95371901Sscottl        }
95471901Sscottl
95571901Sscottl        m3_wr_assp_data(sc, ch->adc_data + CDATA_FREQUENCY, freq);
956146514Syongari	ch->spd = speed;
957146514Syongari	M3_UNLOCK(sc);
95871901Sscottl
959146514Syongari	/* return closest possible speed */
960146514Syongari	return (speed);
96171901Sscottl}
96271901Sscottl
963193640Sariffstatic u_int32_t
96471901Sscottlm3_rchan_setblocksize(kobj_t kobj, void *chdata, u_int32_t blocksize)
96571901Sscottl{
96671901Sscottl	struct sc_rchinfo *ch = chdata;
96771901Sscottl
96874797Scg	M3_DEBUG(CHANGE, ("m3_rchan_setblocksize(adc=%d, blocksize=%d)\n",
96971901Sscottl			  ch->adc_idx, blocksize));
97071901Sscottl
971167355Sariff	return (sndbuf_getblksz(ch->buffer));
97271901Sscottl}
97371901Sscottl
97471901Sscottlstatic int
97571901Sscottlm3_rchan_trigger(kobj_t kobj, void *chdata, int go)
97671901Sscottl{
97771901Sscottl	struct sc_rchinfo *ch = chdata;
97871901Sscottl	struct sc_info *sc = ch->parent;
979146514Syongari	int ret;
980146514Syongari
981170521Sariff	if (!PCMTRIG_COMMON(go))
982170521Sariff		return (0);
983170521Sariff
984146514Syongari	M3_LOCK(sc);
985146514Syongari	ret = m3_rchan_trigger_locked(kobj, chdata, go);
986146514Syongari	M3_UNLOCK(sc);
987146514Syongari
988146514Syongari	return (ret);
989146514Syongari}
990146514Syongari
991146514Syongaristatic int
992146514Syongarim3_rchan_trigger_locked(kobj_t kobj, void *chdata, int go)
993146514Syongari{
994146514Syongari	struct sc_rchinfo *ch = chdata;
995146514Syongari	struct sc_info *sc = ch->parent;
99671901Sscottl	u_int32_t data;
99771901Sscottl
998146514Syongari	M3_LOCK_ASSERT(sc);
99971901Sscottl	M3_DEBUG(go == PCMTRIG_START ? CHANGE :
100071901Sscottl		 go == PCMTRIG_STOP ? CHANGE :
100171901Sscottl		 go == PCMTRIG_ABORT ? CHANGE :
100271901Sscottl		 CALL,
100371901Sscottl		 ("m3_rchan_trigger(adc=%d, go=0x%x{%s})\n", ch->adc_idx, go,
100471901Sscottl		  go == PCMTRIG_START ? "PCMTRIG_START" :
100571901Sscottl		  go == PCMTRIG_STOP ? "PCMTRIG_STOP" :
100671901Sscottl		  go == PCMTRIG_ABORT ? "PCMTRIG_ABORT" : "ignore"));
100771901Sscottl
100871901Sscottl	switch(go) {
100971901Sscottl	case PCMTRIG_START:
101071901Sscottl		if (ch->active) {
101171901Sscottl			return 0;
101271901Sscottl		}
101371901Sscottl		ch->active = 1;
1014167355Sariff		ch->ptr = 0;
1015167355Sariff		ch->prevptr = 0;
101674797Scg
101771901Sscottl		/*[[inc_timer_users]]*/
1018167355Sariff		if (m3_chan_active(sc) == 1) {
1019167355Sariff	                m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 240);
1020167355Sariff        	        m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 240);
1021167355Sariff                	data = m3_rd_2(sc, HOST_INT_CTRL);
1022167355Sariff	                m3_wr_2(sc, HOST_INT_CTRL, data | CLKRUN_GEN_ENABLE);
1023167355Sariff		}
102474797Scg
102571901Sscottl                m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 1);
102671901Sscottl                m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 1);
102771901Sscottl		break;
102871901Sscottl
102971901Sscottl	case PCMTRIG_STOP:
103071901Sscottl	case PCMTRIG_ABORT:
103171901Sscottl		if (ch->active == 0) {
103271901Sscottl			return 0;
103371901Sscottl		}
103471901Sscottl		ch->active = 0;
103571901Sscottl
103671901Sscottl		/*[[dec_timer_users]]*/
1037167355Sariff		if (m3_chan_active(sc) == 0) {
1038167355Sariff	                m3_wr_assp_data(sc, KDATA_TIMER_COUNT_RELOAD, 0);
1039167355Sariff        	        m3_wr_assp_data(sc, KDATA_TIMER_COUNT_CURRENT, 0);
1040167355Sariff                	data = m3_rd_2(sc, HOST_INT_CTRL);
1041167355Sariff	                m3_wr_2(sc, HOST_INT_CTRL, data & ~CLKRUN_GEN_ENABLE);
1042167355Sariff		}
104374797Scg
104471901Sscottl                m3_wr_assp_data(sc, ch->adc_data + CDATA_INSTANCE_READY, 0);
104571901Sscottl                m3_wr_assp_data(sc, KDATA_ADC1_REQUEST, 0);
104671901Sscottl		break;
104771901Sscottl
104871901Sscottl	case PCMTRIG_EMLDMAWR:
104971901Sscottl		/* got play irq, transfer next buffer - ignore if using dma */
105071901Sscottl	case PCMTRIG_EMLDMARD:
105171901Sscottl		/* got rec irq, transfer next buffer - ignore if using dma */
105271901Sscottl	default:
105371901Sscottl		break;
105471901Sscottl	}
105571901Sscottl	return 0;
105671901Sscottl}
105771901Sscottl
1058167355Sariffstatic u_int32_t
1059167355Sariffm3_rchan_getptr_internal(struct sc_rchinfo *ch)
106071901Sscottl{
106171901Sscottl	struct sc_info *sc = ch->parent;
1062146514Syongari	u_int32_t hi, lo, bus_base, bus_crnt;
106371901Sscottl
1064146514Syongari	bus_base = sndbuf_getbufaddr(ch->buffer);
106571901Sscottl	hi = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTH);
106671901Sscottl        lo = m3_rd_assp_data(sc, ch->adc_data + CDATA_HOST_SRC_CURRENTL);
106771901Sscottl        bus_crnt = lo | (hi << 16);
106871901Sscottl
106974797Scg	M3_DEBUG(CALL, ("m3_rchan_getptr(adc=%d) result=%d\n",
107071901Sscottl			ch->adc_idx, bus_crnt - bus_base));
107171901Sscottl
107271901Sscottl	return (bus_crnt - bus_base); /* current byte offset of channel */
107371901Sscottl}
107471901Sscottl
1075167355Sariffstatic u_int32_t
1076167355Sariffm3_rchan_getptr(kobj_t kobj, void *chdata)
1077167355Sariff{
1078167355Sariff	struct sc_rchinfo *ch = chdata;
1079167355Sariff	struct sc_info *sc = ch->parent;
1080167355Sariff	u_int32_t ptr;
1081167355Sariff
1082167355Sariff	M3_LOCK(sc);
1083167355Sariff	ptr = ch->ptr;
1084167355Sariff	M3_UNLOCK(sc);
1085167355Sariff
1086167355Sariff	return (ptr);
1087167355Sariff}
1088167355Sariff
108974763Scgstatic struct pcmchan_caps *
109071901Sscottlm3_rchan_getcaps(kobj_t kobj, void *chdata)
109171901Sscottl{
109271901Sscottl	struct sc_rchinfo *ch = chdata;
109371901Sscottl
109471901Sscottl        M3_DEBUG(CALL, ("m3_rchan_getcaps(adc=%d)\n", ch->adc_idx));
109571901Sscottl
109671901Sscottl	return &m3_reccaps;
109771901Sscottl}
109871901Sscottl
109971901Sscottl/* -------------------------------------------------------------------- */
110071901Sscottl/* The interrupt handler */
110171901Sscottl
110271901Sscottlstatic void
110371901Sscottlm3_intr(void *p)
110471901Sscottl{
110571901Sscottl	struct sc_info *sc = (struct sc_info *)p;
1106167355Sariff	struct sc_pchinfo *pch;
1107167355Sariff	struct sc_rchinfo *rch;
1108167355Sariff	u_int32_t status, ctl, i, delta;
110974797Scg
111071901Sscottl	M3_DEBUG(INTR, ("m3_intr\n"));
111171901Sscottl
1112146514Syongari	M3_LOCK(sc);
111371901Sscottl	status = m3_rd_1(sc, HOST_INT_STATUS);
1114146514Syongari	if (!status) {
1115146514Syongari		M3_UNLOCK(sc);
111671901Sscottl		return;
1117146514Syongari	}
111871901Sscottl
111971901Sscottl	m3_wr_1(sc, HOST_INT_STATUS, 0xff); /* ack the int? */
112071901Sscottl
112171901Sscottl	if (status & HV_INT_PENDING) {
112271901Sscottl		u_int8_t event;
112371901Sscottl
112471901Sscottl		event = m3_rd_1(sc, HW_VOL_COUNTER_MASTER);
112571901Sscottl		switch (event) {
112671901Sscottl		case 0x99:
112771901Sscottl			mixer_hwvol_mute(sc->dev);
112871901Sscottl			break;
112971901Sscottl		case 0xaa:
113071901Sscottl			mixer_hwvol_step(sc->dev, 1, 1);
113171901Sscottl			break;
113271901Sscottl		case 0x66:
113371901Sscottl			mixer_hwvol_step(sc->dev, -1, -1);
113471901Sscottl			break;
113571901Sscottl		case 0x88:
113671901Sscottl			break;
113771901Sscottl		default:
113871901Sscottl			device_printf(sc->dev, "Unknown HWVOL event\n");
113971901Sscottl		}
114071901Sscottl		m3_wr_1(sc, HW_VOL_COUNTER_MASTER, 0x88);
114174797Scg
114271901Sscottl	}
114371901Sscottl
114471901Sscottl	if (status & ASSP_INT_PENDING) {
114571901Sscottl		ctl = m3_rd_1(sc, ASSP_CONTROL_B);
114671901Sscottl		if (!(ctl & STOP_ASSP_CLOCK)) {
114771901Sscottl			ctl = m3_rd_1(sc, ASSP_HOST_INT_STATUS);
114871901Sscottl			if (ctl & DSP2HOST_REQ_TIMER) {
114974797Scg				m3_wr_1(sc, ASSP_HOST_INT_STATUS,
115071901Sscottl					DSP2HOST_REQ_TIMER);
115171901Sscottl				/*[[ess_update_ptr]]*/
1152167355Sariff				goto m3_handle_channel_intr;
115371901Sscottl			}
115471901Sscottl		}
115571901Sscottl	}
115674797Scg
1157167355Sariff	goto m3_handle_channel_intr_out;
1158167355Sariff
1159167355Sariffm3_handle_channel_intr:
116071901Sscottl	for (i=0 ; i<sc->pch_cnt ; i++) {
1161167355Sariff		pch = &sc->pch[i];
1162167355Sariff		if (pch->active) {
1163167355Sariff			pch->ptr = m3_pchan_getptr_internal(pch);
1164167355Sariff			delta = pch->bufsize + pch->ptr - pch->prevptr;
1165167355Sariff			delta %= pch->bufsize;
1166167355Sariff			if (delta < sndbuf_getblksz(pch->buffer))
1167167355Sariff				continue;
1168167355Sariff			pch->prevptr = pch->ptr;
1169146514Syongari			M3_UNLOCK(sc);
1170167355Sariff			chn_intr(pch->channel);
1171146514Syongari			M3_LOCK(sc);
117271901Sscottl		}
117371901Sscottl	}
117471901Sscottl	for (i=0 ; i<sc->rch_cnt ; i++) {
1175167355Sariff		rch = &sc->rch[i];
1176167355Sariff		if (rch->active) {
1177167355Sariff			rch->ptr = m3_rchan_getptr_internal(rch);
1178167355Sariff			delta = rch->bufsize + rch->ptr - rch->prevptr;
1179167355Sariff			delta %= rch->bufsize;
1180167355Sariff			if (delta < sndbuf_getblksz(rch->buffer))
1181167355Sariff				continue;
1182167355Sariff			rch->prevptr = rch->ptr;
1183146514Syongari			M3_UNLOCK(sc);
1184167355Sariff			chn_intr(rch->channel);
1185146514Syongari			M3_LOCK(sc);
118671901Sscottl		}
118771901Sscottl	}
1188146514Syongari
1189167355Sariffm3_handle_channel_intr_out:
1190146514Syongari	M3_UNLOCK(sc);
119171901Sscottl}
119271901Sscottl
119371901Sscottl/* -------------------------------------------------------------------- */
119471901Sscottl/* stuff */
119571901Sscottl
119671901Sscottlstatic int
119771901Sscottlm3_power(struct sc_info *sc, int state)
119871901Sscottl{
119971901Sscottl	u_int32_t data;
120071901Sscottl
120171901Sscottl	M3_DEBUG(CHANGE, ("m3_power(%d)\n", state));
1202146514Syongari	M3_LOCK_ASSERT(sc);
120371901Sscottl
120471901Sscottl	data = pci_read_config(sc->dev, 0x34, 1);
120571901Sscottl	if (pci_read_config(sc->dev, data, 1) == 1) {
120671901Sscottl		pci_write_config(sc->dev, data + 4, state, 1);
120771901Sscottl	}
120871901Sscottl
120971901Sscottl	return 0;
121071901Sscottl}
121171901Sscottl
121271901Sscottlstatic int
121371901Sscottlm3_init(struct sc_info *sc)
121471901Sscottl{
121571901Sscottl	u_int32_t data, i, size;
121671901Sscottl	u_int8_t reset_state;
121771901Sscottl
1218146514Syongari	M3_LOCK_ASSERT(sc);
121971901Sscottl        M3_DEBUG(CHANGE, ("m3_init\n"));
122071901Sscottl
122171901Sscottl	/* diable legacy emulations. */
122271901Sscottl	data = pci_read_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, 2);
122371901Sscottl	data |= DISABLE_LEGACY;
122471901Sscottl	pci_write_config(sc->dev, PCI_LEGACY_AUDIO_CTRL, data, 2);
122571901Sscottl
122671901Sscottl	m3_config(sc);
122774797Scg
122871901Sscottl	reset_state = m3_assp_halt(sc);
122971901Sscottl
123071901Sscottl	m3_codec_reset(sc);
123171901Sscottl
123271901Sscottl	/* [m3_assp_init] */
123371901Sscottl	/* zero kernel data */
123471901Sscottl	size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA;
123571901Sscottl	for(i = 0 ; i < size / 2 ; i++) {
123671901Sscottl		m3_wr_assp_data(sc, KDATA_BASE_ADDR + i, 0);
123771901Sscottl	}
123871901Sscottl	/* zero mixer data? */
123971901Sscottl	size = REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA;
124071901Sscottl	for(i = 0 ; i < size / 2 ; i++) {
124171901Sscottl		m3_wr_assp_data(sc, KDATA_BASE_ADDR2 + i, 0);
124271901Sscottl	}
124371901Sscottl	/* init dma pointer */
124474797Scg	m3_wr_assp_data(sc, KDATA_CURRENT_DMA,
124571901Sscottl			KDATA_DMA_XFER0);
124671901Sscottl	/* write kernel into code memory */
1247230985Spfg	size = sizeof(gaw_kernel_vect_code);
124871901Sscottl	for(i = 0 ; i < size / 2; i++) {
124974797Scg		m3_wr_assp_code(sc, REV_B_CODE_MEMORY_BEGIN + i,
1250230985Spfg				gaw_kernel_vect_code[i]);
125171901Sscottl	}
125271901Sscottl	/*
125371901Sscottl	 * We only have this one client and we know that 0x400 is free in
125471901Sscottl	 * our kernel's mem map, so lets just drop it there.  It seems that
125571901Sscottl	 * the minisrc doesn't need vectors, so we won't bother with them..
125671901Sscottl	 */
1257230985Spfg	size = sizeof(gaw_minisrc_code_0400);
125871901Sscottl	for(i = 0 ; i < size / 2; i++) {
1259230985Spfg		m3_wr_assp_code(sc, 0x400 + i, gaw_minisrc_code_0400[i]);
126071901Sscottl	}
126171901Sscottl	/* write the coefficients for the low pass filter? */
1262230985Spfg	size = sizeof(minisrc_lpf);
126371901Sscottl	for(i = 0; i < size / 2 ; i++) {
126474797Scg		m3_wr_assp_code(sc,0x400 + MINISRC_COEF_LOC + i,
1265230985Spfg				minisrc_lpf[i]);
126671901Sscottl	}
126771901Sscottl	m3_wr_assp_code(sc, 0x400 + MINISRC_COEF_LOC + size, 0x8000);
126871901Sscottl	/* the minisrc is the only thing on our task list */
126971901Sscottl	m3_wr_assp_data(sc, KDATA_TASK0, 0x400);
127071901Sscottl	/* init the mixer number */
127171901Sscottl	m3_wr_assp_data(sc, KDATA_MIXER_TASK_NUMBER, 0);
127271901Sscottl	/* extreme kernel master volume */
1273230985Spfg	m3_wr_assp_data(sc, KDATA_DAC_LEFT_VOLUME, M3_DEFAULT_VOL);
1274230985Spfg	m3_wr_assp_data(sc, KDATA_DAC_RIGHT_VOLUME, M3_DEFAULT_VOL);
127571901Sscottl
127671901Sscottl	m3_amp_enable(sc);
127774797Scg
127871901Sscottl	/* [m3_assp_client_init] (only one client at index 0) */
127971901Sscottl	for (i=0x1100 ; i<0x1c00 ; i++) {
128071901Sscottl		m3_wr_assp_data(sc, i, 0); /* zero entire dac/adc area */
128171901Sscottl	}
128271901Sscottl
128371901Sscottl	/* [m3_assp_continue] */
128471901Sscottl	m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET);
128571901Sscottl
128671901Sscottl	return 0;
128771901Sscottl}
128871901Sscottl
128971901Sscottlstatic int
129071901Sscottlm3_uninit(struct sc_info *sc)
129171901Sscottl{
129271901Sscottl        M3_DEBUG(CHANGE, ("m3_uninit\n"));
129371901Sscottl	return 0;
129471901Sscottl}
129571901Sscottl
129671901Sscottl/* -------------------------------------------------------------------- */
129771901Sscottl/* Probe and attach the card */
129871901Sscottl
129971901Sscottlstatic int
130071901Sscottlm3_pci_probe(device_t dev)
130171901Sscottl{
130271901Sscottl	struct m3_card_type *card;
130374797Scg
130471901Sscottl	M3_DEBUG(CALL, ("m3_pci_probe(0x%x)\n", pci_get_devid(dev)));
130571901Sscottl
130671901Sscottl	for (card = m3_card_types ; card->pci_id ; card++) {
130771901Sscottl		if (pci_get_devid(dev) == card->pci_id) {
130871901Sscottl			device_set_desc(dev, card->name);
1309142890Simp			return BUS_PROBE_DEFAULT;
131071901Sscottl		}
131171901Sscottl	}
131271901Sscottl	return ENXIO;
131371901Sscottl}
131471901Sscottl
131571901Sscottlstatic int
131671901Sscottlm3_pci_attach(device_t dev)
131771901Sscottl{
131871901Sscottl	struct sc_info *sc;
131971901Sscottl	struct ac97_info *codec = NULL;
132071901Sscottl	char status[SND_STATUSLEN];
132171901Sscottl	struct m3_card_type *card;
1322167355Sariff	int i, len, dacn, adcn;
132374797Scg
132471901Sscottl	M3_DEBUG(CALL, ("m3_pci_attach\n"));
132571901Sscottl
1326170873Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
132771901Sscottl	sc->dev = dev;
132871901Sscottl	sc->type = pci_get_devid(dev);
1329146514Syongari	sc->sc_lock = snd_mtxcreate(device_get_nameunit(dev),
1330167608Sariff	    "snd_maestro3 softc");
133171901Sscottl	for (card = m3_card_types ; card->pci_id ; card++) {
133271901Sscottl		if (sc->type == card->pci_id) {
133371901Sscottl			sc->which = card->which;
133471901Sscottl			sc->delay1 = card->delay1;
133571901Sscottl			sc->delay2 = card->delay2;
133671901Sscottl			break;
133771901Sscottl		}
133871901Sscottl	}
133971901Sscottl
1340167355Sariff	if (resource_int_value(device_get_name(dev), device_get_unit(dev),
1341167355Sariff	    "dac", &i) == 0) {
1342167355Sariff	    	if (i < 1)
1343167355Sariff			dacn = 1;
1344167355Sariff		else if (i > M3_PCHANS)
1345167355Sariff			dacn = M3_PCHANS;
1346167355Sariff		else
1347167355Sariff			dacn = i;
1348167355Sariff	} else
1349167355Sariff		dacn = M3_PCHANS;
1350167355Sariff
1351167355Sariff	adcn = M3_RCHANS;
1352167355Sariff
1353254306Sscottl	pci_enable_busmaster(dev);
135471901Sscottl
1355119690Sjhb	sc->regid = PCIR_BAR(0);
135671901Sscottl	sc->regtype = SYS_RES_MEMORY;
1357127135Snjl	sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid,
1358127135Snjl					 RF_ACTIVE);
135971901Sscottl	if (!sc->reg) {
136071901Sscottl		sc->regtype = SYS_RES_IOPORT;
1361127135Snjl		sc->reg = bus_alloc_resource_any(dev, sc->regtype, &sc->regid,
1362127135Snjl						 RF_ACTIVE);
136371901Sscottl	}
136471901Sscottl	if (!sc->reg) {
136571901Sscottl		device_printf(dev, "unable to allocate register space\n");
136671901Sscottl		goto bad;
136771901Sscottl	}
136871901Sscottl	sc->st = rman_get_bustag(sc->reg);
136971901Sscottl	sc->sh = rman_get_bushandle(sc->reg);
137071901Sscottl
137171901Sscottl	sc->irqid = 0;
1372127135Snjl	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
1373127135Snjl					 RF_ACTIVE | RF_SHAREABLE);
137471901Sscottl	if (!sc->irq) {
137571901Sscottl		device_printf(dev, "unable to allocate interrupt\n");
137671901Sscottl		goto bad;
137771901Sscottl	}
137871901Sscottl
1379146514Syongari	if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, m3_intr, sc, &sc->ih)) {
138071901Sscottl		device_printf(dev, "unable to setup interrupt\n");
138171901Sscottl		goto bad;
138271901Sscottl	}
138371901Sscottl
1384167355Sariff	sc->bufsz = pcm_getbuffersize(dev, M3_BUFSIZE_MIN, M3_BUFSIZE_DEFAULT,
1385146514Syongari	    M3_BUFSIZE_MAX);
138684731Sscottl
1387146514Syongari	if (bus_dma_tag_create(
1388166904Snetchild	    bus_get_dma_tag(dev),	/* parent */
1389146514Syongari	    2, 0,		/* alignment, boundary */
1390146514Syongari	    M3_MAXADDR,		/* lowaddr */
1391146514Syongari	    BUS_SPACE_MAXADDR,	/* highaddr */
1392146514Syongari	    NULL, NULL,		/* filtfunc, filtfuncarg */
1393146514Syongari	    sc->bufsz,		/* maxsize */
1394146514Syongari	    1,			/* nsegments */
1395146514Syongari	    0x3ffff,		/* maxsegz */
1396146514Syongari	    0,			/* flags */
1397146514Syongari	    NULL,		/* lockfunc */
1398146514Syongari	    NULL,		/* lockfuncarg */
1399146514Syongari	    &sc->parent_dmat) != 0) {
140071901Sscottl		device_printf(dev, "unable to create dma tag\n");
140171901Sscottl		goto bad;
140271901Sscottl	}
140371901Sscottl
1404146514Syongari	M3_LOCK(sc);
140571901Sscottl	m3_power(sc, 0); /* power up */
140671901Sscottl	/* init chip */
1407146514Syongari	i = m3_init(sc);
1408146514Syongari	M3_UNLOCK(sc);
1409146514Syongari	if (i == -1) {
141071901Sscottl		device_printf(dev, "unable to initialize the card\n");
141171901Sscottl		goto bad;
141271901Sscottl	}
141371901Sscottl
141471901Sscottl	/* create/init mixer */
141571901Sscottl	codec = AC97_CREATE(dev, sc, m3_codec);
141671901Sscottl	if (codec == NULL) {
141771901Sscottl		device_printf(dev, "ac97_create error\n");
141871901Sscottl		goto bad;
141971901Sscottl	}
142071901Sscottl	if (mixer_init(dev, ac97_getmixerclass(), codec)) {
142171901Sscottl		device_printf(dev, "mixer_init error\n");
142271901Sscottl		goto bad;
142371901Sscottl	}
142471901Sscottl
142598764Srobert	m3_enable_ints(sc);
142698764Srobert
1427167355Sariff	if (pcm_register(dev, sc, dacn, adcn)) {
142871901Sscottl		device_printf(dev, "pcm_register error\n");
142971901Sscottl		goto bad;
143071901Sscottl	}
1431167355Sariff	for (i=0 ; i<dacn ; i++) {
143271901Sscottl		if (pcm_addchan(dev, PCMDIR_PLAY, &m3_pch_class, sc)) {
143371901Sscottl			device_printf(dev, "pcm_addchan (play) error\n");
143471901Sscottl			goto bad;
143571901Sscottl		}
143671901Sscottl	}
1437167355Sariff	for (i=0 ; i<adcn ; i++) {
143871901Sscottl		if (pcm_addchan(dev, PCMDIR_REC, &m3_rch_class, sc)) {
143971901Sscottl			device_printf(dev, "pcm_addchan (rec) error\n");
144071901Sscottl			goto bad;
144171901Sscottl		}
144271901Sscottl	}
1443126695Smatk 	snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s",
1444146514Syongari	    (sc->regtype == SYS_RES_IOPORT)? "io" : "memory",
1445146514Syongari	    rman_get_start(sc->reg), rman_get_start(sc->irq),
1446146514Syongari	    PCM_KLDSTRING(snd_maestro3));
144771901Sscottl	if (pcm_setstatus(dev, status)) {
144871901Sscottl		device_printf(dev, "attach: pcm_setstatus error\n");
144971901Sscottl		goto bad;
145071901Sscottl	}
145184926Sscottl
145274763Scg	mixer_hwvol_init(dev);
145371901Sscottl
145471901Sscottl	/* Create the buffer for saving the card state during suspend */
145574797Scg	len = sizeof(u_int16_t) * (REV_B_CODE_MEMORY_LENGTH +
145671901Sscottl	    REV_B_DATA_MEMORY_LENGTH);
1457170873Sariff	sc->savemem = (u_int16_t*)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
145871901Sscottl
145971901Sscottl	return 0;
146071901Sscottl
146171901Sscottl bad:
1462146514Syongari	if (codec)
146371901Sscottl		ac97_destroy(codec);
1464146514Syongari	if (sc->ih)
146571901Sscottl		bus_teardown_intr(dev, sc->irq, sc->ih);
1466146514Syongari	if (sc->irq)
146771901Sscottl		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1468146514Syongari	if (sc->reg)
1469146514Syongari		bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
1470146514Syongari	if (sc->parent_dmat)
147171901Sscottl		bus_dma_tag_destroy(sc->parent_dmat);
1472146514Syongari	if (sc->sc_lock)
1473146514Syongari		snd_mtxfree(sc->sc_lock);
147471901Sscottl	free(sc, M_DEVBUF);
147571901Sscottl	return ENXIO;
147671901Sscottl}
147771901Sscottl
147871901Sscottlstatic int
147971901Sscottlm3_pci_detach(device_t dev)
148071901Sscottl{
148171901Sscottl	struct sc_info *sc = pcm_getdevinfo(dev);
148271901Sscottl	int r;
148371901Sscottl
148471901Sscottl	M3_DEBUG(CALL, ("m3_pci_detach\n"));
148571901Sscottl
148671901Sscottl	if ((r = pcm_unregister(dev)) != 0) {
148771901Sscottl		return r;
148871901Sscottl	}
1489146514Syongari
1490146514Syongari	M3_LOCK(sc);
149171901Sscottl	m3_uninit(sc); /* shutdown chip */
149271901Sscottl	m3_power(sc, 3); /* power off */
1493146514Syongari	M3_UNLOCK(sc);
149471901Sscottl
149571901Sscottl	bus_teardown_intr(dev, sc->irq, sc->ih);
149671901Sscottl	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1497146514Syongari	bus_release_resource(dev, sc->regtype, sc->regid, sc->reg);
149871901Sscottl	bus_dma_tag_destroy(sc->parent_dmat);
149971901Sscottl
150071901Sscottl	free(sc->savemem, M_DEVBUF);
1501146514Syongari	snd_mtxfree(sc->sc_lock);
150271901Sscottl	free(sc, M_DEVBUF);
150371901Sscottl	return 0;
150471901Sscottl}
150571901Sscottl
150671901Sscottlstatic int
150771901Sscottlm3_pci_suspend(device_t dev)
150871901Sscottl{
150971901Sscottl	struct sc_info *sc = pcm_getdevinfo(dev);
151071901Sscottl	int i, index = 0;
151171901Sscottl
151271901Sscottl        M3_DEBUG(CHANGE, ("m3_pci_suspend\n"));
151371901Sscottl
1514146514Syongari	M3_LOCK(sc);
151571901Sscottl	for (i=0 ; i<sc->pch_cnt ; i++) {
151671901Sscottl		if (sc->pch[i].active) {
1517146514Syongari			m3_pchan_trigger_locked(NULL, &sc->pch[i],
1518146514Syongari			    PCMTRIG_STOP);
151971901Sscottl		}
152071901Sscottl	}
152171901Sscottl	for (i=0 ; i<sc->rch_cnt ; i++) {
152271901Sscottl		if (sc->rch[i].active) {
1523146514Syongari			m3_rchan_trigger_locked(NULL, &sc->rch[i],
1524146514Syongari			    PCMTRIG_STOP);
152571901Sscottl		}
152671901Sscottl	}
152771901Sscottl	DELAY(10 * 1000); /* give things a chance to stop */
152871901Sscottl
152971901Sscottl	/* Disable interrupts */
153071901Sscottl	m3_wr_2(sc, HOST_INT_CTRL, 0);
153171901Sscottl	m3_wr_1(sc, ASSP_CONTROL_C, 0);
153271901Sscottl
153371901Sscottl	m3_assp_halt(sc);
153471901Sscottl
153571901Sscottl	/* Save the state of the ASSP */
153671901Sscottl	for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
1537102578Sscottl		sc->savemem[index++] = m3_rd_assp_code(sc, i);
153871901Sscottl	for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++)
1539102578Sscottl		sc->savemem[index++] = m3_rd_assp_data(sc, i);
154071901Sscottl
154171901Sscottl	/* Power down the card to D3 state */
154271901Sscottl	m3_power(sc, 3);
1543146514Syongari	M3_UNLOCK(sc);
154471901Sscottl
154571901Sscottl	return 0;
154671901Sscottl}
154771901Sscottl
154871901Sscottlstatic int
154971901Sscottlm3_pci_resume(device_t dev)
155071901Sscottl{
155171901Sscottl	struct sc_info *sc = pcm_getdevinfo(dev);
155271901Sscottl	int i, index = 0;
155371901Sscottl	u_int8_t reset_state;
155471901Sscottl
155571901Sscottl	M3_DEBUG(CHANGE, ("m3_pci_resume\n"));
155671901Sscottl
1557146514Syongari	M3_LOCK(sc);
155871901Sscottl	/* Power the card back to D0 */
155971901Sscottl	m3_power(sc, 0);
156071901Sscottl
156171901Sscottl	m3_config(sc);
156274797Scg
156371901Sscottl	reset_state = m3_assp_halt(sc);
156471901Sscottl
156587393Sguido	m3_codec_reset(sc);
156687393Sguido
156771901Sscottl	/* Restore the ASSP state */
156871901Sscottl	for (i = REV_B_CODE_MEMORY_BEGIN; i <= REV_B_CODE_MEMORY_END; i++)
1569102924Sscottl		m3_wr_assp_code(sc, i, sc->savemem[index++]);
157071901Sscottl	for (i = REV_B_DATA_MEMORY_BEGIN; i <= REV_B_DATA_MEMORY_END; i++)
1571102924Sscottl		m3_wr_assp_data(sc, i, sc->savemem[index++]);
157271901Sscottl
157371901Sscottl	/* Restart the DMA engine */
157471901Sscottl	m3_wr_assp_data(sc, KDATA_DMA_ACTIVE, 0);
157571901Sscottl
157671901Sscottl	/* [m3_assp_continue] */
157771901Sscottl	m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state | REGB_ENABLE_RESET);
157871901Sscottl
157971901Sscottl	m3_amp_enable(sc);
158071901Sscottl
158199586Srobert	m3_enable_ints(sc);
158299586Srobert
1583146514Syongari	M3_UNLOCK(sc); /* XXX */
158487393Sguido	if (mixer_reinit(dev) == -1) {
158587393Sguido		device_printf(dev, "unable to reinitialize the mixer\n");
1586146514Syongari		return (ENXIO);
158787393Sguido	}
1588146514Syongari	M3_LOCK(sc);
158987393Sguido
159071901Sscottl	/* Turn the channels back on */
159171901Sscottl	for (i=0 ; i<sc->pch_cnt ; i++) {
159271901Sscottl		if (sc->pch[i].active) {
1593146514Syongari			m3_pchan_trigger_locked(NULL, &sc->pch[i],
1594146514Syongari			    PCMTRIG_START);
159571901Sscottl		}
159671901Sscottl	}
159771901Sscottl	for (i=0 ; i<sc->rch_cnt ; i++) {
159871901Sscottl		if (sc->rch[i].active) {
1599146514Syongari			m3_rchan_trigger_locked(NULL, &sc->rch[i],
1600146514Syongari			    PCMTRIG_START);
160171901Sscottl		}
160271901Sscottl	}
160371901Sscottl
1604146514Syongari	M3_UNLOCK(sc);
160571901Sscottl	return 0;
160671901Sscottl}
160771901Sscottl
160871901Sscottlstatic int
160971901Sscottlm3_pci_shutdown(device_t dev)
161071901Sscottl{
161171901Sscottl	struct sc_info *sc = pcm_getdevinfo(dev);
161274797Scg
161371901Sscottl	M3_DEBUG(CALL, ("m3_pci_shutdown\n"));
161471901Sscottl
1615146514Syongari	M3_LOCK(sc);
161671901Sscottl	m3_power(sc, 3); /* power off */
1617146514Syongari	M3_UNLOCK(sc);
1618146514Syongari
161971901Sscottl	return 0;
162071901Sscottl}
162171901Sscottl
162271901Sscottlstatic u_int8_t
162371901Sscottlm3_assp_halt(struct sc_info *sc)
162471901Sscottl{
162571901Sscottl	u_int8_t data, reset_state;
162671901Sscottl
1627146514Syongari	M3_LOCK_ASSERT(sc);
1628146514Syongari
162971901Sscottl	data = m3_rd_1(sc, DSP_PORT_CONTROL_REG_B);
163071901Sscottl	reset_state = data & ~REGB_STOP_CLOCK; /* remember for continue */
163171901Sscottl        DELAY(10 * 1000);
163271901Sscottl	m3_wr_1(sc, DSP_PORT_CONTROL_REG_B, reset_state & ~REGB_ENABLE_RESET);
163371901Sscottl        DELAY(10 * 1000); /* necessary? */
163471901Sscottl
163571901Sscottl	return reset_state;
163671901Sscottl}
163771901Sscottl
163871901Sscottlstatic void
163971901Sscottlm3_config(struct sc_info *sc)
164071901Sscottl{
164184926Sscottl	u_int32_t data, hv_cfg;
164284926Sscottl	int hint;
164371901Sscottl
1644146514Syongari	M3_LOCK_ASSERT(sc);
1645150075Syongari
1646150075Syongari	M3_UNLOCK(sc);
164784926Sscottl	/*
164884926Sscottl	 * The volume buttons can be wired up via two different sets of pins.
164984926Sscottl	 * This presents a problem since we can't tell which way it's
165084926Sscottl	 * configured.  Allow the user to set a hint in order to twiddle
165184926Sscottl	 * the proper bits.
165284926Sscottl	 */
165384926Sscottl	if (resource_int_value(device_get_name(sc->dev),
165484926Sscottl	                       device_get_unit(sc->dev),
165584926Sscottl			       "hwvol_config", &hint) == 0)
165684926Sscottl		hv_cfg = (hint > 0) ? HV_BUTTON_FROM_GD : 0;
165784926Sscottl	else
165884926Sscottl		hv_cfg = HV_BUTTON_FROM_GD;
1659150075Syongari	M3_LOCK(sc);
166084926Sscottl
166171901Sscottl	data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4);
166298961Sscottl	data &= ~HV_BUTTON_FROM_GD;
166384926Sscottl	data |= REDUCED_DEBOUNCE | HV_CTRL_ENABLE | hv_cfg;
166471901Sscottl	data |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
166571901Sscottl	pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4);
166671901Sscottl
166771901Sscottl	m3_wr_1(sc, ASSP_CONTROL_B, RESET_ASSP);
166871901Sscottl	data = pci_read_config(sc->dev, PCI_ALLEGRO_CONFIG, 4);
166971901Sscottl	data &= ~INT_CLK_SELECT;
167071901Sscottl	if (sc->which == ESS_MAESTRO3) {
167171901Sscottl		data &= ~INT_CLK_MULT_ENABLE;
167271901Sscottl		data |= INT_CLK_SRC_NOT_PCI;
167371901Sscottl	}
167471901Sscottl	data &= ~(CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2);
167571901Sscottl	pci_write_config(sc->dev, PCI_ALLEGRO_CONFIG, data, 4);
167671901Sscottl
167771901Sscottl	if (sc->which == ESS_ALLEGRO_1) {
167871901Sscottl		data = pci_read_config(sc->dev, PCI_USER_CONFIG, 4);
167971901Sscottl		data |= IN_CLK_12MHZ_SELECT;
168071901Sscottl		pci_write_config(sc->dev, PCI_USER_CONFIG, data, 4);
168171901Sscottl	}
168271901Sscottl
168371901Sscottl	data = m3_rd_1(sc, ASSP_CONTROL_A);
168471901Sscottl	data &= ~(DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
168571901Sscottl	data |= ASSP_CLK_49MHZ_SELECT; /*XXX assumes 49MHZ dsp XXX*/
168671901Sscottl	data |= ASSP_0_WS_ENABLE;
168771901Sscottl	m3_wr_1(sc, ASSP_CONTROL_A, data);
168871901Sscottl
168971901Sscottl	m3_wr_1(sc, ASSP_CONTROL_B, RUN_ASSP);
169071901Sscottl}
169171901Sscottl
169271901Sscottlstatic void
169371901Sscottlm3_enable_ints(struct sc_info *sc)
169471901Sscottl{
169571901Sscottl	u_int8_t data;
169671901Sscottl
169771901Sscottl	m3_wr_2(sc, HOST_INT_CTRL, ASSP_INT_ENABLE | HV_INT_ENABLE);
169871901Sscottl	data = m3_rd_1(sc, ASSP_CONTROL_C);
169971901Sscottl	m3_wr_1(sc, ASSP_CONTROL_C, data | ASSP_HOST_INT_ENABLE);
170071901Sscottl}
170171901Sscottl
170271901Sscottlstatic void
170371901Sscottlm3_amp_enable(struct sc_info *sc)
170471901Sscottl{
170571901Sscottl	u_int32_t gpo, polarity_port, polarity;
170671901Sscottl	u_int16_t data;
170771901Sscottl
1708146514Syongari	M3_LOCK_ASSERT(sc);
1709146514Syongari
171071901Sscottl	switch (sc->which) {
171171901Sscottl        case ESS_ALLEGRO_1:
171271901Sscottl                polarity_port = 0x1800;
171371901Sscottl                break;
171471901Sscottl	case ESS_MAESTRO3:
171571901Sscottl                polarity_port = 0x1100;
171671901Sscottl                break;
171771901Sscottl        default:
171871901Sscottl		panic("bad sc->which");
171971901Sscottl	}
172071901Sscottl	gpo = (polarity_port >> 8) & 0x0f;
172171901Sscottl	polarity = polarity_port >> 12;
172271901Sscottl	polarity = !polarity; /* enable */
172371901Sscottl	polarity = polarity << gpo;
172471901Sscottl	gpo = 1 << gpo;
172571901Sscottl	m3_wr_2(sc, GPIO_MASK, ~gpo);
172671901Sscottl	data = m3_rd_2(sc, GPIO_DIRECTION);
172771901Sscottl	m3_wr_2(sc, GPIO_DIRECTION, data | gpo);
172871901Sscottl	data = GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity;
172971901Sscottl	m3_wr_2(sc, GPIO_DATA, data);
173071901Sscottl	m3_wr_2(sc, GPIO_MASK, ~0);
173171901Sscottl}
173271901Sscottl
173371901Sscottlstatic void
173471901Sscottlm3_codec_reset(struct sc_info *sc)
173571901Sscottl{
173671901Sscottl	u_int16_t data, dir;
173771901Sscottl	int retry = 0;
173871901Sscottl
1739146514Syongari	M3_LOCK_ASSERT(sc);
174071901Sscottl	do {
174171901Sscottl		data = m3_rd_2(sc, GPIO_DIRECTION);
174271901Sscottl		dir = data | 0x10; /* assuming pci bus master? */
174371901Sscottl
174471901Sscottl		/* [[remote_codec_config]] */
174571901Sscottl		data = m3_rd_2(sc, RING_BUS_CTRL_B);
174671901Sscottl		m3_wr_2(sc, RING_BUS_CTRL_B, data & ~SECOND_CODEC_ID_MASK);
174771901Sscottl		data = m3_rd_2(sc, SDO_OUT_DEST_CTRL);
174871901Sscottl		m3_wr_2(sc, SDO_OUT_DEST_CTRL, data & ~COMMAND_ADDR_OUT);
174971901Sscottl		data = m3_rd_2(sc, SDO_IN_DEST_CTRL);
175071901Sscottl		m3_wr_2(sc, SDO_IN_DEST_CTRL, data & ~STATUS_ADDR_IN);
175174797Scg
175271901Sscottl		m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE);
175371901Sscottl		DELAY(20);
175474797Scg
175571901Sscottl		m3_wr_2(sc, GPIO_DIRECTION, dir & ~GPO_PRIMARY_AC97);
175671901Sscottl		m3_wr_2(sc, GPIO_MASK, ~GPO_PRIMARY_AC97);
175771901Sscottl		m3_wr_2(sc, GPIO_DATA, 0);
175871901Sscottl		m3_wr_2(sc, GPIO_DIRECTION, dir | GPO_PRIMARY_AC97);
175971901Sscottl		DELAY(sc->delay1 * 1000); /*delay1 (ALLEGRO:50, MAESTRO3:20)*/
176071901Sscottl		m3_wr_2(sc, GPIO_DATA, GPO_PRIMARY_AC97);
176171901Sscottl		DELAY(5);
176274797Scg		m3_wr_2(sc, RING_BUS_CTRL_A, IO_SRAM_ENABLE |
176371901Sscottl		    SERIAL_AC_LINK_ENABLE);
176471901Sscottl		m3_wr_2(sc, GPIO_MASK, ~0);
176571901Sscottl		DELAY(sc->delay2 * 1000); /*delay2 (ALLEGRO:800, MAESTRO3:500)*/
176674797Scg
176771901Sscottl		/* [[try read vendor]] */
176871901Sscottl		data = m3_rdcd(NULL, sc, 0x7c);
176971901Sscottl		if ((data == 0) || (data == 0xffff)) {
177071901Sscottl			retry++;
177171901Sscottl			if (retry > 3) {
177271901Sscottl				device_printf(sc->dev, "Codec reset failed\n");
177371901Sscottl				break;
177471901Sscottl			}
177571901Sscottl			device_printf(sc->dev, "Codec reset retry\n");
177671901Sscottl		} else retry = 0;
177771901Sscottl	} while (retry);
177871901Sscottl}
177971901Sscottl
178071901Sscottlstatic device_method_t m3_methods[] = {
178171901Sscottl	DEVMETHOD(device_probe,		m3_pci_probe),
178271901Sscottl	DEVMETHOD(device_attach,	m3_pci_attach),
178371901Sscottl	DEVMETHOD(device_detach,	m3_pci_detach),
178471901Sscottl	DEVMETHOD(device_suspend,       m3_pci_suspend),
178571901Sscottl	DEVMETHOD(device_resume,        m3_pci_resume),
178671901Sscottl	DEVMETHOD(device_shutdown,      m3_pci_shutdown),
178771901Sscottl	{ 0, 0 }
178871901Sscottl};
178971901Sscottl
179071901Sscottlstatic driver_t m3_driver = {
179171901Sscottl	"pcm",
179271901Sscottl	m3_methods,
179382180Scg	PCM_SOFTC_SIZE,
179471901Sscottl};
179571901Sscottl
179671901SscottlDRIVER_MODULE(snd_maestro3, pci, m3_driver, pcm_devclass, 0, 0);
1797132236StanimuraMODULE_DEPEND(snd_maestro3, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
179871901SscottlMODULE_VERSION(snd_maestro3, 1);
1799