xref: /freebsd/sys/dev/sound/pci/emu10kx.c (revision 70e0bbed)
1d056fa04SAlexander Leidinger /*-
2d056fa04SAlexander Leidinger  * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3b28624fdSAriff Abdullah  * Copyright (c) 2003-2007 Yuriy Tsibizov <yuriy.tsibizov@gfk.ru>
4d056fa04SAlexander Leidinger  * All rights reserved.
5d056fa04SAlexander Leidinger  *
6d056fa04SAlexander Leidinger  * Redistribution and use in source and binary forms, with or without
7d056fa04SAlexander Leidinger  * modification, are permitted provided that the following conditions
8d056fa04SAlexander Leidinger  * are met:
9d056fa04SAlexander Leidinger  * 1. Redistributions of source code must retain the above copyright
10d056fa04SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer.
11d056fa04SAlexander Leidinger  * 2. Redistributions in binary form must reproduce the above copyright
12d056fa04SAlexander Leidinger  *    notice, this list of conditions and the following disclaimer in the
13d056fa04SAlexander Leidinger  *    documentation and/or other materials provided with the distribution.
14d056fa04SAlexander Leidinger  *
15d056fa04SAlexander Leidinger  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d056fa04SAlexander Leidinger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d056fa04SAlexander Leidinger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d056fa04SAlexander Leidinger  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d056fa04SAlexander Leidinger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d056fa04SAlexander Leidinger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d056fa04SAlexander Leidinger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d056fa04SAlexander Leidinger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
23d056fa04SAlexander Leidinger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d056fa04SAlexander Leidinger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d056fa04SAlexander Leidinger  * SUCH DAMAGE.
26d056fa04SAlexander Leidinger  *
27d056fa04SAlexander Leidinger  * $FreeBSD$
28d056fa04SAlexander Leidinger  */
29d056fa04SAlexander Leidinger 
30d056fa04SAlexander Leidinger #include <sys/param.h>
31d056fa04SAlexander Leidinger #include <sys/types.h>
32d056fa04SAlexander Leidinger #include <sys/bus.h>
33d056fa04SAlexander Leidinger #include <machine/bus.h>
34d056fa04SAlexander Leidinger #include <sys/rman.h>
35d056fa04SAlexander Leidinger #include <sys/systm.h>
36d056fa04SAlexander Leidinger #include <sys/sbuf.h>
37d056fa04SAlexander Leidinger #include <sys/queue.h>
38d056fa04SAlexander Leidinger #include <sys/lock.h>
39d056fa04SAlexander Leidinger #include <sys/mutex.h>
40d056fa04SAlexander Leidinger #include <sys/sysctl.h>
41b28624fdSAriff Abdullah #include <sys/kdb.h>
42d056fa04SAlexander Leidinger 
43d056fa04SAlexander Leidinger #include <dev/pci/pcireg.h>
44d056fa04SAlexander Leidinger #include <dev/pci/pcivar.h>
45d056fa04SAlexander Leidinger 
46d056fa04SAlexander Leidinger #include <machine/clock.h>	/* for DELAY */
47d056fa04SAlexander Leidinger 
4890da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
4990da2b28SAriff Abdullah #include "opt_snd.h"
5090da2b28SAriff Abdullah #endif
5190da2b28SAriff Abdullah 
52d056fa04SAlexander Leidinger #include <dev/sound/chip.h>
53d056fa04SAlexander Leidinger #include <dev/sound/pcm/sound.h>
54d056fa04SAlexander Leidinger #include <dev/sound/pcm/ac97.h>
55d056fa04SAlexander Leidinger 
5670e0bbedSPedro F. Giffuni #include <dev/sound/pci/emuxkireg.h>
57d056fa04SAlexander Leidinger #include <dev/sound/pci/emu10kx.h>
58d056fa04SAlexander Leidinger 
59d056fa04SAlexander Leidinger /* hw flags */
60d056fa04SAlexander Leidinger #define	HAS_51		0x0001
61d056fa04SAlexander Leidinger #define	HAS_71		0x0002
62d056fa04SAlexander Leidinger #define	HAS_AC97	0x0004
63d056fa04SAlexander Leidinger 
64d056fa04SAlexander Leidinger #define	IS_EMU10K1	0x0008
65d056fa04SAlexander Leidinger #define	IS_EMU10K2	0x0010
66d056fa04SAlexander Leidinger #define	IS_CA0102	0x0020
67d056fa04SAlexander Leidinger #define	IS_CA0108	0x0040
68d056fa04SAlexander Leidinger #define	IS_UNKNOWN	0x0080
69d056fa04SAlexander Leidinger 
70d056fa04SAlexander Leidinger #define	BROKEN_DIGITAL	0x0100
71d056fa04SAlexander Leidinger #define	DIGITAL_ONLY	0x0200
72d056fa04SAlexander Leidinger 
73d056fa04SAlexander Leidinger #define	IS_CARDBUS	0x0400
74d056fa04SAlexander Leidinger 
75d056fa04SAlexander Leidinger #define	MODE_ANALOG	1
76d056fa04SAlexander Leidinger #define	MODE_DIGITAL	2
77d056fa04SAlexander Leidinger #define	SPDIF_MODE_PCM	1
78d056fa04SAlexander Leidinger #define	SPDIF_MODE_AC3	2
79d056fa04SAlexander Leidinger 
80d056fa04SAlexander Leidinger #define	MACS	0x0
81d056fa04SAlexander Leidinger #define	MACS1	0x1
82d056fa04SAlexander Leidinger #define	MACW	0x2
83d056fa04SAlexander Leidinger #define	MACW1	0x3
84d056fa04SAlexander Leidinger #define	MACINTS	0x4
85d056fa04SAlexander Leidinger #define	MACINTW	0x5
86d056fa04SAlexander Leidinger #define	ACC3	0x6
87d056fa04SAlexander Leidinger #define	MACMV	0x7
88d056fa04SAlexander Leidinger #define	ANDXOR	0x8
89d056fa04SAlexander Leidinger #define	TSTNEG	0x9
90d056fa04SAlexander Leidinger #define	LIMIT	0xA
91d056fa04SAlexander Leidinger #define	LIMIT1	0xB
92d056fa04SAlexander Leidinger #define	LOG	0xC
93d056fa04SAlexander Leidinger #define	EXP	0xD
94d056fa04SAlexander Leidinger #define	INTERP	0xE
95d056fa04SAlexander Leidinger #define	SKIP	0xF
96d056fa04SAlexander Leidinger 
97d056fa04SAlexander Leidinger #define	GPR(i)	(sc->gpr_base+(i))
98d056fa04SAlexander Leidinger #define	INP(i)	(sc->input_base+(i))
99d056fa04SAlexander Leidinger #define	OUTP(i)	(sc->output_base+(i))
100d056fa04SAlexander Leidinger #define	FX(i)	(i)
101d056fa04SAlexander Leidinger #define	FX2(i)	(sc->efxc_base+(i))
102d056fa04SAlexander Leidinger #define	DSP_CONST(i) (sc->dsp_zero+(i))
103d056fa04SAlexander Leidinger 
104d056fa04SAlexander Leidinger #define	COND_NORMALIZED	DSP_CONST(0x1)
105d056fa04SAlexander Leidinger #define	COND_BORROW	DSP_CONST(0x2)
106d056fa04SAlexander Leidinger #define	COND_MINUS	DSP_CONST(0x3)
107d056fa04SAlexander Leidinger #define	COND_LESS_ZERO	DSP_CONST(0x4)
108d056fa04SAlexander Leidinger #define	COND_EQ_ZERO	DSP_CONST(0x5)
109d056fa04SAlexander Leidinger #define	COND_SATURATION	DSP_CONST(0x6)
110d056fa04SAlexander Leidinger #define	COND_NEQ_ZERO	DSP_CONST(0x8)
111d056fa04SAlexander Leidinger 
112b28624fdSAriff Abdullah #define	DSP_ACCUM	DSP_CONST(0x16)
113b28624fdSAriff Abdullah #define	DSP_CCR		DSP_CONST(0x17)
114b28624fdSAriff Abdullah 
115d056fa04SAlexander Leidinger /* Live! Inputs */
116d056fa04SAlexander Leidinger #define	IN_AC97_L 	0x00
117d056fa04SAlexander Leidinger #define	IN_AC97_R 	0x01
118d056fa04SAlexander Leidinger #define	IN_AC97		IN_AC97_L
119d056fa04SAlexander Leidinger #define	IN_SPDIF_CD_L	0x02
120d056fa04SAlexander Leidinger #define	IN_SPDIF_CD_R	0x03
121d056fa04SAlexander Leidinger #define	IN_SPDIF_CD	IN_SPDIF_CD_L
122d056fa04SAlexander Leidinger #define	IN_ZOOM_L 	0x04
123d056fa04SAlexander Leidinger #define	IN_ZOOM_R 	0x05
124d056fa04SAlexander Leidinger #define	IN_ZOOM		IN_ZOOM_L
125d056fa04SAlexander Leidinger #define	IN_TOSLINK_L	0x06
126d056fa04SAlexander Leidinger #define	IN_TOSLINK_R	0x07
127d056fa04SAlexander Leidinger #define	IN_TOSLINK	IN_TOSLINK_L
128d056fa04SAlexander Leidinger #define	IN_LINE1_L	0x08
129d056fa04SAlexander Leidinger #define	IN_LINE1_R	0x09
130d056fa04SAlexander Leidinger #define	IN_LINE1	IN_LINE1_L
131d056fa04SAlexander Leidinger #define	IN_COAX_SPDIF_L	0x0a
132d056fa04SAlexander Leidinger #define	IN_COAX_SPDIF_R	0x0b
133d056fa04SAlexander Leidinger #define	IN_COAX_SPDIF	IN_COAX_SPDIF_L
134d056fa04SAlexander Leidinger #define	IN_LINE2_L	0x0c
135d056fa04SAlexander Leidinger #define	IN_LINE2_R	0x0d
136d056fa04SAlexander Leidinger #define	IN_LINE2	IN_LINE2_L
137d056fa04SAlexander Leidinger #define	IN_0E		0x0e
138d056fa04SAlexander Leidinger #define	IN_0F		0x0f
139d056fa04SAlexander Leidinger 
140d056fa04SAlexander Leidinger /* Outputs */
141d056fa04SAlexander Leidinger #define	OUT_AC97_L	0x00
142d056fa04SAlexander Leidinger #define	OUT_AC97_R	0x01
143d056fa04SAlexander Leidinger #define	OUT_AC97	OUT_AC97_L
144d056fa04SAlexander Leidinger #define	OUT_A_FRONT	OUT_AC97
145d056fa04SAlexander Leidinger #define	OUT_TOSLINK_L 	0x02
146d056fa04SAlexander Leidinger #define	OUT_TOSLINK_R 	0x03
147d056fa04SAlexander Leidinger #define	OUT_TOSLINK	OUT_TOSLINK_L
148d056fa04SAlexander Leidinger #define	OUT_D_CENTER	0x04
149d056fa04SAlexander Leidinger #define	OUT_D_SUB	0x05
150d056fa04SAlexander Leidinger #define	OUT_HEADPHONE_L	0x06
151d056fa04SAlexander Leidinger #define	OUT_HEADPHONE_R	0x07
152d056fa04SAlexander Leidinger #define	OUT_HEADPHONE	OUT_HEADPHONE_L
153d056fa04SAlexander Leidinger #define	OUT_REAR_L	0x08
154d056fa04SAlexander Leidinger #define	OUT_REAR_R	0x09
155d056fa04SAlexander Leidinger #define	OUT_REAR	OUT_REAR_L
156d056fa04SAlexander Leidinger #define	OUT_ADC_REC_L 	0x0a
157d056fa04SAlexander Leidinger #define	OUT_ADC_REC_R	0x0b
158d056fa04SAlexander Leidinger #define	OUT_ADC_REC	OUT_ADC_REC_L
159d056fa04SAlexander Leidinger #define	OUT_MIC_CAP	0x0c
160f856af04SAlexander Leidinger 
161f856af04SAlexander Leidinger /* Live! 5.1 Digital, non-standart 5.1 (center & sub) outputs */
162d056fa04SAlexander Leidinger #define	OUT_A_CENTER	0x11
163d056fa04SAlexander Leidinger #define	OUT_A_SUB	0x12
164d056fa04SAlexander Leidinger 
165d056fa04SAlexander Leidinger /* Audigy Inputs */
166d056fa04SAlexander Leidinger #define	A_IN_AC97_L	0x00
167d056fa04SAlexander Leidinger #define	A_IN_AC97_R	0x01
168d056fa04SAlexander Leidinger #define	A_IN_AC97	A_IN_AC97_L
169d056fa04SAlexander Leidinger #define	A_IN_SPDIF_CD_L	0x02
170d056fa04SAlexander Leidinger #define	A_IN_SPDIF_CD_R	0x03
171d056fa04SAlexander Leidinger #define	A_IN_SPDIF_CD	A_IN_SPDIF_CD_L
172d056fa04SAlexander Leidinger #define	A_IN_O_SPDIF_L	0x04
173d056fa04SAlexander Leidinger #define	A_IN_O_SPDIF_R	0x05
174d056fa04SAlexander Leidinger #define	A_IN_O_SPDIF	A_IN_O_SPDIF_L
175d056fa04SAlexander Leidinger #define	A_IN_LINE2_L	0x08
176d056fa04SAlexander Leidinger #define	A_IN_LINE2_R	0x09
177d056fa04SAlexander Leidinger #define	A_IN_LINE2	A_IN_LINE2_L
178d056fa04SAlexander Leidinger #define	A_IN_R_SPDIF_L	0x0a
179d056fa04SAlexander Leidinger #define	A_IN_R_SPDIF_R	0x0b
180d056fa04SAlexander Leidinger #define	A_IN_R_SPDIF	A_IN_R_SPDIF_L
181d056fa04SAlexander Leidinger #define	A_IN_AUX2_L	0x0c
182d056fa04SAlexander Leidinger #define	A_IN_AUX2_R	0x0d
183d056fa04SAlexander Leidinger #define	A_IN_AUX2	A_IN_AUX2_L
184d056fa04SAlexander Leidinger 
18570e0bbedSPedro F. Giffuni /* Audigy Outputs */
186d056fa04SAlexander Leidinger #define	A_OUT_D_FRONT_L	0x00
187d056fa04SAlexander Leidinger #define	A_OUT_D_FRONT_R	0x01
188d056fa04SAlexander Leidinger #define	A_OUT_D_FRONT	A_OUT_D_FRONT_L
189d056fa04SAlexander Leidinger #define	A_OUT_D_CENTER	0x02
190d056fa04SAlexander Leidinger #define	A_OUT_D_SUB	0x03
191d056fa04SAlexander Leidinger #define	A_OUT_D_SIDE_L	0x04
192d056fa04SAlexander Leidinger #define	A_OUT_D_SIDE_R	0x05
193d056fa04SAlexander Leidinger #define	A_OUT_D_SIDE	A_OUT_D_SIDE_L
194d056fa04SAlexander Leidinger #define	A_OUT_D_REAR_L	0x06
195d056fa04SAlexander Leidinger #define	A_OUT_D_REAR_R	0x07
196d056fa04SAlexander Leidinger #define	A_OUT_D_REAR	A_OUT_D_REAR_L
197d056fa04SAlexander Leidinger 
198d056fa04SAlexander Leidinger /* on Audigy Platinum only */
199d056fa04SAlexander Leidinger #define	A_OUT_HPHONE_L	0x04
200d056fa04SAlexander Leidinger #define	A_OUT_HPHONE_R	0x05
201d056fa04SAlexander Leidinger #define	A_OUT_HPHONE	A_OUT_HPHONE_L
202d056fa04SAlexander Leidinger 
203d056fa04SAlexander Leidinger #define	A_OUT_A_FRONT_L	0x08
204d056fa04SAlexander Leidinger #define	A_OUT_A_FRONT_R	0x09
205d056fa04SAlexander Leidinger #define	A_OUT_A_FRONT	A_OUT_A_FRONT_L
206d056fa04SAlexander Leidinger #define	A_OUT_A_CENTER	0x0a
207d056fa04SAlexander Leidinger #define	A_OUT_A_SUB	0x0b
208d056fa04SAlexander Leidinger #define	A_OUT_A_SIDE_L	0x0c
209d056fa04SAlexander Leidinger #define	A_OUT_A_SIDE_R	0x0d
210d056fa04SAlexander Leidinger #define	A_OUT_A_SIDE	A_OUT_A_SIDE_L
211d056fa04SAlexander Leidinger #define	A_OUT_A_REAR_L	0x0e
212d056fa04SAlexander Leidinger #define	A_OUT_A_REAR_R	0x0f
213d056fa04SAlexander Leidinger #define	A_OUT_A_REAR	A_OUT_A_REAR_L
214d056fa04SAlexander Leidinger #define	A_OUT_AC97_L	0x10
215d056fa04SAlexander Leidinger #define	A_OUT_AC97_R	0x11
216d056fa04SAlexander Leidinger #define	A_OUT_AC97	A_OUT_AC97_L
217d056fa04SAlexander Leidinger #define	A_OUT_ADC_REC_L	0x16
218d056fa04SAlexander Leidinger #define	A_OUT_ADC_REC_R	0x17
219d056fa04SAlexander Leidinger #define	A_OUT_ADC_REC	A_OUT_ADC_REC_L
220d056fa04SAlexander Leidinger 
22170e0bbedSPedro F. Giffuni #define EMU_DATA2	0x24
22270e0bbedSPedro F. Giffuni #define EMU_IPR2	0x28
22370e0bbedSPedro F. Giffuni #define EMU_INTE2	0x2c
22470e0bbedSPedro F. Giffuni #define EMU_IPR3	0x38
22570e0bbedSPedro F. Giffuni #define EMU_INTE3	0x3c
22670e0bbedSPedro F. Giffuni 
22770e0bbedSPedro F. Giffuni #define EMU_A2_SRCSel		0x60
22870e0bbedSPedro F. Giffuni #define EMU_A2_SRCMULTI_ENABLE	0x6e
22970e0bbedSPedro F. Giffuni 
23070e0bbedSPedro F. Giffuni #define EMU_A_I2S_CAPTURE_96000	0x00000400
23170e0bbedSPedro F. Giffuni 
23270e0bbedSPedro F. Giffuni #define EMU_A2_MIXER_I2S_ENABLE           0x7B
23370e0bbedSPedro F. Giffuni #define EMU_A2_MIXER_SPDIF_ENABLE         0x7A
234d056fa04SAlexander Leidinger 
235d056fa04SAlexander Leidinger #define	C_FRONT_L	0
236d056fa04SAlexander Leidinger #define	C_FRONT_R	1
237d056fa04SAlexander Leidinger #define	C_REC_L		2
238d056fa04SAlexander Leidinger #define	C_REC_R		3
239d056fa04SAlexander Leidinger #define	C_REAR_L	4
240d056fa04SAlexander Leidinger #define	C_REAR_R	5
241d056fa04SAlexander Leidinger #define	C_CENTER	6
242d056fa04SAlexander Leidinger #define	C_SUB		7
243d056fa04SAlexander Leidinger #define	C_SIDE_L	8
244d056fa04SAlexander Leidinger #define	C_SIDE_R	9
245d056fa04SAlexander Leidinger #define	NUM_CACHES	10
246d056fa04SAlexander Leidinger 
247b28624fdSAriff Abdullah #define	CDSPDIFMUTE	0
248b28624fdSAriff Abdullah #define	ANALOGMUTE	1
249b28624fdSAriff Abdullah #define	NUM_MUTE	2
250f856af04SAlexander Leidinger 
251d056fa04SAlexander Leidinger #define	EMU_MAX_GPR	512
252d056fa04SAlexander Leidinger #define	EMU_MAX_IRQ_CONSUMERS 32
253d056fa04SAlexander Leidinger 
254d056fa04SAlexander Leidinger struct emu_voice {
255d056fa04SAlexander Leidinger 	int	vnum;
256feaa7fe1SAlexander Leidinger 	unsigned int	b16:1, stereo:1, busy:1, running:1, ismaster:1;
257d056fa04SAlexander Leidinger 	int	speed;
258d056fa04SAlexander Leidinger 	int	start;
259d056fa04SAlexander Leidinger 	int	end;
260d056fa04SAlexander Leidinger 	int	vol;
261d056fa04SAlexander Leidinger 	uint32_t buf;
262d056fa04SAlexander Leidinger 	void	*vbuf;
263d056fa04SAlexander Leidinger 	struct emu_voice *slave;
264d056fa04SAlexander Leidinger 	uint32_t sa;
265d056fa04SAlexander Leidinger 	uint32_t ea;
266b28624fdSAriff Abdullah 	uint32_t routing[8];
267b28624fdSAriff Abdullah 	uint32_t amounts[8];
268d056fa04SAlexander Leidinger };
269d056fa04SAlexander Leidinger 
270d056fa04SAlexander Leidinger struct emu_memblk {
271d056fa04SAlexander Leidinger 	SLIST_ENTRY(emu_memblk)	link;
272d056fa04SAlexander Leidinger 	void		*buf;
273d056fa04SAlexander Leidinger 	char		owner[16];
274d056fa04SAlexander Leidinger 	bus_addr_t	buf_addr;
275d056fa04SAlexander Leidinger 	uint32_t	pte_start, pte_size;
276d056fa04SAlexander Leidinger };
277d056fa04SAlexander Leidinger 
278d056fa04SAlexander Leidinger struct emu_mem {
279e4c87b14SAlexander Leidinger 	uint8_t		bmap[EMU_MAXPAGES / 8];
280d056fa04SAlexander Leidinger 	uint32_t	*ptb_pages;
281d056fa04SAlexander Leidinger 	void		*silent_page;
282d056fa04SAlexander Leidinger 	bus_addr_t	silent_page_addr;
283d056fa04SAlexander Leidinger 	bus_addr_t	ptb_pages_addr;
284d056fa04SAlexander Leidinger 	bus_dma_tag_t	dmat;
285b28624fdSAriff Abdullah 	struct emu_sc_info *card;
286d056fa04SAlexander Leidinger 	SLIST_HEAD(, emu_memblk) blocks;
287d056fa04SAlexander Leidinger };
288d056fa04SAlexander Leidinger 
289d056fa04SAlexander Leidinger /* rm */
290d056fa04SAlexander Leidinger struct emu_rm {
291d056fa04SAlexander Leidinger 	struct emu_sc_info *card;
292d056fa04SAlexander Leidinger 	struct mtx	gpr_lock;
293d056fa04SAlexander Leidinger 	signed int	allocmap[EMU_MAX_GPR];
294d056fa04SAlexander Leidinger 	int		num_gprs;
295d056fa04SAlexander Leidinger 	int		last_free_gpr;
296d056fa04SAlexander Leidinger 	int 		num_used;
297d056fa04SAlexander Leidinger };
298d056fa04SAlexander Leidinger 
299d056fa04SAlexander Leidinger struct emu_intr_handler {
300d056fa04SAlexander Leidinger 	void*		softc;
301d056fa04SAlexander Leidinger 	uint32_t	intr_mask;
302d056fa04SAlexander Leidinger 	uint32_t	inte_mask;
303d056fa04SAlexander Leidinger 	uint32_t(*irq_func) (void *softc, uint32_t irq);
304d056fa04SAlexander Leidinger };
305d056fa04SAlexander Leidinger 
306d056fa04SAlexander Leidinger struct emu_sc_info {
307d056fa04SAlexander Leidinger 	struct mtx	lock;
308d056fa04SAlexander Leidinger 	struct mtx	rw;		/* Hardware exclusive access lock */
309d056fa04SAlexander Leidinger 
310d056fa04SAlexander Leidinger 	/* Hardware and subdevices */
311d056fa04SAlexander Leidinger 	device_t	dev;
312f856af04SAlexander Leidinger 	device_t	pcm[RT_COUNT];
313d056fa04SAlexander Leidinger 	device_t	midi[2];
314d056fa04SAlexander Leidinger 	uint32_t	type;
315d056fa04SAlexander Leidinger 	uint32_t	rev;
316d056fa04SAlexander Leidinger 
317d056fa04SAlexander Leidinger 	bus_space_tag_t	st;
318d056fa04SAlexander Leidinger 	bus_space_handle_t sh;
319d056fa04SAlexander Leidinger 
320d056fa04SAlexander Leidinger 	struct cdev	*cdev;		/* /dev/emu10k character device */
321d056fa04SAlexander Leidinger 	struct mtx	emu10kx_lock;
322d056fa04SAlexander Leidinger 	int		emu10kx_isopen;
323d056fa04SAlexander Leidinger 	struct sbuf	emu10kx_sbuf;
324d056fa04SAlexander Leidinger 	int		emu10kx_bufptr;
325d056fa04SAlexander Leidinger 
326d056fa04SAlexander Leidinger 
327d056fa04SAlexander Leidinger 	/* Resources */
328d056fa04SAlexander Leidinger 	struct resource	*reg;
329d056fa04SAlexander Leidinger 	struct resource	*irq;
330d056fa04SAlexander Leidinger 	void 		*ih;
331d056fa04SAlexander Leidinger 
332d056fa04SAlexander Leidinger 	/* IRQ handlers */
333d056fa04SAlexander Leidinger 	struct emu_intr_handler ihandler[EMU_MAX_IRQ_CONSUMERS];
334d056fa04SAlexander Leidinger 
335d056fa04SAlexander Leidinger 	/* Card HW configuration */
336b28624fdSAriff Abdullah 	unsigned int	mode;	/* analog / digital */
337d056fa04SAlexander Leidinger 	unsigned int	mchannel_fx;
338d056fa04SAlexander Leidinger 	unsigned int	dsp_zero;
339d056fa04SAlexander Leidinger 	unsigned int	code_base;
340d056fa04SAlexander Leidinger 	unsigned int	code_size;
341d056fa04SAlexander Leidinger 	unsigned int	gpr_base;
342d056fa04SAlexander Leidinger 	unsigned int	num_gprs;
343d056fa04SAlexander Leidinger 	unsigned int	input_base;
344d056fa04SAlexander Leidinger 	unsigned int	output_base;
345d056fa04SAlexander Leidinger 	unsigned int	efxc_base;
346d056fa04SAlexander Leidinger 	unsigned int	opcode_shift;
347d056fa04SAlexander Leidinger 	unsigned int	high_operand_shift;
348d056fa04SAlexander Leidinger 	unsigned int	address_mask;
349d056fa04SAlexander Leidinger 	uint32_t 	is_emu10k1:1, is_emu10k2, is_ca0102, is_ca0108:1,
350d056fa04SAlexander Leidinger 			has_ac97:1, has_51:1, has_71:1,
351b28624fdSAriff Abdullah 			enable_ir:1,
352d056fa04SAlexander Leidinger 			broken_digital:1, is_cardbus:1;
353d056fa04SAlexander Leidinger 
354b28624fdSAriff Abdullah 	signed int	mch_disabled, mch_rec, dbg_level;
355b28624fdSAriff Abdullah 	signed int 	num_inputs;
356d056fa04SAlexander Leidinger 	unsigned int 	num_outputs;
357d056fa04SAlexander Leidinger 	unsigned int 	num_fxbuses;
358d056fa04SAlexander Leidinger 	unsigned int 	routing_code_start;
359d056fa04SAlexander Leidinger 	unsigned int	routing_code_end;
360d056fa04SAlexander Leidinger 
361d056fa04SAlexander Leidinger 	/* HW resources */
362d056fa04SAlexander Leidinger 	struct emu_voice voice[NUM_G];			/* Hardware voices */
363d056fa04SAlexander Leidinger 	uint32_t	irq_mask[EMU_MAX_IRQ_CONSUMERS]; /* IRQ manager data */
364d056fa04SAlexander Leidinger 	int 		timer[EMU_MAX_IRQ_CONSUMERS];	/* timer */
365d056fa04SAlexander Leidinger 	int		timerinterval;
366d056fa04SAlexander Leidinger 	struct		emu_rm *rm;
367d056fa04SAlexander Leidinger 	struct		emu_mem mem;			/* memory */
368d056fa04SAlexander Leidinger 
369d056fa04SAlexander Leidinger 	/* Mixer */
370d056fa04SAlexander Leidinger 	int		mixer_gpr[NUM_MIXERS];
371d056fa04SAlexander Leidinger 	int		mixer_volcache[NUM_MIXERS];
372d056fa04SAlexander Leidinger 	int		cache_gpr[NUM_CACHES];
373b28624fdSAriff Abdullah 	int		dummy_gpr;
374b28624fdSAriff Abdullah 	int		mute_gpr[NUM_MUTE];
375d056fa04SAlexander Leidinger 	struct sysctl_ctx_list	*ctx;
376d056fa04SAlexander Leidinger 	struct sysctl_oid	*root;
377d056fa04SAlexander Leidinger };
378d056fa04SAlexander Leidinger 
379d056fa04SAlexander Leidinger static void	emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error);
380d056fa04SAlexander Leidinger static void*	emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr);
381d056fa04SAlexander Leidinger static void	emu_free(struct emu_mem *mem, void *dmabuf);
382d056fa04SAlexander Leidinger static void*	emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char * owner);
383d056fa04SAlexander Leidinger static int	emu_memfree(struct emu_mem *mem, void *membuf);
384d056fa04SAlexander Leidinger static int	emu_memstart(struct emu_mem *mem, void *membuf);
385d056fa04SAlexander Leidinger 
386d056fa04SAlexander Leidinger /* /dev */
387d056fa04SAlexander Leidinger static int	emu10kx_dev_init(struct emu_sc_info *sc);
388d056fa04SAlexander Leidinger static int	emu10kx_dev_uninit(struct emu_sc_info *sc);
389d056fa04SAlexander Leidinger static int	emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s);
390d056fa04SAlexander Leidinger 
391d056fa04SAlexander Leidinger static void	emumix_set_mode(struct emu_sc_info *sc, int mode);
392d056fa04SAlexander Leidinger static void	emumix_set_spdif_mode(struct emu_sc_info *sc, int mode);
393d056fa04SAlexander Leidinger static void	emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol);
394d056fa04SAlexander Leidinger static void	emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val);
395d056fa04SAlexander Leidinger static int	sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS);
396d056fa04SAlexander Leidinger 
397d056fa04SAlexander Leidinger static int	emu_rm_init(struct emu_sc_info *sc);
398d056fa04SAlexander Leidinger static int	emu_rm_uninit(struct emu_sc_info *sc);
399d056fa04SAlexander Leidinger static int	emu_rm_gpr_alloc(struct emu_rm *rm, int count);
400d056fa04SAlexander Leidinger 
401f856af04SAlexander Leidinger static unsigned int emu_getcard(device_t dev);
402d056fa04SAlexander Leidinger static uint32_t	emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size);
403d056fa04SAlexander Leidinger static void	emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size);
404d056fa04SAlexander Leidinger static void	emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data);
405d056fa04SAlexander Leidinger 
406d056fa04SAlexander Leidinger static void	emu_vstop(struct emu_sc_info *sc, char channel, int enable);
407d056fa04SAlexander Leidinger 
408d056fa04SAlexander Leidinger static void	emu_intr(void *p);
409d056fa04SAlexander Leidinger static void	emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data);
410d056fa04SAlexander Leidinger static void	emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc);
411d056fa04SAlexander Leidinger static void	emu_initefx(struct emu_sc_info *sc);
412d056fa04SAlexander Leidinger 
413d056fa04SAlexander Leidinger static int	emu_cardbus_init(struct emu_sc_info *sc);
41455837609SAriff Abdullah static int	emu_init(struct emu_sc_info *sc);
415d056fa04SAlexander Leidinger static int	emu_uninit(struct emu_sc_info *sc);
416d056fa04SAlexander Leidinger 
417d056fa04SAlexander Leidinger static int	emu_read_ivar(device_t bus __unused, device_t dev, int ivar_index, uintptr_t * result);
418d056fa04SAlexander Leidinger static int	emu_write_ivar(device_t bus __unused, device_t dev __unused,
419d056fa04SAlexander Leidinger     int ivar_index, uintptr_t value __unused);
420d056fa04SAlexander Leidinger 
421d056fa04SAlexander Leidinger static int	emu_pci_probe(device_t dev);
422d056fa04SAlexander Leidinger static int	emu_pci_attach(device_t dev);
423d056fa04SAlexander Leidinger static int	emu_pci_detach(device_t dev);
424d056fa04SAlexander Leidinger static int	emu_modevent(module_t mod __unused, int cmd, void *data __unused);
425d056fa04SAlexander Leidinger 
426b28624fdSAriff Abdullah #ifdef	SND_EMU10KX_DEBUG
427b28624fdSAriff Abdullah 
428b28624fdSAriff Abdullah #define EMU_MTX_DEBUG() do { 						\
429b28624fdSAriff Abdullah 		if (mtx_owned(&sc->rw)) {				\
430b28624fdSAriff Abdullah 		printf("RW owned in %s line %d for %s\n", __func__,	\
431b28624fdSAriff Abdullah 			__LINE__ , device_get_nameunit(sc->dev));	\
432b28624fdSAriff Abdullah 		printf("rw lock owned: %d\n", mtx_owned(&sc->rw));	\
433b28624fdSAriff Abdullah 		printf("rw lock: value %x thread %x\n",			\
434b28624fdSAriff Abdullah 			((&sc->rw)->mtx_lock & ~MTX_FLAGMASK), 		\
435b28624fdSAriff Abdullah 			(uintptr_t)curthread);				\
436b28624fdSAriff Abdullah 		printf("rw lock: recursed %d\n", mtx_recursed(&sc->rw));\
437b28624fdSAriff Abdullah 		db_show_mtx(&sc->rw);					\
438b28624fdSAriff Abdullah 		}							\
439b28624fdSAriff Abdullah 	} while (0)
440b28624fdSAriff Abdullah #else
441b28624fdSAriff Abdullah #define EMU_MTX_DEBUG() do { 						\
442b28624fdSAriff Abdullah 	} while (0)
443b28624fdSAriff Abdullah #endif
444b28624fdSAriff Abdullah 
445b28624fdSAriff Abdullah #define EMU_RWLOCK() do {		\
446b28624fdSAriff Abdullah 	EMU_MTX_DEBUG();		\
447b28624fdSAriff Abdullah 	mtx_lock(&(sc->rw));		\
448b28624fdSAriff Abdullah 	} while (0)
449b28624fdSAriff Abdullah 
450b28624fdSAriff Abdullah #define EMU_RWUNLOCK() do {		\
451b28624fdSAriff Abdullah 	mtx_unlock(&(sc->rw));		\
452b28624fdSAriff Abdullah 	EMU_MTX_DEBUG();		\
453b28624fdSAriff Abdullah 	} while (0)
454b28624fdSAriff Abdullah 
455d056fa04SAlexander Leidinger /* Supported cards */
456d056fa04SAlexander Leidinger struct emu_hwinfo {
457d056fa04SAlexander Leidinger 	uint16_t	vendor;
458d056fa04SAlexander Leidinger 	uint16_t	device;
459d056fa04SAlexander Leidinger 	uint16_t	subvendor;
460d056fa04SAlexander Leidinger 	uint16_t	subdevice;
461d056fa04SAlexander Leidinger 	char		SBcode[8];
462d056fa04SAlexander Leidinger 	char		desc[32];
463d056fa04SAlexander Leidinger 	int		flags;
464d056fa04SAlexander Leidinger };
465d056fa04SAlexander Leidinger 
466d056fa04SAlexander Leidinger static struct emu_hwinfo emu_cards[] = {
467f856af04SAlexander Leidinger 	{0xffff, 0xffff, 0xffff, 0xffff, "BADCRD", "Not a compatible card", 0},
468d056fa04SAlexander Leidinger 	/* 0x0020..0x002f 4.0 EMU10K1 cards */
469d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x0020, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
470d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x0021, "CT4620", "SBLive!", HAS_AC97 | IS_EMU10K1},
471d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x002f, "CT????", "SBLive! mainboard implementation", HAS_AC97 | IS_EMU10K1},
472d056fa04SAlexander Leidinger 
473d056fa04SAlexander Leidinger 	/* (range unknown) 5.1 EMU10K1 cards */
474d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x100a, "CT????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
475d056fa04SAlexander Leidinger 
476d056fa04SAlexander Leidinger 	/* 0x80??..0x805? 4.0 EMU10K1 cards */
477d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8022, "CT4780", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
478d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8023, "CT4790", "SB PCI512", HAS_AC97 | IS_EMU10K1},
479d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8024, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1},
480d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8025, "CT????", "SBLive! Mainboard Implementation", HAS_AC97 | IS_EMU10K1},
481d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8026, "CT4830", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
482d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8027, "CT4832", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
483d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8028, "CT4760", "SBLive! OEM version", HAS_AC97 | IS_EMU10K1},
484d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8031, "CT4831", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
485d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8040, "CT4760", "SBLive!", HAS_AC97 | IS_EMU10K1},
486d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8051, "CT4850", "SBLive! Value", HAS_AC97 | IS_EMU10K1},
487d056fa04SAlexander Leidinger 
488d056fa04SAlexander Leidinger 	/* 0x8061..0x???? 5.1 EMU10K1  cards */
489d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8061, "SB????", "SBLive! Player 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
490b28624fdSAriff Abdullah 	{0x1102, 0x0002, 0x1102, 0x8062, "CT4830", "SBLive! 1024", HAS_AC97 | HAS_51 | IS_EMU10K1},
491d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8064, "SB????", "SBLive! 5.1", HAS_AC97 | HAS_51 | IS_EMU10K1},
492d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8065, "SB0220", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1},
493d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8066, "CT4780", "SBLive! 5.1 Digital", HAS_AC97 | HAS_51 | IS_EMU10K1},
494d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x8067, "SB????", "SBLive!", HAS_AC97 | HAS_51 | IS_EMU10K1},
495d056fa04SAlexander Leidinger 
496d056fa04SAlexander Leidinger 	/* Generic SB Live! */
497d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x0000, "SB????", "SBLive! (Unknown model)", HAS_AC97 | IS_EMU10K1},
498d056fa04SAlexander Leidinger 
499d056fa04SAlexander Leidinger 	/* 0x0041..0x0043 EMU10K2 (some kind of Audigy) cards */
500d056fa04SAlexander Leidinger 
501d056fa04SAlexander Leidinger 	/* 0x0051..0x0051 5.1 CA0100-IAF cards */
502d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x0051, "SB0090", "Audigy", HAS_AC97 | HAS_51 | IS_EMU10K2},
503d056fa04SAlexander Leidinger 	/* ES is CA0100-IDF chip that don't work in digital mode */
504d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x0052, "SB0160", "Audigy ES", HAS_AC97 | HAS_71 | IS_EMU10K2 | BROKEN_DIGITAL},
505d056fa04SAlexander Leidinger 	/* 0x0053..0x005C 5.1 CA0101-NAF cards */
506d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x0053, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2},
507d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x0058, "SB0090", "Audigy Player/OEM", HAS_AC97 | HAS_51 | IS_EMU10K2},
508d056fa04SAlexander Leidinger 
509d056fa04SAlexander Leidinger 	/* 0x1002..0x1009 5.1 CA0102-IAT cards */
510d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x1002, "SB????", "Audigy 2 Platinum", HAS_51 | IS_CA0102},
511d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x1005, "SB????", "Audigy 2 Platinum EX", HAS_51 | IS_CA0102},
512d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x1007, "SB0240", "Audigy 2", HAS_AC97 | HAS_51 | IS_CA0102},
513d056fa04SAlexander Leidinger 
514d056fa04SAlexander Leidinger 	/* 0x2001..0x2003 7.1 CA0102-ICT cards */
515d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2001, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
516d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2002, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
517f856af04SAlexander Leidinger 	/* XXX No reports about 0x2003 & 0x2004 cards */
518f856af04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2003, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
519f856af04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2004, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
520f856af04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2005, "SB0350", "Audigy 2 ZS", HAS_AC97 | HAS_71 | IS_CA0102},
521d056fa04SAlexander Leidinger 
522d056fa04SAlexander Leidinger 	/* (range unknown) 7.1 CA0102-xxx Audigy 4 cards */
523d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x2007, "SB0380", "Audigy 4 Pro", HAS_AC97 | HAS_71 | IS_CA0102},
524d056fa04SAlexander Leidinger 
525d056fa04SAlexander Leidinger 	/* Generic Audigy or Audigy 2 */
526d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x0000, "SB????", "Audigy (Unknown model)", HAS_AC97 | HAS_51 | IS_EMU10K2},
527d056fa04SAlexander Leidinger 
528d056fa04SAlexander Leidinger 	/* We don't support CA0103-DAT (Audigy LS) cards */
529d056fa04SAlexander Leidinger 	/* There is NO CA0104-xxx cards */
530d056fa04SAlexander Leidinger 	/* There is NO CA0105-xxx cards */
531d056fa04SAlexander Leidinger 	/* We don't support CA0106-DAT (SB Live! 24 bit) cards */
532d056fa04SAlexander Leidinger 	/* There is NO CA0107-xxx cards */
533d056fa04SAlexander Leidinger 
534d056fa04SAlexander Leidinger 	/* 0x1000..0x1001 7.1 CA0108-IAT cards */
535d056fa04SAlexander Leidinger 	{0x1102, 0x0008, 0x1102, 0x1000, "SB????", "Audigy 2 LS", HAS_AC97 | HAS_51 | IS_CA0108 | DIGITAL_ONLY},
536d056fa04SAlexander Leidinger 	{0x1102, 0x0008, 0x1102, 0x1001, "SB0400", "Audigy 2 Value", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY},
537d056fa04SAlexander Leidinger 	{0x1102, 0x0008, 0x1102, 0x1021, "SB0610", "Audigy 4", HAS_AC97 | HAS_71 | IS_CA0108 | DIGITAL_ONLY},
538d056fa04SAlexander Leidinger 
539d056fa04SAlexander Leidinger 	{0x1102, 0x0008, 0x1102, 0x2001, "SB0530", "Audigy 2 ZS CardBus", HAS_AC97 | HAS_71 | IS_CA0108 | IS_CARDBUS},
540d056fa04SAlexander Leidinger 
541d056fa04SAlexander Leidinger 	{0x1102, 0x0008, 0x0000, 0x0000, "SB????", "Audigy 2 Value (Unknown model)", HAS_AC97 | HAS_51 | IS_CA0108},
542d056fa04SAlexander Leidinger };
543d056fa04SAlexander Leidinger /* Unsupported cards */
544d056fa04SAlexander Leidinger 
545d056fa04SAlexander Leidinger static struct emu_hwinfo emu_bad_cards[] = {
546d056fa04SAlexander Leidinger 	/* APS cards should be possible to support */
547d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x4001, "EMUAPS", "E-mu APS", 0},
548d056fa04SAlexander Leidinger 	{0x1102, 0x0002, 0x1102, 0x4002, "EMUAPS", "E-mu APS", 0},
549d056fa04SAlexander Leidinger 	{0x1102, 0x0004, 0x1102, 0x4001, "EMU???", "E-mu 1212m [4001]", 0},
550d056fa04SAlexander Leidinger 	/* Similar-named ("Live!" or "Audigy") cards on different chipsets */
551d056fa04SAlexander Leidinger 	{0x1102, 0x8064, 0x0000, 0x0000, "SB0100", "SBLive! 5.1 OEM", 0},
552d056fa04SAlexander Leidinger 	{0x1102, 0x0006, 0x0000, 0x0000, "SB0200", "DELL OEM SBLive! Value", 0},
553d056fa04SAlexander Leidinger 	{0x1102, 0x0007, 0x0000, 0x0000, "SB0310", "Audigy LS", 0},
554d056fa04SAlexander Leidinger };
555d056fa04SAlexander Leidinger 
556d056fa04SAlexander Leidinger /*
557d056fa04SAlexander Leidinger  * Get best known information about device.
558d056fa04SAlexander Leidinger  */
559f856af04SAlexander Leidinger static unsigned int
560d056fa04SAlexander Leidinger emu_getcard(device_t dev)
561d056fa04SAlexander Leidinger {
562d056fa04SAlexander Leidinger 	uint16_t device;
563d056fa04SAlexander Leidinger 	uint16_t subdevice;
564d056fa04SAlexander Leidinger 	int n_cards;
565f856af04SAlexander Leidinger 	unsigned int thiscard;
566d056fa04SAlexander Leidinger 	int i;
567d056fa04SAlexander Leidinger 
568d056fa04SAlexander Leidinger 	device = pci_read_config(dev, PCIR_DEVICE, /* bytes */ 2);
569d056fa04SAlexander Leidinger 	subdevice = pci_read_config(dev, PCIR_SUBDEV_0, /* bytes */ 2);
570d056fa04SAlexander Leidinger 
571d056fa04SAlexander Leidinger 	n_cards = sizeof(emu_cards) / sizeof(struct emu_hwinfo);
572f856af04SAlexander Leidinger 	thiscard = 0;
573f856af04SAlexander Leidinger 	for (i = 1; i < n_cards; i++) {
574d056fa04SAlexander Leidinger 		if (device == emu_cards[i].device) {
575d056fa04SAlexander Leidinger 			if (subdevice == emu_cards[i].subdevice) {
576d056fa04SAlexander Leidinger 				thiscard = i;
577d056fa04SAlexander Leidinger 				break;
578d056fa04SAlexander Leidinger 			}
579d056fa04SAlexander Leidinger 			if (0x0000 == emu_cards[i].subdevice) {
580d056fa04SAlexander Leidinger 				thiscard = i;
581b28624fdSAriff Abdullah 				/*
582b28624fdSAriff Abdullah 				 * don't break, we can get more specific card
583b28624fdSAriff Abdullah 				 * later in the list.
584b28624fdSAriff Abdullah 				 */
585d056fa04SAlexander Leidinger 			}
586d056fa04SAlexander Leidinger 		}
587d056fa04SAlexander Leidinger 	}
588d056fa04SAlexander Leidinger 
589d056fa04SAlexander Leidinger 	n_cards = sizeof(emu_bad_cards) / sizeof(struct emu_hwinfo);
590d056fa04SAlexander Leidinger 	for (i = 0; i < n_cards; i++) {
591d056fa04SAlexander Leidinger 		if (device == emu_bad_cards[i].device) {
592d056fa04SAlexander Leidinger 			if (subdevice == emu_bad_cards[i].subdevice) {
593f856af04SAlexander Leidinger 				thiscard = 0;
594d056fa04SAlexander Leidinger 				break;
595d056fa04SAlexander Leidinger 			}
596d056fa04SAlexander Leidinger 			if (0x0000 == emu_bad_cards[i].subdevice) {
597f856af04SAlexander Leidinger 				thiscard = 0;
598d056fa04SAlexander Leidinger 				break;	/* we avoid all this cards */
599d056fa04SAlexander Leidinger 			}
600d056fa04SAlexander Leidinger 		}
601d056fa04SAlexander Leidinger 	}
602d056fa04SAlexander Leidinger 	return (thiscard);
603d056fa04SAlexander Leidinger }
604d056fa04SAlexander Leidinger 
605d056fa04SAlexander Leidinger 
606d056fa04SAlexander Leidinger /*
607d056fa04SAlexander Leidinger  * Base hardware interface are 32 (Audigy) or 64 (Audigy2) registers.
608d056fa04SAlexander Leidinger  * Some of them are used directly, some of them provide pointer / data pairs.
609d056fa04SAlexander Leidinger  */
610d056fa04SAlexander Leidinger static uint32_t
611d056fa04SAlexander Leidinger emu_rd_nolock(struct emu_sc_info *sc, unsigned int regno, unsigned int size)
612d056fa04SAlexander Leidinger {
613d056fa04SAlexander Leidinger 
614d056fa04SAlexander Leidinger 	KASSERT(sc != NULL, ("emu_rd: NULL sc"));
615d056fa04SAlexander Leidinger 	switch (size) {
616d056fa04SAlexander Leidinger 	case 1:
617d056fa04SAlexander Leidinger 		return (bus_space_read_1(sc->st, sc->sh, regno));
618d056fa04SAlexander Leidinger 	case 2:
619d056fa04SAlexander Leidinger 		return (bus_space_read_2(sc->st, sc->sh, regno));
620d056fa04SAlexander Leidinger 	case 4:
621d056fa04SAlexander Leidinger 		return (bus_space_read_4(sc->st, sc->sh, regno));
622d056fa04SAlexander Leidinger 	}
623d056fa04SAlexander Leidinger 	return (0xffffffff);
624d056fa04SAlexander Leidinger }
625d056fa04SAlexander Leidinger 
626d056fa04SAlexander Leidinger static void
627d056fa04SAlexander Leidinger emu_wr_nolock(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size)
628d056fa04SAlexander Leidinger {
629d056fa04SAlexander Leidinger 
630d056fa04SAlexander Leidinger 	KASSERT(sc != NULL, ("emu_rd: NULL sc"));
631d056fa04SAlexander Leidinger 	switch (size) {
632d056fa04SAlexander Leidinger 	case 1:
633d056fa04SAlexander Leidinger 		bus_space_write_1(sc->st, sc->sh, regno, data);
634d056fa04SAlexander Leidinger 		break;
635d056fa04SAlexander Leidinger 	case 2:
636d056fa04SAlexander Leidinger 		bus_space_write_2(sc->st, sc->sh, regno, data);
637d056fa04SAlexander Leidinger 		break;
638d056fa04SAlexander Leidinger 	case 4:
639d056fa04SAlexander Leidinger 		bus_space_write_4(sc->st, sc->sh, regno, data);
640d056fa04SAlexander Leidinger 		break;
641d056fa04SAlexander Leidinger 	}
642d056fa04SAlexander Leidinger }
643d056fa04SAlexander Leidinger /*
64470e0bbedSPedro F. Giffuni  * EMU_PTR / EMU_DATA interface. Access to EMU10Kx is made
645d056fa04SAlexander Leidinger  * via (channel, register) pair. Some registers are channel-specific,
646d056fa04SAlexander Leidinger  * some not.
647d056fa04SAlexander Leidinger  */
648d056fa04SAlexander Leidinger uint32_t
649d056fa04SAlexander Leidinger emu_rdptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg)
650d056fa04SAlexander Leidinger {
651d056fa04SAlexander Leidinger 	uint32_t ptr, val, mask, size, offset;
652d056fa04SAlexander Leidinger 
65370e0bbedSPedro F. Giffuni 	ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK);
654b28624fdSAriff Abdullah 
655b28624fdSAriff Abdullah 	EMU_RWLOCK();
65670e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_PTR, ptr, 4);
65770e0bbedSPedro F. Giffuni 	val = emu_rd_nolock(sc, EMU_DATA, 4);
658b28624fdSAriff Abdullah 	EMU_RWUNLOCK();
659b28624fdSAriff Abdullah 
660d056fa04SAlexander Leidinger 	/*
661d056fa04SAlexander Leidinger 	 * XXX Some register numbers has data size and offset encoded in
662d056fa04SAlexander Leidinger 	 * it to get only part of 32bit register. This use is not described
663d056fa04SAlexander Leidinger 	 * in register name, be careful!
664d056fa04SAlexander Leidinger 	 */
665d056fa04SAlexander Leidinger 	if (reg & 0xff000000) {
666d056fa04SAlexander Leidinger 		size = (reg >> 24) & 0x3f;
667d056fa04SAlexander Leidinger 		offset = (reg >> 16) & 0x1f;
668d056fa04SAlexander Leidinger 		mask = ((1 << size) - 1) << offset;
669d056fa04SAlexander Leidinger 		val &= mask;
670d056fa04SAlexander Leidinger 		val >>= offset;
671d056fa04SAlexander Leidinger 	}
672d056fa04SAlexander Leidinger 	return (val);
673d056fa04SAlexander Leidinger }
674d056fa04SAlexander Leidinger 
675d056fa04SAlexander Leidinger void
676d056fa04SAlexander Leidinger emu_wrptr(struct emu_sc_info *sc, unsigned int chn, unsigned int reg, uint32_t data)
677d056fa04SAlexander Leidinger {
678d056fa04SAlexander Leidinger 	uint32_t ptr, mask, size, offset;
679b28624fdSAriff Abdullah 
68070e0bbedSPedro F. Giffuni 	ptr = ((reg << 16) & sc->address_mask) | (chn & EMU_PTR_CHNO_MASK);
681b28624fdSAriff Abdullah 
682b28624fdSAriff Abdullah 	EMU_RWLOCK();
68370e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_PTR, ptr, 4);
684d056fa04SAlexander Leidinger 	/*
685d056fa04SAlexander Leidinger 	 * XXX Another kind of magic encoding in register number. This can
686d056fa04SAlexander Leidinger 	 * give you side effect - it will read previous data from register
687d056fa04SAlexander Leidinger 	 * and change only required bits.
688d056fa04SAlexander Leidinger 	 */
689d056fa04SAlexander Leidinger 	if (reg & 0xff000000) {
690d056fa04SAlexander Leidinger 		size = (reg >> 24) & 0x3f;
691d056fa04SAlexander Leidinger 		offset = (reg >> 16) & 0x1f;
692d056fa04SAlexander Leidinger 		mask = ((1 << size) - 1) << offset;
693d056fa04SAlexander Leidinger 		data <<= offset;
694d056fa04SAlexander Leidinger 		data &= mask;
69570e0bbedSPedro F. Giffuni 		data |= emu_rd_nolock(sc, EMU_DATA, 4) & ~mask;
696d056fa04SAlexander Leidinger 	}
69770e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_DATA, data, 4);
698b28624fdSAriff Abdullah 	EMU_RWUNLOCK();
699d056fa04SAlexander Leidinger }
700d056fa04SAlexander Leidinger /*
70170e0bbedSPedro F. Giffuni  * EMU_A2_PTR / EMU_DATA2 interface. Access to P16v is made
702d056fa04SAlexander Leidinger  * via (channel, register) pair. Some registers are channel-specific,
703d056fa04SAlexander Leidinger  * some not. This interface is supported by CA0102 and CA0108 chips only.
704d056fa04SAlexander Leidinger  */
705d056fa04SAlexander Leidinger uint32_t
706d056fa04SAlexander Leidinger emu_rd_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg)
707d056fa04SAlexander Leidinger {
708d056fa04SAlexander Leidinger 	uint32_t val;
709d056fa04SAlexander Leidinger 
710b28624fdSAriff Abdullah 	/* XXX separate lock? */
711b28624fdSAriff Abdullah 	EMU_RWLOCK();
71270e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4);
71370e0bbedSPedro F. Giffuni 	val = emu_rd_nolock(sc, EMU_DATA2, 4);
714b28624fdSAriff Abdullah 
715b28624fdSAriff Abdullah 	EMU_RWUNLOCK();
716b28624fdSAriff Abdullah 
717d056fa04SAlexander Leidinger 	return (val);
718d056fa04SAlexander Leidinger }
719d056fa04SAlexander Leidinger 
720d056fa04SAlexander Leidinger void
721d056fa04SAlexander Leidinger emu_wr_p16vptr(struct emu_sc_info *sc, uint16_t chn, uint16_t reg, uint32_t data)
722d056fa04SAlexander Leidinger {
723d056fa04SAlexander Leidinger 
724b28624fdSAriff Abdullah 	EMU_RWLOCK();
72570e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_A2_PTR, (reg << 16) | chn, 4);
72670e0bbedSPedro F. Giffuni 	emu_wr_nolock(sc, EMU_DATA2, data, 4);
727b28624fdSAriff Abdullah 	EMU_RWUNLOCK();
728d056fa04SAlexander Leidinger }
729d056fa04SAlexander Leidinger /*
730d056fa04SAlexander Leidinger  * XXX CardBus interface. Not tested on any real hardware.
731d056fa04SAlexander Leidinger  */
732d056fa04SAlexander Leidinger static void
733d056fa04SAlexander Leidinger emu_wr_cbptr(struct emu_sc_info *sc, uint32_t data)
734d056fa04SAlexander Leidinger {
735d056fa04SAlexander Leidinger 	uint32_t val;
736d056fa04SAlexander Leidinger 
737b28624fdSAriff Abdullah 	/*
738b28624fdSAriff Abdullah 	 * 0x38 is IPE3 (CD S/PDIF interrupt pending register) on CA0102. Seems
739d056fa04SAlexander Leidinger 	 * to be some reg/value accessible kind of config register on CardBus
740b28624fdSAriff Abdullah 	 * CA0108, with value(?) in top 16 bit, address(?) in low 16
741b28624fdSAriff Abdullah 	 */
742b28624fdSAriff Abdullah 
743d056fa04SAlexander Leidinger 	val = emu_rd_nolock(sc, 0x38, 4);
744d056fa04SAlexander Leidinger 	emu_wr_nolock(sc, 0x38, data, 4);
745d056fa04SAlexander Leidinger 	val = emu_rd_nolock(sc, 0x38, 4);
746b28624fdSAriff Abdullah 
747d056fa04SAlexander Leidinger }
748d056fa04SAlexander Leidinger 
749d056fa04SAlexander Leidinger /*
750d056fa04SAlexander Leidinger  * Direct hardware register access
75170e0bbedSPedro F. Giffuni  * Assume that it is never used to access EMU_PTR-based registers and can run unlocked.
752d056fa04SAlexander Leidinger  */
753d056fa04SAlexander Leidinger void
754d056fa04SAlexander Leidinger emu_wr(struct emu_sc_info *sc, unsigned int regno, uint32_t data, unsigned int size)
755d056fa04SAlexander Leidinger {
75670e0bbedSPedro F. Giffuni 	KASSERT(regno != EMU_PTR, ("emu_wr: attempt to write to EMU_PTR"));
75770e0bbedSPedro F. Giffuni 	KASSERT(regno != EMU_A2_PTR, ("emu_wr: attempt to write to EMU_A2_PTR"));
758d056fa04SAlexander Leidinger 
759d056fa04SAlexander Leidinger 	emu_wr_nolock(sc, regno, data, size);
760d056fa04SAlexander Leidinger }
761d056fa04SAlexander Leidinger 
762d056fa04SAlexander Leidinger uint32_t
763d056fa04SAlexander Leidinger emu_rd(struct emu_sc_info *sc, unsigned int regno, unsigned int size)
764d056fa04SAlexander Leidinger {
765d056fa04SAlexander Leidinger 	uint32_t rd;
766d056fa04SAlexander Leidinger 
76770e0bbedSPedro F. Giffuni 	KASSERT(regno != EMU_DATA, ("emu_rd: attempt to read DATA"));
76870e0bbedSPedro F. Giffuni 	KASSERT(regno != EMU_DATA2, ("emu_rd: attempt to read DATA2"));
769b28624fdSAriff Abdullah 
770d056fa04SAlexander Leidinger 	rd = emu_rd_nolock(sc, regno, size);
771d056fa04SAlexander Leidinger 	return (rd);
772d056fa04SAlexander Leidinger }
773d056fa04SAlexander Leidinger 
774d056fa04SAlexander Leidinger /*
775d056fa04SAlexander Leidinger  * Enabling IR MIDI messages is another kind of black magic. It just
776d056fa04SAlexander Leidinger  * has to be made this way. It really do it.
777d056fa04SAlexander Leidinger  */
778d056fa04SAlexander Leidinger void
779d056fa04SAlexander Leidinger emu_enable_ir(struct emu_sc_info *sc)
780d056fa04SAlexander Leidinger {
781d056fa04SAlexander Leidinger 	uint32_t iocfg;
782d056fa04SAlexander Leidinger 
783d056fa04SAlexander Leidinger 	if (sc->is_emu10k2 || sc->is_ca0102) {
78470e0bbedSPedro F. Giffuni 		iocfg = emu_rd_nolock(sc, EMU_A_IOCFG, 2);
78570e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT2, 2);
786d056fa04SAlexander Leidinger 		DELAY(500);
78770e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1 | EMU_A_IOCFG_GPOUT2, 2);
788d056fa04SAlexander Leidinger 		DELAY(500);
78970e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_A_IOCFG, iocfg | EMU_A_IOCFG_GPOUT1, 2);
790d056fa04SAlexander Leidinger 		DELAY(100);
79170e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_A_IOCFG, iocfg, 2);
792d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Audigy IR MIDI events enabled.\n");
793d056fa04SAlexander Leidinger 		sc->enable_ir = 1;
794d056fa04SAlexander Leidinger 	}
795d056fa04SAlexander Leidinger 	if (sc->is_emu10k1) {
79670e0bbedSPedro F. Giffuni 		iocfg = emu_rd_nolock(sc, EMU_HCFG, 4);
79770e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT2, 4);
798d056fa04SAlexander Leidinger 		DELAY(500);
79970e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_HCFG, iocfg | EMU_HCFG_GPOUT1 | EMU_HCFG_GPOUT2, 4);
800d056fa04SAlexander Leidinger 		DELAY(100);
80170e0bbedSPedro F. Giffuni 		emu_wr_nolock(sc, EMU_HCFG, iocfg, 4);
802d056fa04SAlexander Leidinger 		device_printf(sc->dev, "SB Live! IR MIDI events enabled.\n");
803d056fa04SAlexander Leidinger 		sc->enable_ir = 1;
804d056fa04SAlexander Leidinger 	}
805d056fa04SAlexander Leidinger }
806d056fa04SAlexander Leidinger 
807d056fa04SAlexander Leidinger 
808d056fa04SAlexander Leidinger /*
809d056fa04SAlexander Leidinger  * emu_timer_ - HW timer managment
810d056fa04SAlexander Leidinger  */
811d056fa04SAlexander Leidinger int
812d056fa04SAlexander Leidinger emu_timer_create(struct emu_sc_info *sc)
813d056fa04SAlexander Leidinger {
814d056fa04SAlexander Leidinger 	int i, timer;
815d056fa04SAlexander Leidinger 
816d056fa04SAlexander Leidinger 	timer = -1;
817b28624fdSAriff Abdullah 
818b28624fdSAriff Abdullah 	mtx_lock(&sc->lock);
819d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
820d056fa04SAlexander Leidinger 		if (sc->timer[i] == 0) {
821d056fa04SAlexander Leidinger 			sc->timer[i] = -1;	/* disable it */
822d056fa04SAlexander Leidinger 			timer = i;
823b28624fdSAriff Abdullah 			mtx_unlock(&sc->lock);
824d056fa04SAlexander Leidinger 			return (timer);
825d056fa04SAlexander Leidinger 		}
826b28624fdSAriff Abdullah 	mtx_unlock(&sc->lock);
827d056fa04SAlexander Leidinger 
828d056fa04SAlexander Leidinger 	return (-1);
829d056fa04SAlexander Leidinger }
830d056fa04SAlexander Leidinger 
831d056fa04SAlexander Leidinger int
832d056fa04SAlexander Leidinger emu_timer_set(struct emu_sc_info *sc, int timer, int delay)
833d056fa04SAlexander Leidinger {
834d056fa04SAlexander Leidinger 	int i;
835d056fa04SAlexander Leidinger 
836f856af04SAlexander Leidinger 	if (timer < 0)
837f856af04SAlexander Leidinger 		return (-1);
838f856af04SAlexander Leidinger 
839d056fa04SAlexander Leidinger 	RANGE(delay, 16, 1024);
840f856af04SAlexander Leidinger 	RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
841d056fa04SAlexander Leidinger 
842b28624fdSAriff Abdullah 	mtx_lock(&sc->lock);
843d056fa04SAlexander Leidinger 	sc->timer[timer] = delay;
844d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
845d056fa04SAlexander Leidinger 		if (sc->timerinterval > sc->timer[i])
846d056fa04SAlexander Leidinger 			sc->timerinterval = sc->timer[i];
847d056fa04SAlexander Leidinger 
848b28624fdSAriff Abdullah 	/* XXX */
84970e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
850b28624fdSAriff Abdullah 	mtx_unlock(&sc->lock);
851b28624fdSAriff Abdullah 
852d056fa04SAlexander Leidinger 	return (timer);
853d056fa04SAlexander Leidinger }
854d056fa04SAlexander Leidinger 
855d056fa04SAlexander Leidinger int
856d056fa04SAlexander Leidinger emu_timer_enable(struct emu_sc_info *sc, int timer, int go)
857d056fa04SAlexander Leidinger {
858d056fa04SAlexander Leidinger 	uint32_t x;
859d056fa04SAlexander Leidinger 	int ena_int;
860d056fa04SAlexander Leidinger 	int i;
861d056fa04SAlexander Leidinger 
862f856af04SAlexander Leidinger 	if (timer < 0)
863f856af04SAlexander Leidinger 		return (-1);
864f856af04SAlexander Leidinger 
865f856af04SAlexander Leidinger 	RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
866f856af04SAlexander Leidinger 
867d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
868d056fa04SAlexander Leidinger 
869d056fa04SAlexander Leidinger 	if ((go == 1) && (sc->timer[timer] < 0))
870d056fa04SAlexander Leidinger 		sc->timer[timer] = -sc->timer[timer];
871d056fa04SAlexander Leidinger 	if ((go == 0) && (sc->timer[timer] > 0))
872d056fa04SAlexander Leidinger 		sc->timer[timer] = -sc->timer[timer];
873d056fa04SAlexander Leidinger 
874d056fa04SAlexander Leidinger 	ena_int = 0;
875d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) {
876d056fa04SAlexander Leidinger 		if (sc->timerinterval > sc->timer[i])
877d056fa04SAlexander Leidinger 			sc->timerinterval = sc->timer[i];
878d056fa04SAlexander Leidinger 		if (sc->timer[i] > 0)
879d056fa04SAlexander Leidinger 			ena_int = 1;
880d056fa04SAlexander Leidinger 	}
881d056fa04SAlexander Leidinger 
88270e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
883d056fa04SAlexander Leidinger 
884d056fa04SAlexander Leidinger 	if (ena_int == 1) {
88570e0bbedSPedro F. Giffuni 		x = emu_rd(sc, EMU_INTE, 4);
88670e0bbedSPedro F. Giffuni 		x |= EMU_INTE_INTERTIMERENB;
88770e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_INTE, x, 4);
888d056fa04SAlexander Leidinger 	} else {
88970e0bbedSPedro F. Giffuni 		x = emu_rd(sc, EMU_INTE, 4);
89070e0bbedSPedro F. Giffuni 		x &= ~EMU_INTE_INTERTIMERENB;
89170e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_INTE, x, 4);
892d056fa04SAlexander Leidinger 	}
893d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
894d056fa04SAlexander Leidinger 	return (0);
895d056fa04SAlexander Leidinger }
896d056fa04SAlexander Leidinger 
897d056fa04SAlexander Leidinger int
898d056fa04SAlexander Leidinger emu_timer_clear(struct emu_sc_info *sc, int timer)
899d056fa04SAlexander Leidinger {
900f856af04SAlexander Leidinger 	if (timer < 0)
901f856af04SAlexander Leidinger 		return (-1);
902f856af04SAlexander Leidinger 
903f856af04SAlexander Leidinger 	RANGE(timer, 0, EMU_MAX_IRQ_CONSUMERS-1);
904f856af04SAlexander Leidinger 
905d056fa04SAlexander Leidinger 	emu_timer_enable(sc, timer, 0);
906d056fa04SAlexander Leidinger 
907d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
908d056fa04SAlexander Leidinger 	if (sc->timer[timer] != 0)
909d056fa04SAlexander Leidinger 		sc->timer[timer] = 0;
910d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
911d056fa04SAlexander Leidinger 
912d056fa04SAlexander Leidinger 	return (timer);
913d056fa04SAlexander Leidinger }
914d056fa04SAlexander Leidinger 
915d056fa04SAlexander Leidinger /*
916d056fa04SAlexander Leidinger  * emu_intr_ - HW interrupt handler managment
917d056fa04SAlexander Leidinger  */
918d056fa04SAlexander Leidinger int
919d056fa04SAlexander Leidinger emu_intr_register(struct emu_sc_info *sc, uint32_t inte_mask, uint32_t intr_mask, uint32_t(*func) (void *softc, uint32_t irq), void *isc)
920d056fa04SAlexander Leidinger {
921d056fa04SAlexander Leidinger 	int i;
922d056fa04SAlexander Leidinger 	uint32_t x;
923d056fa04SAlexander Leidinger 
924d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
925d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
926d056fa04SAlexander Leidinger 		if (sc->ihandler[i].inte_mask == 0) {
927d056fa04SAlexander Leidinger 			sc->ihandler[i].inte_mask = inte_mask;
928d056fa04SAlexander Leidinger 			sc->ihandler[i].intr_mask = intr_mask;
929d056fa04SAlexander Leidinger 			sc->ihandler[i].softc = isc;
930d056fa04SAlexander Leidinger 			sc->ihandler[i].irq_func = func;
93170e0bbedSPedro F. Giffuni 			x = emu_rd(sc, EMU_INTE, 4);
932d056fa04SAlexander Leidinger 			x |= inte_mask;
93370e0bbedSPedro F. Giffuni 			emu_wr(sc, EMU_INTE, x, 4);
934d056fa04SAlexander Leidinger 			mtx_unlock(&sc->lock);
935b28624fdSAriff Abdullah 			if (sc->dbg_level > 1)
936f856af04SAlexander Leidinger 				device_printf(sc->dev, "ihandle %d registered\n", i);
937b28624fdSAriff Abdullah 
938d056fa04SAlexander Leidinger 			return (i);
939d056fa04SAlexander Leidinger 		}
940d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
941b28624fdSAriff Abdullah 	if (sc->dbg_level > 1)
942f856af04SAlexander Leidinger 		device_printf(sc->dev, "ihandle not registered\n");
943b28624fdSAriff Abdullah 
944d056fa04SAlexander Leidinger 	return (-1);
945d056fa04SAlexander Leidinger }
946d056fa04SAlexander Leidinger 
947d056fa04SAlexander Leidinger int
948d056fa04SAlexander Leidinger emu_intr_unregister(struct emu_sc_info *sc, int hnumber)
949d056fa04SAlexander Leidinger {
950d056fa04SAlexander Leidinger 	uint32_t x;
951d056fa04SAlexander Leidinger 	int i;
952d056fa04SAlexander Leidinger 
953d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
954d056fa04SAlexander Leidinger 
955d056fa04SAlexander Leidinger 	if (sc->ihandler[hnumber].inte_mask == 0) {
956d056fa04SAlexander Leidinger 		mtx_unlock(&sc->lock);
957d056fa04SAlexander Leidinger 		return (-1);
958d056fa04SAlexander Leidinger 	}
959d056fa04SAlexander Leidinger 
96070e0bbedSPedro F. Giffuni 	x = emu_rd(sc, EMU_INTE, 4);
961d056fa04SAlexander Leidinger 	x &= ~sc->ihandler[hnumber].inte_mask;
962d056fa04SAlexander Leidinger 
963d056fa04SAlexander Leidinger 	sc->ihandler[hnumber].inte_mask = 0;
964d056fa04SAlexander Leidinger 	sc->ihandler[hnumber].intr_mask = 0;
965d056fa04SAlexander Leidinger 	sc->ihandler[hnumber].softc = NULL;
966d056fa04SAlexander Leidinger 	sc->ihandler[hnumber].irq_func = NULL;
967d056fa04SAlexander Leidinger 
96870e0bbedSPedro F. Giffuni 	/* other interrupt handlers may use this EMU_INTE value */
969d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
970d056fa04SAlexander Leidinger 		if (sc->ihandler[i].inte_mask != 0)
971d056fa04SAlexander Leidinger 			x |= sc->ihandler[i].inte_mask;
972d056fa04SAlexander Leidinger 
97370e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_INTE, x, 4);
974d056fa04SAlexander Leidinger 
975d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
976d056fa04SAlexander Leidinger 	return (hnumber);
977d056fa04SAlexander Leidinger }
978d056fa04SAlexander Leidinger 
979d056fa04SAlexander Leidinger static void
980d056fa04SAlexander Leidinger emu_intr(void *p)
981d056fa04SAlexander Leidinger {
982d056fa04SAlexander Leidinger 	struct emu_sc_info *sc = (struct emu_sc_info *)p;
983d056fa04SAlexander Leidinger 	uint32_t stat, ack;
984d056fa04SAlexander Leidinger 	int i;
985d056fa04SAlexander Leidinger 
986d056fa04SAlexander Leidinger 	for (;;) {
98770e0bbedSPedro F. Giffuni 		stat = emu_rd(sc, EMU_IPR, 4);
988d056fa04SAlexander Leidinger 		ack = 0;
989d056fa04SAlexander Leidinger 		if (stat == 0)
990d056fa04SAlexander Leidinger 			break;
99170e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_IPR, stat, 4);
992d056fa04SAlexander Leidinger 		for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++) {
993d056fa04SAlexander Leidinger 			if ((((sc->ihandler[i].intr_mask) & stat) != 0) &&
994d056fa04SAlexander Leidinger 			    (((void *)sc->ihandler[i].irq_func) != NULL)) {
995d056fa04SAlexander Leidinger 				ack |= sc->ihandler[i].irq_func(sc->ihandler[i].softc,
996d056fa04SAlexander Leidinger 				    (sc->ihandler[i].intr_mask) & stat);
997d056fa04SAlexander Leidinger 			}
998d056fa04SAlexander Leidinger 		}
999b28624fdSAriff Abdullah 	if (sc->dbg_level > 1)
1000f856af04SAlexander Leidinger 		if (stat & (~ack))
1001f856af04SAlexander Leidinger 			device_printf(sc->dev, "Unhandled interrupt: %08x\n", stat & (~ack));
1002b28624fdSAriff Abdullah 
1003d056fa04SAlexander Leidinger 	}
1004d056fa04SAlexander Leidinger 
1005d056fa04SAlexander Leidinger 	if ((sc->is_ca0102) || (sc->is_ca0108))
1006d056fa04SAlexander Leidinger 		for (;;) {
100770e0bbedSPedro F. Giffuni 			stat = emu_rd(sc, EMU_IPR2, 4);
1008d056fa04SAlexander Leidinger 			ack = 0;
1009d056fa04SAlexander Leidinger 			if (stat == 0)
1010d056fa04SAlexander Leidinger 				break;
101170e0bbedSPedro F. Giffuni 			emu_wr(sc, EMU_IPR2, stat, 4);
1012b28624fdSAriff Abdullah 			if (sc->dbg_level > 1)
101370e0bbedSPedro F. Giffuni 				device_printf(sc->dev, "EMU_IPR2: %08x\n", stat);
1014b28624fdSAriff Abdullah 
1015d056fa04SAlexander Leidinger 			break;	/* to avoid infinite loop. shoud be removed
1016d056fa04SAlexander Leidinger 				 * after completion of P16V interface. */
1017d056fa04SAlexander Leidinger 		}
1018d056fa04SAlexander Leidinger 
1019d056fa04SAlexander Leidinger 	if (sc->is_ca0102)
1020d056fa04SAlexander Leidinger 		for (;;) {
102170e0bbedSPedro F. Giffuni 			stat = emu_rd(sc, EMU_IPR3, 4);
1022d056fa04SAlexander Leidinger 			ack = 0;
1023d056fa04SAlexander Leidinger 			if (stat == 0)
1024d056fa04SAlexander Leidinger 				break;
102570e0bbedSPedro F. Giffuni 			emu_wr(sc, EMU_IPR3, stat, 4);
1026b28624fdSAriff Abdullah 			if (sc->dbg_level > 1)
102770e0bbedSPedro F. Giffuni 				device_printf(sc->dev, "EMU_IPR3: %08x\n", stat);
1028b28624fdSAriff Abdullah 
1029d056fa04SAlexander Leidinger 			break;	/* to avoid infinite loop. should be removed
1030d056fa04SAlexander Leidinger 				 * after completion of S/PDIF interface */
1031d056fa04SAlexander Leidinger 		}
1032d056fa04SAlexander Leidinger }
1033d056fa04SAlexander Leidinger 
1034d056fa04SAlexander Leidinger 
1035d056fa04SAlexander Leidinger /*
1036d056fa04SAlexander Leidinger  * Get data from private emu10kx structure for PCM buffer allocation.
1037d056fa04SAlexander Leidinger  * Used by PCM code only.
1038d056fa04SAlexander Leidinger  */
1039d056fa04SAlexander Leidinger bus_dma_tag_t
1040d056fa04SAlexander Leidinger emu_gettag(struct emu_sc_info *sc)
1041d056fa04SAlexander Leidinger {
1042d056fa04SAlexander Leidinger 	return (sc->mem.dmat);
1043d056fa04SAlexander Leidinger }
1044d056fa04SAlexander Leidinger 
1045d056fa04SAlexander Leidinger static void
1046d056fa04SAlexander Leidinger emu_setmap(void *arg, bus_dma_segment_t * segs, int nseg, int error)
1047d056fa04SAlexander Leidinger {
1048d056fa04SAlexander Leidinger 	bus_addr_t *phys = (bus_addr_t *) arg;
1049d056fa04SAlexander Leidinger 
1050d056fa04SAlexander Leidinger 	*phys = error ? 0 : (bus_addr_t) segs->ds_addr;
1051d056fa04SAlexander Leidinger 
1052d056fa04SAlexander Leidinger 	if (bootverbose) {
1053d056fa04SAlexander Leidinger 		printf("emu10kx: setmap (%lx, %lx), nseg=%d, error=%d\n",
1054d056fa04SAlexander Leidinger 		    (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
1055d056fa04SAlexander Leidinger 		    nseg, error);
1056d056fa04SAlexander Leidinger 	}
1057d056fa04SAlexander Leidinger }
1058d056fa04SAlexander Leidinger 
1059d056fa04SAlexander Leidinger static void *
1060d056fa04SAlexander Leidinger emu_malloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr)
1061d056fa04SAlexander Leidinger {
1062d056fa04SAlexander Leidinger 	void *dmabuf;
1063d056fa04SAlexander Leidinger 	bus_dmamap_t map;
1064b28624fdSAriff Abdullah 	int error;
1065d056fa04SAlexander Leidinger 
1066d056fa04SAlexander Leidinger 	*addr = 0;
1067b28624fdSAriff Abdullah 	if ((error = bus_dmamem_alloc(mem->dmat, &dmabuf, BUS_DMA_NOWAIT, &map))) {
1068b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1069b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_malloc: failed to alloc DMA map: %d\n", error);
1070d056fa04SAlexander Leidinger 		return (NULL);
1071b28624fdSAriff Abdullah 		}
1072b28624fdSAriff Abdullah 	if ((error = bus_dmamap_load(mem->dmat, map, dmabuf, sz, emu_setmap, addr, 0)) || !*addr) {
1073b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1074b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_malloc: failed to load DMA memory: %d\n", error);
1075d056fa04SAlexander Leidinger 		return (NULL);
1076b28624fdSAriff Abdullah 		}
1077d056fa04SAlexander Leidinger 	return (dmabuf);
1078d056fa04SAlexander Leidinger }
1079d056fa04SAlexander Leidinger 
1080d056fa04SAlexander Leidinger static void
1081d056fa04SAlexander Leidinger emu_free(struct emu_mem *mem, void *dmabuf)
1082d056fa04SAlexander Leidinger {
1083d056fa04SAlexander Leidinger 	bus_dmamem_free(mem->dmat, dmabuf, NULL);
1084d056fa04SAlexander Leidinger }
1085d056fa04SAlexander Leidinger 
1086d056fa04SAlexander Leidinger static void *
1087d056fa04SAlexander Leidinger emu_memalloc(struct emu_mem *mem, uint32_t sz, bus_addr_t * addr, const char *owner)
1088d056fa04SAlexander Leidinger {
1089d056fa04SAlexander Leidinger 	uint32_t blksz, start, idx, ofs, tmp, found;
1090d056fa04SAlexander Leidinger 	struct emu_memblk *blk;
1091d056fa04SAlexander Leidinger 	void *membuf;
1092d056fa04SAlexander Leidinger 
1093d056fa04SAlexander Leidinger 	blksz = sz / EMUPAGESIZE;
1094d056fa04SAlexander Leidinger 	if (sz > (blksz * EMUPAGESIZE))
1095d056fa04SAlexander Leidinger 		blksz++;
1096b28624fdSAriff Abdullah 	if (blksz > EMU_MAX_BUFSZ / EMUPAGESIZE) {
1097b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1098b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_memalloc: memory request tool large\n");
1099e4c87b14SAlexander Leidinger 		return (NULL);
1100b28624fdSAriff Abdullah 		}
1101d056fa04SAlexander Leidinger 	/* find a free block in the bitmap */
1102d056fa04SAlexander Leidinger 	found = 0;
1103d056fa04SAlexander Leidinger 	start = 1;
1104e4c87b14SAlexander Leidinger 	while (!found && start + blksz < EMU_MAXPAGES) {
1105d056fa04SAlexander Leidinger 		found = 1;
1106d056fa04SAlexander Leidinger 		for (idx = start; idx < start + blksz; idx++)
1107d056fa04SAlexander Leidinger 			if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
1108d056fa04SAlexander Leidinger 				found = 0;
1109d056fa04SAlexander Leidinger 		if (!found)
1110d056fa04SAlexander Leidinger 			start++;
1111d056fa04SAlexander Leidinger 	}
1112b28624fdSAriff Abdullah 	if (!found) {
1113b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1114b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_memalloc: no free space in bitmap\n");
1115d056fa04SAlexander Leidinger 		return (NULL);
1116b28624fdSAriff Abdullah 		}
1117d056fa04SAlexander Leidinger 	blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT);
1118b28624fdSAriff Abdullah 	if (blk == NULL) {
1119b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1120b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_memalloc: buffer allocation failed\n");
1121d056fa04SAlexander Leidinger 		return (NULL);
1122b28624fdSAriff Abdullah 		}
1123d056fa04SAlexander Leidinger 	bzero(blk, sizeof(*blk));
1124d056fa04SAlexander Leidinger 	membuf = emu_malloc(mem, sz, &blk->buf_addr);
1125d056fa04SAlexander Leidinger 	*addr = blk->buf_addr;
1126d056fa04SAlexander Leidinger 	if (membuf == NULL) {
1127b28624fdSAriff Abdullah 		if (mem->card->dbg_level > 2)
1128b28624fdSAriff Abdullah 			device_printf(mem->card->dev, "emu_memalloc: can't setup HW memory\n");
1129d056fa04SAlexander Leidinger 		free(blk, M_DEVBUF);
1130d056fa04SAlexander Leidinger 		return (NULL);
1131d056fa04SAlexander Leidinger 	}
1132d056fa04SAlexander Leidinger 	blk->buf = membuf;
1133d056fa04SAlexander Leidinger 	blk->pte_start = start;
1134d056fa04SAlexander Leidinger 	blk->pte_size = blksz;
1135d056fa04SAlexander Leidinger 	strncpy(blk->owner, owner, 15);
1136d056fa04SAlexander Leidinger 	blk->owner[15] = '\0';
1137d056fa04SAlexander Leidinger 	ofs = 0;
1138d056fa04SAlexander Leidinger 	for (idx = start; idx < start + blksz; idx++) {
1139d056fa04SAlexander Leidinger 		mem->bmap[idx >> 3] |= 1 << (idx & 7);
1140d056fa04SAlexander Leidinger 		tmp = (uint32_t) (u_long) ((uint8_t *) blk->buf_addr + ofs);
1141d056fa04SAlexander Leidinger 		mem->ptb_pages[idx] = (tmp << 1) | idx;
1142d056fa04SAlexander Leidinger 		ofs += EMUPAGESIZE;
1143d056fa04SAlexander Leidinger 	}
1144d056fa04SAlexander Leidinger 	SLIST_INSERT_HEAD(&mem->blocks, blk, link);
1145d056fa04SAlexander Leidinger 	return (membuf);
1146d056fa04SAlexander Leidinger }
1147d056fa04SAlexander Leidinger 
1148d056fa04SAlexander Leidinger static int
1149d056fa04SAlexander Leidinger emu_memfree(struct emu_mem *mem, void *membuf)
1150d056fa04SAlexander Leidinger {
1151d056fa04SAlexander Leidinger 	uint32_t idx, tmp;
1152d056fa04SAlexander Leidinger 	struct emu_memblk *blk, *i;
1153d056fa04SAlexander Leidinger 
1154d056fa04SAlexander Leidinger 	blk = NULL;
1155d056fa04SAlexander Leidinger 	SLIST_FOREACH(i, &mem->blocks, link) {
1156d056fa04SAlexander Leidinger 		if (i->buf == membuf)
1157d056fa04SAlexander Leidinger 			blk = i;
1158d056fa04SAlexander Leidinger 	}
1159d056fa04SAlexander Leidinger 	if (blk == NULL)
1160d056fa04SAlexander Leidinger 		return (EINVAL);
1161d056fa04SAlexander Leidinger 	SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link);
1162d056fa04SAlexander Leidinger 	emu_free(mem, membuf);
1163d056fa04SAlexander Leidinger 	tmp = (uint32_t) (mem->silent_page_addr) << 1;
1164d056fa04SAlexander Leidinger 	for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) {
1165d056fa04SAlexander Leidinger 		mem->bmap[idx >> 3] &= ~(1 << (idx & 7));
1166d056fa04SAlexander Leidinger 		mem->ptb_pages[idx] = tmp | idx;
1167d056fa04SAlexander Leidinger 	}
1168d056fa04SAlexander Leidinger 	free(blk, M_DEVBUF);
1169d056fa04SAlexander Leidinger 	return (0);
1170d056fa04SAlexander Leidinger }
1171d056fa04SAlexander Leidinger 
1172d056fa04SAlexander Leidinger static int
1173d056fa04SAlexander Leidinger emu_memstart(struct emu_mem *mem, void *membuf)
1174d056fa04SAlexander Leidinger {
1175d056fa04SAlexander Leidinger 	struct emu_memblk *blk, *i;
1176d056fa04SAlexander Leidinger 
1177d056fa04SAlexander Leidinger 	blk = NULL;
1178d056fa04SAlexander Leidinger 	SLIST_FOREACH(i, &mem->blocks, link) {
1179d056fa04SAlexander Leidinger 		if (i->buf == membuf)
1180d056fa04SAlexander Leidinger 			blk = i;
1181d056fa04SAlexander Leidinger 	}
1182d056fa04SAlexander Leidinger 	if (blk == NULL)
1183d056fa04SAlexander Leidinger 		return (-1);
1184d056fa04SAlexander Leidinger 	return (blk->pte_start);
1185d056fa04SAlexander Leidinger }
1186d056fa04SAlexander Leidinger 
1187d056fa04SAlexander Leidinger 
1188d056fa04SAlexander Leidinger static uint32_t
1189d056fa04SAlexander Leidinger emu_rate_to_pitch(uint32_t rate)
1190d056fa04SAlexander Leidinger {
1191d056fa04SAlexander Leidinger 	static uint32_t logMagTable[128] = {
1192d056fa04SAlexander Leidinger 		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
1193d056fa04SAlexander Leidinger 		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
1194d056fa04SAlexander Leidinger 		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
1195d056fa04SAlexander Leidinger 		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
1196d056fa04SAlexander Leidinger 		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
1197d056fa04SAlexander Leidinger 		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
1198d056fa04SAlexander Leidinger 		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
1199d056fa04SAlexander Leidinger 		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
1200d056fa04SAlexander Leidinger 		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
1201d056fa04SAlexander Leidinger 		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
1202d056fa04SAlexander Leidinger 		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
1203d056fa04SAlexander Leidinger 		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
1204d056fa04SAlexander Leidinger 		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
1205d056fa04SAlexander Leidinger 		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
1206d056fa04SAlexander Leidinger 		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
1207d056fa04SAlexander Leidinger 		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
1208d056fa04SAlexander Leidinger 	};
1209d056fa04SAlexander Leidinger 	static char logSlopeTable[128] = {
1210d056fa04SAlexander Leidinger 		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
1211d056fa04SAlexander Leidinger 		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
1212d056fa04SAlexander Leidinger 		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
1213d056fa04SAlexander Leidinger 		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
1214d056fa04SAlexander Leidinger 		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
1215d056fa04SAlexander Leidinger 		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
1216d056fa04SAlexander Leidinger 		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
1217d056fa04SAlexander Leidinger 		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
1218d056fa04SAlexander Leidinger 		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
1219d056fa04SAlexander Leidinger 		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
1220d056fa04SAlexander Leidinger 		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
1221d056fa04SAlexander Leidinger 		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
1222d056fa04SAlexander Leidinger 		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
1223d056fa04SAlexander Leidinger 		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
1224d056fa04SAlexander Leidinger 		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
1225d056fa04SAlexander Leidinger 		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
1226d056fa04SAlexander Leidinger 	};
1227d056fa04SAlexander Leidinger 	int i;
1228d056fa04SAlexander Leidinger 
1229d056fa04SAlexander Leidinger 	if (rate == 0)
1230d056fa04SAlexander Leidinger 		return (0);
1231d056fa04SAlexander Leidinger 	rate *= 11185;		/* Scale 48000 to 0x20002380 */
1232d056fa04SAlexander Leidinger 	for (i = 31; i > 0; i--) {
1233d056fa04SAlexander Leidinger 		if (rate & 0x80000000) {	/* Detect leading "1" */
1234d056fa04SAlexander Leidinger 			return (((uint32_t) (i - 15) << 20) +
1235d056fa04SAlexander Leidinger 			    logMagTable[0x7f & (rate >> 24)] +
1236d056fa04SAlexander Leidinger 			    (0x7f & (rate >> 17)) *
1237d056fa04SAlexander Leidinger 			    logSlopeTable[0x7f & (rate >> 24)]);
1238d056fa04SAlexander Leidinger 		}
1239d056fa04SAlexander Leidinger 		rate <<= 1;
1240d056fa04SAlexander Leidinger 	}
1241d056fa04SAlexander Leidinger 	/* NOTREACHED */
1242d056fa04SAlexander Leidinger 	return (0);
1243d056fa04SAlexander Leidinger }
1244d056fa04SAlexander Leidinger 
1245d056fa04SAlexander Leidinger static uint32_t
1246d056fa04SAlexander Leidinger emu_rate_to_linearpitch(uint32_t rate)
1247d056fa04SAlexander Leidinger {
1248d056fa04SAlexander Leidinger 	rate = (rate << 8) / 375;
1249d056fa04SAlexander Leidinger 	return ((rate >> 1) + (rate & 1));
1250d056fa04SAlexander Leidinger }
1251d056fa04SAlexander Leidinger 
1252d056fa04SAlexander Leidinger struct emu_voice *
1253d056fa04SAlexander Leidinger emu_valloc(struct emu_sc_info *sc)
1254d056fa04SAlexander Leidinger {
1255d056fa04SAlexander Leidinger 	struct emu_voice *v;
1256d056fa04SAlexander Leidinger 	int i;
1257d056fa04SAlexander Leidinger 
1258d056fa04SAlexander Leidinger 	v = NULL;
1259d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
1260d056fa04SAlexander Leidinger 	for (i = 0; i < NUM_G && sc->voice[i].busy; i++);
1261d056fa04SAlexander Leidinger 	if (i < NUM_G) {
1262d056fa04SAlexander Leidinger 		v = &sc->voice[i];
1263d056fa04SAlexander Leidinger 		v->busy = 1;
1264d056fa04SAlexander Leidinger 	}
1265d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
1266d056fa04SAlexander Leidinger 	return (v);
1267d056fa04SAlexander Leidinger }
1268d056fa04SAlexander Leidinger 
1269d056fa04SAlexander Leidinger void
1270d056fa04SAlexander Leidinger emu_vfree(struct emu_sc_info *sc, struct emu_voice *v)
1271d056fa04SAlexander Leidinger {
1272d056fa04SAlexander Leidinger 	int i, r;
1273d056fa04SAlexander Leidinger 
1274d056fa04SAlexander Leidinger 	mtx_lock(&sc->lock);
1275d056fa04SAlexander Leidinger 	for (i = 0; i < NUM_G; i++) {
1276d056fa04SAlexander Leidinger 		if (v == &sc->voice[i] && sc->voice[i].busy) {
1277d056fa04SAlexander Leidinger 			v->busy = 0;
1278b28624fdSAriff Abdullah 			/*
1279b28624fdSAriff Abdullah 			 * XXX What we should do with mono channels?
1280b28624fdSAriff Abdullah 			 * See -pcm.c emupchan_init for other side of
1281b28624fdSAriff Abdullah 			 * this problem
1282b28624fdSAriff Abdullah 			 */
1283d056fa04SAlexander Leidinger 			if (v->slave != NULL)
1284d056fa04SAlexander Leidinger 				r = emu_memfree(&sc->mem, v->vbuf);
1285d056fa04SAlexander Leidinger 		}
1286d056fa04SAlexander Leidinger 	}
1287d056fa04SAlexander Leidinger 	mtx_unlock(&sc->lock);
1288d056fa04SAlexander Leidinger }
1289d056fa04SAlexander Leidinger 
1290d056fa04SAlexander Leidinger int
1291d056fa04SAlexander Leidinger emu_vinit(struct emu_sc_info *sc, struct emu_voice *m, struct emu_voice *s,
1292d056fa04SAlexander Leidinger     uint32_t sz, struct snd_dbuf *b)
1293d056fa04SAlexander Leidinger {
1294d056fa04SAlexander Leidinger 	void *vbuf;
1295d056fa04SAlexander Leidinger 	bus_addr_t tmp_addr;
1296d056fa04SAlexander Leidinger 
1297d056fa04SAlexander Leidinger 	vbuf = emu_memalloc(&sc->mem, sz, &tmp_addr, "vinit");
1298b28624fdSAriff Abdullah 	if (vbuf == NULL) {
1299b28624fdSAriff Abdullah 		if(sc->dbg_level > 2)
1300b28624fdSAriff Abdullah 			device_printf(sc->dev, "emu_memalloc returns NULL in enu_vinit\n");
1301d056fa04SAlexander Leidinger 		return (ENOMEM);
1302b28624fdSAriff Abdullah 		}
1303d056fa04SAlexander Leidinger 	if (b != NULL)
1304d056fa04SAlexander Leidinger 		sndbuf_setup(b, vbuf, sz);
1305d056fa04SAlexander Leidinger 	m->start = emu_memstart(&sc->mem, vbuf) * EMUPAGESIZE;
1306b28624fdSAriff Abdullah 	if (m->start < 0) {
1307b28624fdSAriff Abdullah 		if(sc->dbg_level > 2)
1308b28624fdSAriff Abdullah 			device_printf(sc->dev, "emu_memstart returns (-1) in enu_vinit\n");
1309d056fa04SAlexander Leidinger 		emu_memfree(&sc->mem, vbuf);
1310d056fa04SAlexander Leidinger 		return (ENOMEM);
1311d056fa04SAlexander Leidinger 	}
1312d056fa04SAlexander Leidinger 	m->end = m->start + sz;
1313d056fa04SAlexander Leidinger 	m->speed = 0;
1314d056fa04SAlexander Leidinger 	m->b16 = 0;
1315d056fa04SAlexander Leidinger 	m->stereo = 0;
1316d056fa04SAlexander Leidinger 	m->running = 0;
1317d056fa04SAlexander Leidinger 	m->ismaster = 1;
1318d056fa04SAlexander Leidinger 	m->vol = 0xff;
1319d056fa04SAlexander Leidinger 	m->buf = tmp_addr;
1320d056fa04SAlexander Leidinger 	m->vbuf = vbuf;
1321d056fa04SAlexander Leidinger 	m->slave = s;
1322d056fa04SAlexander Leidinger 	if (s != NULL) {
1323d056fa04SAlexander Leidinger 		s->start = m->start;
1324d056fa04SAlexander Leidinger 		s->end = m->end;
1325d056fa04SAlexander Leidinger 		s->speed = 0;
1326d056fa04SAlexander Leidinger 		s->b16 = 0;
1327d056fa04SAlexander Leidinger 		s->stereo = 0;
1328d056fa04SAlexander Leidinger 		s->running = 0;
1329d056fa04SAlexander Leidinger 		s->ismaster = 0;
1330d056fa04SAlexander Leidinger 		s->vol = m->vol;
1331d056fa04SAlexander Leidinger 		s->buf = m->buf;
1332d056fa04SAlexander Leidinger 		s->vbuf = NULL;
1333d056fa04SAlexander Leidinger 		s->slave = NULL;
1334d056fa04SAlexander Leidinger 	}
1335d056fa04SAlexander Leidinger 	return (0);
1336d056fa04SAlexander Leidinger }
1337d056fa04SAlexander Leidinger 
1338d056fa04SAlexander Leidinger void
1339d056fa04SAlexander Leidinger emu_vsetup(struct emu_voice *v, int fmt, int spd)
1340d056fa04SAlexander Leidinger {
1341d056fa04SAlexander Leidinger 	if (fmt) {
1342d056fa04SAlexander Leidinger 		v->b16 = (fmt & AFMT_16BIT) ? 1 : 0;
134390da2b28SAriff Abdullah 		v->stereo = (AFMT_CHANNEL(fmt) > 1) ? 1 : 0;
1344d056fa04SAlexander Leidinger 		if (v->slave != NULL) {
1345d056fa04SAlexander Leidinger 			v->slave->b16 = v->b16;
1346d056fa04SAlexander Leidinger 			v->slave->stereo = v->stereo;
1347d056fa04SAlexander Leidinger 		}
1348d056fa04SAlexander Leidinger 	}
1349d056fa04SAlexander Leidinger 	if (spd) {
1350d056fa04SAlexander Leidinger 		v->speed = spd;
1351d056fa04SAlexander Leidinger 		if (v->slave != NULL)
1352d056fa04SAlexander Leidinger 			v->slave->speed = v->speed;
1353d056fa04SAlexander Leidinger 	}
1354d056fa04SAlexander Leidinger }
1355d056fa04SAlexander Leidinger 
1356d056fa04SAlexander Leidinger void
1357d056fa04SAlexander Leidinger emu_vroute(struct emu_sc_info *sc, struct emu_route *rt,  struct emu_voice *v)
1358d056fa04SAlexander Leidinger {
1359d056fa04SAlexander Leidinger 	int i;
1360d056fa04SAlexander Leidinger 
1361d056fa04SAlexander Leidinger 	for (i = 0; i < 8; i++) {
1362b28624fdSAriff Abdullah 		v->routing[i] = rt->routing_left[i];
1363b28624fdSAriff Abdullah 		v->amounts[i] = rt->amounts_left[i];
1364d056fa04SAlexander Leidinger 	}
1365d056fa04SAlexander Leidinger 	if ((v->stereo) && (v->ismaster == 0))
1366d056fa04SAlexander Leidinger 		for (i = 0; i < 8; i++) {
1367b28624fdSAriff Abdullah 			v->routing[i] = rt->routing_right[i];
1368b28624fdSAriff Abdullah 			v->amounts[i] = rt->amounts_right[i];
1369d056fa04SAlexander Leidinger 		}
1370d056fa04SAlexander Leidinger 
1371d056fa04SAlexander Leidinger 	if ((v->stereo) && (v->slave != NULL))
1372d056fa04SAlexander Leidinger 		emu_vroute(sc, rt, v->slave);
1373d056fa04SAlexander Leidinger }
1374d056fa04SAlexander Leidinger 
1375d056fa04SAlexander Leidinger void
1376d056fa04SAlexander Leidinger emu_vwrite(struct emu_sc_info *sc, struct emu_voice *v)
1377d056fa04SAlexander Leidinger {
1378d056fa04SAlexander Leidinger 	int s;
1379b28624fdSAriff Abdullah 	uint32_t start, val, silent_page;
1380d056fa04SAlexander Leidinger 
1381d056fa04SAlexander Leidinger 	s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0);
1382d056fa04SAlexander Leidinger 
1383d056fa04SAlexander Leidinger 	v->sa = v->start >> s;
1384d056fa04SAlexander Leidinger 	v->ea = v->end >> s;
1385d056fa04SAlexander Leidinger 
1386d056fa04SAlexander Leidinger 
1387d056fa04SAlexander Leidinger 	if (v->stereo) {
138870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, EMU_CHAN_CPF_STEREO_MASK);
1389d056fa04SAlexander Leidinger 	} else {
139070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, 0);
1391d056fa04SAlexander Leidinger 	}
1392d056fa04SAlexander Leidinger 	val = v->stereo ? 28 : 30;
1393d056fa04SAlexander Leidinger 	val *= v->b16 ? 1 : 2;
1394d056fa04SAlexander Leidinger 	start = v->sa + val;
1395d056fa04SAlexander Leidinger 
1396b28624fdSAriff Abdullah 	if (sc->is_emu10k1) {
139770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_FXRT, ((v->routing[3] << 12) |
1398b28624fdSAriff Abdullah 		    (v->routing[2] << 8) |
1399b28624fdSAriff Abdullah 		    (v->routing[1] << 4) |
1400b28624fdSAriff Abdullah 		    (v->routing[0] << 0)) << 16);
1401b28624fdSAriff Abdullah 	} else {
140270e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT1, (v->routing[3] << 24) |
1403b28624fdSAriff Abdullah 		    (v->routing[2] << 16) |
1404b28624fdSAriff Abdullah 		    (v->routing[1] << 8) |
1405b28624fdSAriff Abdullah 		    (v->routing[0] << 0));
140670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT2, (v->routing[7] << 24) |
1407b28624fdSAriff Abdullah 		    (v->routing[6] << 16) |
1408b28624fdSAriff Abdullah 		    (v->routing[5] << 8) |
1409b28624fdSAriff Abdullah 		    (v->routing[4] << 0));
141070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_A_CHAN_SENDAMOUNTS, (v->amounts[7] << 24) |
1411b28624fdSAriff Abdullah 		    (v->amounts[6] << 26) |
1412b28624fdSAriff Abdullah 		    (v->amounts[5] << 8) |
1413b28624fdSAriff Abdullah 		    (v->amounts[4] << 0));
1414b28624fdSAriff Abdullah 	}
141570e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX, (v->amounts[0] << 8) | (v->amounts[1] << 0));
141670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_DSL, v->ea | (v->amounts[3] << 24));
141770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_PSST, v->sa | (v->amounts[2] << 24));
1418d056fa04SAlexander Leidinger 
141970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_CCCA, start | (v->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT));
142070e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_Z1, 0);
142170e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_Z2, 0);
1422d056fa04SAlexander Leidinger 
142370e0bbedSPedro F. Giffuni 	silent_page = ((uint32_t) (sc->mem.silent_page_addr) << 1) | EMU_CHAN_MAP_PTI_MASK;
142470e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_MAPA, silent_page);
142570e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_MAPB, silent_page);
1426d056fa04SAlexander Leidinger 
142770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, EMU_CHAN_CVCF_CURRFILTER_MASK);
142870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, EMU_CHAN_VTFT_FILTERTARGET_MASK);
142970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDM, 0);
143070e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSM, EMU_CHAN_DCYSUSM_DECAYTIME_MASK);
143170e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL1, 0x8000);
143270e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL2, 0x8000);
143370e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_FMMOD, 0);
143470e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_TREMFRQ, 0);
143570e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_FM2FRQ2, 0);
143670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVAL, 0x8000);
1437d056fa04SAlexander Leidinger 
143870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDV, EMU_CHAN_ATKHLDV_HOLDTIME_MASK | EMU_CHAN_ATKHLDV_ATTACKTIME_MASK);
143970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVOL, 0x8000);
1440d056fa04SAlexander Leidinger 
144170e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_FILTERAMOUNT, 0x7f);
144270e0bbedSPedro F. Giffuni 	emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_PITCHAMOUNT, 0);
1443d056fa04SAlexander Leidinger 	if ((v->stereo) && (v->slave != NULL))
1444d056fa04SAlexander Leidinger 		emu_vwrite(sc, v->slave);
1445d056fa04SAlexander Leidinger }
1446d056fa04SAlexander Leidinger 
1447d056fa04SAlexander Leidinger static void
1448d056fa04SAlexander Leidinger emu_vstop(struct emu_sc_info *sc, char channel, int enable)
1449d056fa04SAlexander Leidinger {
1450d056fa04SAlexander Leidinger 	int reg;
1451d056fa04SAlexander Leidinger 
145270e0bbedSPedro F. Giffuni 	reg = (channel & 0x20) ? EMU_SOLEH : EMU_SOLEL;
1453d056fa04SAlexander Leidinger 	channel &= 0x1f;
1454d056fa04SAlexander Leidinger 	reg |= 1 << 24;
1455d056fa04SAlexander Leidinger 	reg |= channel << 16;
1456d056fa04SAlexander Leidinger 	emu_wrptr(sc, 0, reg, enable);
1457d056fa04SAlexander Leidinger }
1458d056fa04SAlexander Leidinger 
1459d056fa04SAlexander Leidinger void
1460d056fa04SAlexander Leidinger emu_vtrigger(struct emu_sc_info *sc, struct emu_voice *v, int go)
1461d056fa04SAlexander Leidinger {
1462d056fa04SAlexander Leidinger 	uint32_t pitch_target, initial_pitch;
1463d056fa04SAlexander Leidinger 	uint32_t cra, cs, ccis;
1464d056fa04SAlexander Leidinger 	uint32_t sample, i;
1465d056fa04SAlexander Leidinger 
1466d056fa04SAlexander Leidinger 	if (go) {
1467d056fa04SAlexander Leidinger 		cra = 64;
1468d056fa04SAlexander Leidinger 		cs = v->stereo ? 4 : 2;
1469d056fa04SAlexander Leidinger 		ccis = v->stereo ? 28 : 30;
1470d056fa04SAlexander Leidinger 		ccis *= v->b16 ? 1 : 2;
1471d056fa04SAlexander Leidinger 		sample = v->b16 ? 0x00000000 : 0x80808080;
1472d056fa04SAlexander Leidinger 		for (i = 0; i < cs; i++)
147370e0bbedSPedro F. Giffuni 			emu_wrptr(sc, v->vnum, EMU_CHAN_CD0 + i, sample);
147470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
147570e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_READADDRESS, cra);
147670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, ccis);
1477d056fa04SAlexander Leidinger 
147870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xff00);
147970e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0xffffffff);
148070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0xffffffff);
148170e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSV, 0x00007f7f);
1482d056fa04SAlexander Leidinger 		emu_vstop(sc, v->vnum, 0);
1483d056fa04SAlexander Leidinger 
1484d056fa04SAlexander Leidinger 		pitch_target = emu_rate_to_linearpitch(v->speed);
1485d056fa04SAlexander Leidinger 		initial_pitch = emu_rate_to_pitch(v->speed) >> 8;
148670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, pitch_target);
148770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, pitch_target);
148870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_IP, initial_pitch);
1489d056fa04SAlexander Leidinger 	} else {
149070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, 0);
149170e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, 0);
149270e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xffff);
149370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0x0000ffff);
149470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0x0000ffff);
149570e0bbedSPedro F. Giffuni 		emu_wrptr(sc, v->vnum, EMU_CHAN_IP, 0);
1496d056fa04SAlexander Leidinger 		emu_vstop(sc, v->vnum, 1);
1497d056fa04SAlexander Leidinger 	}
1498d056fa04SAlexander Leidinger 	if ((v->stereo) && (v->slave != NULL))
1499d056fa04SAlexander Leidinger 		emu_vtrigger(sc, v->slave, go);
1500d056fa04SAlexander Leidinger }
1501d056fa04SAlexander Leidinger 
1502d056fa04SAlexander Leidinger int
1503d056fa04SAlexander Leidinger emu_vpos(struct emu_sc_info *sc, struct emu_voice *v)
1504d056fa04SAlexander Leidinger {
1505d056fa04SAlexander Leidinger 	int s, ptr;
1506d056fa04SAlexander Leidinger 
1507d056fa04SAlexander Leidinger 	s = (v->b16 ? 1 : 0) + (v->stereo ? 1 : 0);
150870e0bbedSPedro F. Giffuni 	ptr = (emu_rdptr(sc, v->vnum, EMU_CHAN_CCCA_CURRADDR) - (v->start >> s)) << s;
1509d056fa04SAlexander Leidinger 	return (ptr & ~0x0000001f);
1510d056fa04SAlexander Leidinger }
1511d056fa04SAlexander Leidinger 
1512d056fa04SAlexander Leidinger 
1513d056fa04SAlexander Leidinger /* fx */
1514d056fa04SAlexander Leidinger static void
1515d056fa04SAlexander Leidinger emu_wrefx(struct emu_sc_info *sc, unsigned int pc, unsigned int data)
1516d056fa04SAlexander Leidinger {
1517d056fa04SAlexander Leidinger 	emu_wrptr(sc, 0, sc->code_base + pc, data);
1518d056fa04SAlexander Leidinger }
1519d056fa04SAlexander Leidinger 
1520d056fa04SAlexander Leidinger 
1521d056fa04SAlexander Leidinger static void
1522d056fa04SAlexander Leidinger emu_addefxop(struct emu_sc_info *sc, unsigned int op, unsigned int z, unsigned int w, unsigned int x, unsigned int y, uint32_t * pc)
1523d056fa04SAlexander Leidinger {
1524d056fa04SAlexander Leidinger 	if ((*pc) + 1 > sc->code_size) {
1525d056fa04SAlexander Leidinger 		device_printf(sc->dev, "DSP CODE OVERRUN: attept to write past code_size (pc=%d)\n", (*pc));
1526d056fa04SAlexander Leidinger 		return;
1527d056fa04SAlexander Leidinger 	}
1528d056fa04SAlexander Leidinger 	emu_wrefx(sc, (*pc) * 2, (x << sc->high_operand_shift) | y);
1529d056fa04SAlexander Leidinger 	emu_wrefx(sc, (*pc) * 2 + 1, (op << sc->opcode_shift) | (z << sc->high_operand_shift) | w);
1530d056fa04SAlexander Leidinger 	(*pc)++;
1531d056fa04SAlexander Leidinger }
1532d056fa04SAlexander Leidinger 
1533d056fa04SAlexander Leidinger static int
1534d056fa04SAlexander Leidinger sysctl_emu_mixer_control(SYSCTL_HANDLER_ARGS)
1535d056fa04SAlexander Leidinger {
1536d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
1537d056fa04SAlexander Leidinger 	int	mixer_id;
1538d056fa04SAlexander Leidinger 	int	new_vol;
1539d056fa04SAlexander Leidinger 	int	err;
1540d056fa04SAlexander Leidinger 
1541d056fa04SAlexander Leidinger 	sc = arg1;
1542d056fa04SAlexander Leidinger 	mixer_id = arg2;
1543d056fa04SAlexander Leidinger 
1544d056fa04SAlexander Leidinger 	new_vol = emumix_get_volume(sc, mixer_id);
1545041b706bSDavid Malone 	err = sysctl_handle_int(oidp, &new_vol, 0, req);
1546d056fa04SAlexander Leidinger 
1547d056fa04SAlexander Leidinger 	if (err || req->newptr == NULL)
1548d056fa04SAlexander Leidinger 		return (err);
1549d056fa04SAlexander Leidinger 	if (new_vol < 0 || new_vol > 100)
1550d056fa04SAlexander Leidinger 		return (EINVAL);
1551d056fa04SAlexander Leidinger 	emumix_set_volume(sc, mixer_id, new_vol);
1552d056fa04SAlexander Leidinger 
1553d056fa04SAlexander Leidinger 	return (0);
1554d056fa04SAlexander Leidinger }
1555d056fa04SAlexander Leidinger 
1556d056fa04SAlexander Leidinger static int
1557d056fa04SAlexander Leidinger emu_addefxmixer(struct emu_sc_info *sc, const char *mix_name, const int mix_id, uint32_t defvolume)
1558d056fa04SAlexander Leidinger {
1559d056fa04SAlexander Leidinger 	int volgpr;
15604002c392SAlexander Leidinger 	char	sysctl_name[32];
1561d056fa04SAlexander Leidinger 
1562d056fa04SAlexander Leidinger 	volgpr = emu_rm_gpr_alloc(sc->rm, 1);
1563d056fa04SAlexander Leidinger 	emumix_set_fxvol(sc, volgpr, defvolume);
1564b28624fdSAriff Abdullah 	/*
1565b28624fdSAriff Abdullah 	 * Mixer controls with NULL mix_name are handled
1566b28624fdSAriff Abdullah 	 * by AC97 emulation code or PCM mixer.
1567b28624fdSAriff Abdullah 	 */
1568d056fa04SAlexander Leidinger 	if (mix_name != NULL) {
1569b28624fdSAriff Abdullah 		/*
1570b28624fdSAriff Abdullah 		 * Temporary sysctls should start with underscore,
15714002c392SAlexander Leidinger 		 * see freebsd-current mailing list, emu10kx driver
1572b28624fdSAriff Abdullah 		 * discussion around 2006-05-24.
1573b28624fdSAriff Abdullah 		 */
15744002c392SAlexander Leidinger 		snprintf(sysctl_name, 32, "_%s", mix_name);
1575d056fa04SAlexander Leidinger 		SYSCTL_ADD_PROC(sc->ctx,
1576d056fa04SAlexander Leidinger 			SYSCTL_CHILDREN(sc->root),
15774002c392SAlexander Leidinger 			OID_AUTO, sysctl_name,
1578d056fa04SAlexander Leidinger 			CTLTYPE_INT | CTLFLAG_RW, sc, mix_id,
1579d056fa04SAlexander Leidinger 			sysctl_emu_mixer_control, "I", "");
1580d056fa04SAlexander Leidinger 	}
1581d056fa04SAlexander Leidinger 
1582d056fa04SAlexander Leidinger 	return (volgpr);
1583d056fa04SAlexander Leidinger }
1584d056fa04SAlexander Leidinger 
1585b28624fdSAriff Abdullah static int
1586b28624fdSAriff Abdullah sysctl_emu_digitalswitch_control(SYSCTL_HANDLER_ARGS)
1587b28624fdSAriff Abdullah {
1588b28624fdSAriff Abdullah 	struct emu_sc_info *sc;
1589b28624fdSAriff Abdullah 	int	new_val;
1590b28624fdSAriff Abdullah 	int	err;
1591b28624fdSAriff Abdullah 
1592b28624fdSAriff Abdullah 	sc = arg1;
1593b28624fdSAriff Abdullah 
1594b28624fdSAriff Abdullah 	new_val = (sc->mode == MODE_DIGITAL) ? 1 : 0;
1595b28624fdSAriff Abdullah 	err = sysctl_handle_int(oidp, &new_val, 0, req);
1596b28624fdSAriff Abdullah 
1597b28624fdSAriff Abdullah 	if (err || req->newptr == NULL)
1598b28624fdSAriff Abdullah 		return (err);
1599b28624fdSAriff Abdullah 	if (new_val < 0 || new_val > 1)
1600b28624fdSAriff Abdullah 		return (EINVAL);
1601b28624fdSAriff Abdullah 
1602b28624fdSAriff Abdullah 	switch (new_val) {
1603b28624fdSAriff Abdullah 		case 0:
1604b28624fdSAriff Abdullah 			emumix_set_mode(sc, MODE_ANALOG);
1605b28624fdSAriff Abdullah 			break;
1606b28624fdSAriff Abdullah 		case 1:
1607b28624fdSAriff Abdullah 			emumix_set_mode(sc, MODE_DIGITAL);
1608b28624fdSAriff Abdullah 			break;
1609b28624fdSAriff Abdullah 	}
1610b28624fdSAriff Abdullah 	return (0);
1611b28624fdSAriff Abdullah }
1612b28624fdSAriff Abdullah 
1613b28624fdSAriff Abdullah static void
1614b28624fdSAriff Abdullah emu_digitalswitch(struct emu_sc_info *sc)
1615b28624fdSAriff Abdullah {
1616b28624fdSAriff Abdullah 	/* XXX temporary? */
1617b28624fdSAriff Abdullah 	SYSCTL_ADD_PROC(sc->ctx,
1618b28624fdSAriff Abdullah 		SYSCTL_CHILDREN(sc->root),
1619b28624fdSAriff Abdullah 		OID_AUTO, "_digital",
1620b28624fdSAriff Abdullah 		CTLTYPE_INT | CTLFLAG_RW, sc, 0,
1621b28624fdSAriff Abdullah 		sysctl_emu_digitalswitch_control, "I", "Enable digital output");
1622b28624fdSAriff Abdullah 
1623b28624fdSAriff Abdullah 	return;
1624b28624fdSAriff Abdullah }
1625b28624fdSAriff Abdullah 
1626b28624fdSAriff Abdullah /*
1627b28624fdSAriff Abdullah  * Allocate cache GPRs that will hold mixed output channels
1628d056fa04SAlexander Leidinger  * and clear it on every DSP run.
1629d056fa04SAlexander Leidinger  */
1630d056fa04SAlexander Leidinger #define	EFX_CACHE(CACHE_IDX) do {				\
1631d056fa04SAlexander Leidinger 	sc->cache_gpr[CACHE_IDX] = emu_rm_gpr_alloc(sc->rm, 1); \
1632d056fa04SAlexander Leidinger 	emu_addefxop(sc, ACC3, 					\
1633d056fa04SAlexander Leidinger 		GPR(sc->cache_gpr[CACHE_IDX]), 			\
1634d056fa04SAlexander Leidinger 		DSP_CONST(0), 					\
1635d056fa04SAlexander Leidinger 		DSP_CONST(0), 					\
1636d056fa04SAlexander Leidinger 		DSP_CONST(0), 					\
1637d056fa04SAlexander Leidinger 		&pc);						\
1638d056fa04SAlexander Leidinger } while (0)
1639d056fa04SAlexander Leidinger 
1640d056fa04SAlexander Leidinger /* Allocate GPR for volume control and route sound: OUT = OUT + IN * VOL */
1641d056fa04SAlexander Leidinger #define	EFX_ROUTE(TITLE, INP_NR, IN_GPR_IDX, OUT_CACHE_IDX, DEF) do { 	\
1642d056fa04SAlexander Leidinger 	sc->mixer_gpr[IN_GPR_IDX] = emu_addefxmixer(sc, TITLE, IN_GPR_IDX,  DEF); \
1643d056fa04SAlexander Leidinger 	sc->mixer_volcache[IN_GPR_IDX] = DEF; 			\
1644d056fa04SAlexander Leidinger 	emu_addefxop(sc, MACS, 					\
1645d056fa04SAlexander Leidinger 		GPR(sc->cache_gpr[OUT_CACHE_IDX]), 		\
1646d056fa04SAlexander Leidinger 		GPR(sc->cache_gpr[OUT_CACHE_IDX]),		\
1647d056fa04SAlexander Leidinger 		INP_NR,						\
1648d056fa04SAlexander Leidinger 		GPR(sc->mixer_gpr[IN_GPR_IDX]),			\
1649d056fa04SAlexander Leidinger 		&pc);						\
1650d056fa04SAlexander Leidinger } while (0)
1651d056fa04SAlexander Leidinger 
1652d056fa04SAlexander Leidinger /* allocate GPR, OUT = IN * VOL */
1653d056fa04SAlexander Leidinger #define	EFX_OUTPUT(TITLE, OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR, DEF) do {	\
1654d056fa04SAlexander Leidinger 	sc->mixer_gpr[OUT_GPR_IDX] = emu_addefxmixer(sc, TITLE, OUT_GPR_IDX, DEF); \
1655d056fa04SAlexander Leidinger 	sc->mixer_volcache[OUT_GPR_IDX] = DEF;			\
1656d056fa04SAlexander Leidinger 	emu_addefxop(sc, MACS,					\
1657d056fa04SAlexander Leidinger 		OUTP(OUTP_NR),					\
1658d056fa04SAlexander Leidinger 		DSP_CONST(0),					\
1659d056fa04SAlexander Leidinger 		GPR(sc->cache_gpr[OUT_CACHE_IDX]),		\
1660d056fa04SAlexander Leidinger 		GPR(sc->mixer_gpr[OUT_GPR_IDX]),		\
1661d056fa04SAlexander Leidinger 		&pc);						\
1662d056fa04SAlexander Leidinger } while (0)
1663d056fa04SAlexander Leidinger 
1664d056fa04SAlexander Leidinger /* like EFX_OUTPUT, but don't allocate mixer gpr */
1665d056fa04SAlexander Leidinger #define	EFX_OUTPUTD(OUT_CACHE_IDX, OUT_GPR_IDX, OUTP_NR) do {	\
1666d056fa04SAlexander Leidinger 	emu_addefxop(sc, MACS,					\
1667d056fa04SAlexander Leidinger 		OUTP(OUTP_NR),					\
1668d056fa04SAlexander Leidinger 		DSP_CONST(0),					\
1669d056fa04SAlexander Leidinger 		GPR(sc->cache_gpr[OUT_CACHE_IDX]),		\
1670d056fa04SAlexander Leidinger 		GPR(sc->mixer_gpr[OUT_GPR_IDX]),		\
1671d056fa04SAlexander Leidinger 		&pc);						\
1672d056fa04SAlexander Leidinger } while (0)
1673d056fa04SAlexander Leidinger 
1674b28624fdSAriff Abdullah /* skip next OPCOUNT instructions if FLAG != 0 */
1675b28624fdSAriff Abdullah #define EFX_SKIP(OPCOUNT, FLAG_GPR) do {			\
1676b28624fdSAriff Abdullah 	emu_addefxop(sc, MACS,					\
1677b28624fdSAriff Abdullah 		DSP_CONST(0),					\
1678b28624fdSAriff Abdullah 		GPR(sc->mute_gpr[FLAG_GPR]),					\
1679b28624fdSAriff Abdullah 		DSP_CONST(0),					\
1680b28624fdSAriff Abdullah 		DSP_CONST(0),					\
1681b28624fdSAriff Abdullah 		&pc);						\
1682b28624fdSAriff Abdullah 	emu_addefxop(sc, SKIP,					\
1683b28624fdSAriff Abdullah 		DSP_CCR,					\
1684b28624fdSAriff Abdullah 		DSP_CCR,					\
1685b28624fdSAriff Abdullah 		COND_NEQ_ZERO,					\
1686b28624fdSAriff Abdullah 		OPCOUNT,					\
1687b28624fdSAriff Abdullah 		&pc);						\
1688f856af04SAlexander Leidinger } while (0)
1689f856af04SAlexander Leidinger 
1690b28624fdSAriff Abdullah #define EFX_COPY(TO, FROM) do {					\
1691f856af04SAlexander Leidinger 	emu_addefxop(sc, ACC3,					\
1692b28624fdSAriff Abdullah 		TO,						\
1693f856af04SAlexander Leidinger 		DSP_CONST(0),					\
1694f856af04SAlexander Leidinger 		DSP_CONST(0),					\
1695b28624fdSAriff Abdullah 		FROM,						\
1696f856af04SAlexander Leidinger 		&pc);						\
1697f856af04SAlexander Leidinger } while (0)
1698f856af04SAlexander Leidinger 
1699f856af04SAlexander Leidinger 
1700d056fa04SAlexander Leidinger static void
1701d056fa04SAlexander Leidinger emu_initefx(struct emu_sc_info *sc)
1702d056fa04SAlexander Leidinger {
1703f856af04SAlexander Leidinger 	unsigned int i;
1704d056fa04SAlexander Leidinger 	uint32_t pc;
1705d056fa04SAlexander Leidinger 
1706d056fa04SAlexander Leidinger 	/* stop DSP */
1707d056fa04SAlexander Leidinger 	if (sc->is_emu10k1) {
170870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_DBG, EMU_DBG_SINGLE_STEP);
1709d056fa04SAlexander Leidinger 	} else {
171070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
1711d056fa04SAlexander Leidinger 	}
1712d056fa04SAlexander Leidinger 
1713d056fa04SAlexander Leidinger 	/* code size is in instructions */
1714d056fa04SAlexander Leidinger 	pc = 0;
1715f856af04SAlexander Leidinger 	for (i = 0; i < sc->code_size; i++) {
1716d056fa04SAlexander Leidinger 		if (sc->is_emu10k1) {
1717d056fa04SAlexander Leidinger 			emu_addefxop(sc, ACC3, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0x0), &pc);
1718d056fa04SAlexander Leidinger 		} else {
1719d056fa04SAlexander Leidinger 			emu_addefxop(sc, SKIP, DSP_CONST(0x0), DSP_CONST(0x0), DSP_CONST(0xf), DSP_CONST(0x0), &pc);
1720d056fa04SAlexander Leidinger 		}
1721d056fa04SAlexander Leidinger 	}
1722d056fa04SAlexander Leidinger 
1723b28624fdSAriff Abdullah 	/* allocate GPRs for mute switches (EFX_SKIP). Mute by default */
1724b28624fdSAriff Abdullah 	for (i = 0; i < NUM_MUTE; i++) {
1725b28624fdSAriff Abdullah 		sc->mute_gpr[i] = emu_rm_gpr_alloc(sc->rm, 1);
1726b28624fdSAriff Abdullah 		emumix_set_gpr(sc, sc->mute_gpr[i], 1);
1727b28624fdSAriff Abdullah 	}
1728b28624fdSAriff Abdullah 	emu_digitalswitch(sc);
1729b28624fdSAriff Abdullah 
1730d056fa04SAlexander Leidinger 	pc = 0;
1731d056fa04SAlexander Leidinger 
1732d056fa04SAlexander Leidinger 	/*
1733d056fa04SAlexander Leidinger 	 * DSP code below is not good, because:
1734d056fa04SAlexander Leidinger 	 * 1. It can be written smaller, if it can use DSP accumulator register
1735d056fa04SAlexander Leidinger 	 * instead of cache_gpr[].
1736d056fa04SAlexander Leidinger 	 * 2. It can be more careful when volume is 100%, because in DSP
1737d056fa04SAlexander Leidinger 	 * x*0x7fffffff may not be equal to x !
1738d056fa04SAlexander Leidinger 	 */
1739d056fa04SAlexander Leidinger 
1740d056fa04SAlexander Leidinger 	/* clean outputs */
1741f856af04SAlexander Leidinger 	for (i = 0; i < 16 ; i++) {
1742f856af04SAlexander Leidinger 		emu_addefxop(sc, ACC3, OUTP(i), DSP_CONST(0), DSP_CONST(0), DSP_CONST(0), &pc);
1743d056fa04SAlexander Leidinger 	}
1744d056fa04SAlexander Leidinger 
1745d056fa04SAlexander Leidinger 
1746d056fa04SAlexander Leidinger 	if (sc->is_emu10k1) {
1747d056fa04SAlexander Leidinger 		EFX_CACHE(C_FRONT_L);
1748d056fa04SAlexander Leidinger 		EFX_CACHE(C_FRONT_R);
1749d056fa04SAlexander Leidinger 		EFX_CACHE(C_REC_L);
1750d056fa04SAlexander Leidinger 		EFX_CACHE(C_REC_R);
1751d056fa04SAlexander Leidinger 
1752d056fa04SAlexander Leidinger 		/* fx0 to front/record, 100%/muted by default */
1753d056fa04SAlexander Leidinger 		EFX_ROUTE("pcm_front_l", FX(0), M_FX0_FRONT_L, C_FRONT_L, 100);
1754d056fa04SAlexander Leidinger 		EFX_ROUTE("pcm_front_r", FX(1), M_FX1_FRONT_R, C_FRONT_R, 100);
1755b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0);
1756b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0);
1757d056fa04SAlexander Leidinger 
1758d056fa04SAlexander Leidinger 		/* in0, from AC97 codec output */
1759d056fa04SAlexander Leidinger 		EFX_ROUTE("ac97_front_l", INP(IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 0);
1760d056fa04SAlexander Leidinger 		EFX_ROUTE("ac97_front_r", INP(IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 0);
1761d056fa04SAlexander Leidinger 		EFX_ROUTE("ac97_rec_l", INP(IN_AC97_L), M_IN0_REC_L, C_REC_L, 0);
1762d056fa04SAlexander Leidinger 		EFX_ROUTE("ac97_rec_r", INP(IN_AC97_R), M_IN0_REC_R, C_REC_R, 0);
1763d056fa04SAlexander Leidinger 
1764d056fa04SAlexander Leidinger 		/* in1, from CD S/PDIF */
1765b28624fdSAriff Abdullah 		/* XXX EFX_SKIP 4 assumes that each EFX_ROUTE is one DSP op */
1766b28624fdSAriff Abdullah 		EFX_SKIP(4, CDSPDIFMUTE);
1767b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0);
1768b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0);
1769b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0);
1770b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0);
1771b28624fdSAriff Abdullah 
1772b28624fdSAriff Abdullah 		if (sc->dbg_level > 0) {
1773d056fa04SAlexander Leidinger 			/* in2, ZoomVide (???) */
1774d056fa04SAlexander Leidinger 			EFX_ROUTE("zoom_front_l", INP(IN_ZOOM_L), M_IN2_FRONT_L, C_FRONT_L, 0);
1775d056fa04SAlexander Leidinger 			EFX_ROUTE("zoom_front_r", INP(IN_ZOOM_R), M_IN2_FRONT_R, C_FRONT_R, 0);
1776d056fa04SAlexander Leidinger 			EFX_ROUTE("zoom_rec_l", INP(IN_ZOOM_L), M_IN2_REC_L, C_REC_L, 0);
1777d056fa04SAlexander Leidinger 			EFX_ROUTE("zoom_rec_r", INP(IN_ZOOM_R), M_IN2_REC_R, C_REC_R, 0);
1778b28624fdSAriff Abdullah 		}
1779b28624fdSAriff Abdullah 
1780b28624fdSAriff Abdullah 		/* in3, TOSLink  */
1781b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_FRONT_L, C_FRONT_L, 0);
1782b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_FRONT_R, C_FRONT_R, 0);
1783b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_TOSLINK_L), M_IN3_REC_L, C_REC_L, 0);
1784b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_TOSLINK_R), M_IN3_REC_R, C_REC_R, 0);
1785d056fa04SAlexander Leidinger 		/* in4, LineIn  */
1786b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_FRONT_L, C_FRONT_L, 0);
1787b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_FRONT_R, C_FRONT_R, 0);
1788b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE1_L), M_IN4_REC_L, C_REC_L, 0);
1789b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE1_R), M_IN4_REC_R, C_REC_R, 0);
1790d056fa04SAlexander Leidinger 
1791d056fa04SAlexander Leidinger 		/* in5, on-card S/PDIF */
1792b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0);
1793b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0);
1794b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_L), M_IN5_REC_L, C_REC_L, 0);
1795b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_COAX_SPDIF_R), M_IN5_REC_R, C_REC_R, 0);
1796d056fa04SAlexander Leidinger 
1797d056fa04SAlexander Leidinger 		/* in6, Line2 on Live!Drive */
1798b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_FRONT_L, C_FRONT_L, 0);
1799b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_FRONT_R, C_FRONT_R, 0);
1800b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE2_L), M_IN6_REC_L, C_REC_L, 0);
1801b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(IN_LINE2_R), M_IN6_REC_R, C_REC_R, 0);
1802b28624fdSAriff Abdullah 
1803b28624fdSAriff Abdullah 		if (sc->dbg_level > 0) {
1804d056fa04SAlexander Leidinger 			/* in7, unknown */
1805d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0);
1806d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0);
1807d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0);
1808d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0);
1809b28624fdSAriff Abdullah 		}
1810b28624fdSAriff Abdullah 
1811b28624fdSAriff Abdullah 		/* analog and digital */
1812d056fa04SAlexander Leidinger 		EFX_OUTPUT("master_front_l", C_FRONT_L, M_MASTER_FRONT_L, OUT_AC97_L, 100);
1813d056fa04SAlexander Leidinger 		EFX_OUTPUT("master_front_r", C_FRONT_R, M_MASTER_FRONT_R, OUT_AC97_R, 100);
1814b28624fdSAriff Abdullah 		/* S/PDIF */
1815b28624fdSAriff Abdullah 		EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_TOSLINK_L);
1816b28624fdSAriff Abdullah 		EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_TOSLINK_R);
1817b28624fdSAriff Abdullah 		/* Headphones */
1818f856af04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, OUT_HEADPHONE_L);
1819f856af04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, OUT_HEADPHONE_R);
1820d056fa04SAlexander Leidinger 
1821d056fa04SAlexander Leidinger 		/* rec output to "ADC" */
1822d056fa04SAlexander Leidinger 		EFX_OUTPUT("master_rec_l", C_REC_L, M_MASTER_REC_L, OUT_ADC_REC_L, 100);
1823d056fa04SAlexander Leidinger 		EFX_OUTPUT("master_rec_r", C_REC_R, M_MASTER_REC_R, OUT_ADC_REC_R, 100);
1824b28624fdSAriff Abdullah 
1825b28624fdSAriff Abdullah 		if (!(sc->mch_disabled)) {
1826d056fa04SAlexander Leidinger 			/*
1827d056fa04SAlexander Leidinger 			 * Additional channel volume is controlled by mixer in
1828d056fa04SAlexander Leidinger 			 * emu_dspmixer_set() in -pcm.c
1829d056fa04SAlexander Leidinger 			 */
1830d056fa04SAlexander Leidinger 
1831d056fa04SAlexander Leidinger 			/* fx2/3 (pcm1) to rear */
1832d056fa04SAlexander Leidinger 			EFX_CACHE(C_REAR_L);
1833d056fa04SAlexander Leidinger 			EFX_CACHE(C_REAR_R);
1834d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100);
1835d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100);
1836d056fa04SAlexander Leidinger 
1837d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, OUT_REAR_L, 100);
1838d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, OUT_REAR_R, 100);
1839f856af04SAlexander Leidinger 			if (sc->has_51) {
1840f856af04SAlexander Leidinger 				/* fx4 (pcm2) to center */
1841f856af04SAlexander Leidinger 				EFX_CACHE(C_CENTER);
1842f856af04SAlexander Leidinger 				EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100);
1843f856af04SAlexander Leidinger 				EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100);
1844b28624fdSAriff Abdullah 
1845f856af04SAlexander Leidinger 				/* XXX in digital mode (default) this should be muted because
1846f856af04SAlexander Leidinger 				this output is shared with digital out */
1847b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
1848f856af04SAlexander Leidinger 				EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER);
1849b28624fdSAriff Abdullah 
1850f856af04SAlexander Leidinger 				/* fx5 (pcm3) to sub */
1851f856af04SAlexander Leidinger 				EFX_CACHE(C_SUB);
1852f856af04SAlexander Leidinger 				EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100);
1853f856af04SAlexander Leidinger 				EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100);
1854b28624fdSAriff Abdullah 
1855f856af04SAlexander Leidinger 				/* XXX in digital mode (default) this should be muted because
1856f856af04SAlexander Leidinger 				this output is shared with digital out */
1857b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
1858f856af04SAlexander Leidinger 				EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB);
1859f856af04SAlexander Leidinger 
1860f856af04SAlexander Leidinger 			}
1861b28624fdSAriff Abdullah 		} else {
1862b28624fdSAriff Abdullah 			/* SND_EMU10KX_MULTICHANNEL_DISABLED */
1863b28624fdSAriff Abdullah 			EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_REAR_L, OUT_REAR_L, 57); /* 75%*75% */
1864b28624fdSAriff Abdullah 			EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_REAR_R, OUT_REAR_R, 57); /* 75%*75% */
1865b28624fdSAriff Abdullah 
1866b28624fdSAriff Abdullah #if 0
1867b28624fdSAriff Abdullah 			/* XXX 5.1 does not work */
1868b28624fdSAriff Abdullah 
1869b28624fdSAriff Abdullah 			if (sc->has_51) {
1870b28624fdSAriff Abdullah 				/* (fx0+fx1)/2 to center */
1871b28624fdSAriff Abdullah 				EFX_CACHE(C_CENTER);
1872b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
1873b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1874b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1875b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
1876b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_L]),
1877b28624fdSAriff Abdullah 					&pc);
1878b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
1879b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1880b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1881b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
1882b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_R]),
1883b28624fdSAriff Abdullah 					&pc);
1884b28624fdSAriff Abdullah 				EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, OUT_D_CENTER, 100);
1885b28624fdSAriff Abdullah 
1886b28624fdSAriff Abdullah 				/* XXX in digital mode (default) this should be muted because
1887b28624fdSAriff Abdullah 				this output is shared with digital out */
1888b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
1889b28624fdSAriff Abdullah 				EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, OUT_A_CENTER);
1890b28624fdSAriff Abdullah 
1891b28624fdSAriff Abdullah 				/* (fx0+fx1)/2  to sub */
1892b28624fdSAriff Abdullah 				EFX_CACHE(C_SUB);
1893b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
1894b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1895b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1896b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
1897b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_L]),
1898b28624fdSAriff Abdullah 					&pc);
1899b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
1900b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1901b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
1902b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
1903b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_R]),
1904b28624fdSAriff Abdullah 					&pc);
1905b28624fdSAriff Abdullah 				/* XXX add lowpass filter here */
1906b28624fdSAriff Abdullah 
1907b28624fdSAriff Abdullah 				EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, OUT_D_SUB, 100);
1908b28624fdSAriff Abdullah 
1909b28624fdSAriff Abdullah 				/* XXX in digital mode (default) this should be muted because
1910b28624fdSAriff Abdullah 				this output is shared with digital out */
1911b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
1912b28624fdSAriff Abdullah 				EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, OUT_A_SUB);
1913b28624fdSAriff Abdullah 			}
1914f856af04SAlexander Leidinger #endif
1915b28624fdSAriff Abdullah 		} /* !mch_disabled */
1916b28624fdSAriff Abdullah 		if (sc->mch_rec) {
1917b28624fdSAriff Abdullah 			/*
1918b28624fdSAriff Abdullah 			 * MCH RECORDING , hight 16 slots. On 5.1 cards first 4 slots
1919b28624fdSAriff Abdullah 			 * are used as outputs and already filled with data
1920b28624fdSAriff Abdullah 			 */
1921b28624fdSAriff Abdullah 			/*
1922b28624fdSAriff Abdullah 			 * XXX On Live! cards stream does not begin at zero offset.
1923b28624fdSAriff Abdullah 			 * It can be HW, driver or sound buffering problem.
1924b28624fdSAriff Abdullah 			 * Use sync substream (offset 0x3E) to let userland find
1925b28624fdSAriff Abdullah 			 * correct data.
1926b28624fdSAriff Abdullah 			 */
1927b28624fdSAriff Abdullah 
1928b28624fdSAriff Abdullah 			/*
1929b28624fdSAriff Abdullah 			 * Substream map (in byte offsets, each substream is 2 bytes):
1930b28624fdSAriff Abdullah 			 *	0x00..0x1E - outputs
1931b28624fdSAriff Abdullah 			 *	0x20..0x3E - FX, inputs ans sync stream
1932b28624fdSAriff Abdullah 			 */
1933b28624fdSAriff Abdullah 
1934b28624fdSAriff Abdullah 			/* First 2 channels (offset 0x20,0x22) are empty */
1935b28624fdSAriff Abdullah 			for(i = (sc->has_51 ? 2 : 0); i < 2; i++)
1936b28624fdSAriff Abdullah 				EFX_COPY(FX2(i), DSP_CONST(0));
1937b28624fdSAriff Abdullah 
1938b28624fdSAriff Abdullah 			/* PCM Playback monitoring, offset 0x24..0x2A */
1939b28624fdSAriff Abdullah 			for(i = 0; i < 4; i++)
1940b28624fdSAriff Abdullah 				EFX_COPY(FX2(i+2), FX(i));
1941b28624fdSAriff Abdullah 
1942b28624fdSAriff Abdullah 			/* Copy of some inputs, offset 0x2C..0x3C */
1943b28624fdSAriff Abdullah 			for(i = 0; i < 9; i++)
1944b28624fdSAriff Abdullah 				EFX_COPY(FX2(i+8), INP(i));
1945b28624fdSAriff Abdullah 
1946b28624fdSAriff Abdullah 			/* sync data (0xc0de, offset 0x3E) */
1947b28624fdSAriff Abdullah 			sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1);
1948b28624fdSAriff Abdullah 			emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000);
1949b28624fdSAriff Abdullah 
1950b28624fdSAriff Abdullah 			EFX_COPY(FX2(15), GPR(sc->dummy_gpr));
1951b28624fdSAriff Abdullah 		} /* mch_rec */
1952d056fa04SAlexander Leidinger 	} else /* emu10k2 and later */ {
1953d056fa04SAlexander Leidinger 		EFX_CACHE(C_FRONT_L);
1954d056fa04SAlexander Leidinger 		EFX_CACHE(C_FRONT_R);
1955d056fa04SAlexander Leidinger 		EFX_CACHE(C_REC_L);
1956d056fa04SAlexander Leidinger 		EFX_CACHE(C_REC_R);
1957d056fa04SAlexander Leidinger 
1958d056fa04SAlexander Leidinger 		/* fx0 to front/record, 100%/muted by default */
1959d056fa04SAlexander Leidinger 		/*
1960d056fa04SAlexander Leidinger 		 * FRONT_[L|R] is controlled by AC97 emulation in
1961d056fa04SAlexander Leidinger 		 * emu_ac97_[read|write]_emulation in -pcm.c
1962d056fa04SAlexander Leidinger 		 */
1963d056fa04SAlexander Leidinger 		EFX_ROUTE(NULL, FX(0), M_FX0_FRONT_L, C_FRONT_L, 100);
1964d056fa04SAlexander Leidinger 		EFX_ROUTE(NULL, FX(1), M_FX1_FRONT_R, C_FRONT_R, 100);
1965b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, FX(0), M_FX0_REC_L, C_REC_L, 0);
1966b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, FX(1), M_FX1_REC_R, C_REC_R, 0);
1967d056fa04SAlexander Leidinger 
1968d056fa04SAlexander Leidinger 		/* in0, from AC97 codec output */
1969b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_FRONT_L, C_FRONT_L, 100);
1970b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_FRONT_R, C_FRONT_R, 100);
1971b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AC97_L), M_IN0_REC_L, C_REC_L, 0);
1972b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AC97_R), M_IN0_REC_R, C_REC_R, 0);
1973d056fa04SAlexander Leidinger 
1974d056fa04SAlexander Leidinger 		/* in1, from CD S/PDIF */
1975b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_FRONT_L, C_FRONT_L, 0);
1976b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_FRONT_R, C_FRONT_R, 0);
1977b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_L), M_IN1_REC_L, C_REC_L, 0);
1978b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_SPDIF_CD_R), M_IN1_REC_R, C_REC_R, 0);
1979d056fa04SAlexander Leidinger 
1980d056fa04SAlexander Leidinger 		/* in2, optical & coax S/PDIF on AudigyDrive*/
1981f856af04SAlexander Leidinger 		/* XXX Should be muted when GPRSCS valid stream == 0 */
1982b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_FRONT_L, C_FRONT_L, 0);
1983b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_FRONT_R, C_FRONT_R, 0);
1984b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_L), M_IN2_REC_L, C_REC_L, 0);
1985b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_O_SPDIF_R), M_IN2_REC_R, C_REC_R, 0);
1986b28624fdSAriff Abdullah 
1987b28624fdSAriff Abdullah 		if (sc->dbg_level > 0) {
1988d056fa04SAlexander Leidinger 			/* in3, unknown */
1989d056fa04SAlexander Leidinger 			EFX_ROUTE("in3_front_l", INP(0x6), M_IN3_FRONT_L, C_FRONT_L, 0);
1990d056fa04SAlexander Leidinger 			EFX_ROUTE("in3_front_r", INP(0x7), M_IN3_FRONT_R, C_FRONT_R, 0);
1991d056fa04SAlexander Leidinger 			EFX_ROUTE("in3_rec_l", INP(0x6), M_IN3_REC_L, C_REC_L, 0);
1992d056fa04SAlexander Leidinger 			EFX_ROUTE("in3_rec_r", INP(0x7), M_IN3_REC_R, C_REC_R, 0);
1993b28624fdSAriff Abdullah 		}
1994b28624fdSAriff Abdullah 
1995d056fa04SAlexander Leidinger 		/* in4, LineIn 2 on AudigyDrive */
1996b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_FRONT_L, C_FRONT_L, 0);
1997b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_FRONT_R, C_FRONT_R, 0);
1998b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_LINE2_L), M_IN4_REC_L, C_REC_L, 0);
1999b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_LINE2_R), M_IN4_REC_R, C_REC_R, 0);
2000d056fa04SAlexander Leidinger 
2001d056fa04SAlexander Leidinger 		/* in5, on-card S/PDIF */
2002b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_FRONT_L, C_FRONT_L, 0);
2003b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_FRONT_R, C_FRONT_R, 0);
2004b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_L), M_IN5_REC_L, C_REC_L, 0);
2005b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_R_SPDIF_R), M_IN5_REC_R, C_REC_R, 0);
2006d056fa04SAlexander Leidinger 
2007d056fa04SAlexander Leidinger 		/* in6, AUX2 on AudigyDrive */
2008b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_FRONT_L, C_FRONT_L, 0);
2009b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_FRONT_R, C_FRONT_R, 0);
2010b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AUX2_L), M_IN6_REC_L, C_REC_L, 0);
2011b28624fdSAriff Abdullah 		EFX_ROUTE(NULL, INP(A_IN_AUX2_R), M_IN6_REC_R, C_REC_R, 0);
2012b28624fdSAriff Abdullah 
2013b28624fdSAriff Abdullah 		if (sc->dbg_level > 0) {
2014d056fa04SAlexander Leidinger 			/* in7, unknown */
2015d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_front_l", INP(0xE), M_IN7_FRONT_L, C_FRONT_L, 0);
2016d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_front_r", INP(0xF), M_IN7_FRONT_R, C_FRONT_R, 0);
2017d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_rec_l", INP(0xE), M_IN7_REC_L, C_REC_L, 0);
2018d056fa04SAlexander Leidinger 			EFX_ROUTE("in7_rec_r", INP(0xF), M_IN7_REC_R, C_REC_R, 0);
2019b28624fdSAriff Abdullah 		}
2020b28624fdSAriff Abdullah 
2021d056fa04SAlexander Leidinger 		/* front output to headphones and  alog and digital *front */
2022d056fa04SAlexander Leidinger 		/* volume controlled by AC97 emulation */
2023d056fa04SAlexander Leidinger 		EFX_OUTPUT(NULL, C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_FRONT_L, 100);
2024d056fa04SAlexander Leidinger 		EFX_OUTPUT(NULL, C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_FRONT_R, 100);
2025d056fa04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_FRONT_L);
2026d056fa04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_FRONT_R);
2027d056fa04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_HPHONE_L);
2028d056fa04SAlexander Leidinger 		EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_HPHONE_R);
2029d056fa04SAlexander Leidinger 
2030d056fa04SAlexander Leidinger 		/* rec output to "ADC" */
2031d056fa04SAlexander Leidinger 		/* volume controlled by AC97 emulation */
2032d056fa04SAlexander Leidinger 		EFX_OUTPUT(NULL, C_REC_L, M_MASTER_REC_L, A_OUT_ADC_REC_L, 100);
2033507ec6d5SAlexander Leidinger 		EFX_OUTPUT(NULL, C_REC_R, M_MASTER_REC_R, A_OUT_ADC_REC_R, 100);
2034b28624fdSAriff Abdullah 
2035b28624fdSAriff Abdullah 		if (!(sc->mch_disabled)) {
2036d056fa04SAlexander Leidinger 			/*
2037d056fa04SAlexander Leidinger 			 * Additional channel volume is controlled by mixer in
2038d056fa04SAlexander Leidinger 			 * emu_dspmixer_set() in -pcm.c
2039d056fa04SAlexander Leidinger 			 */
2040d056fa04SAlexander Leidinger 
2041d056fa04SAlexander Leidinger 			/* fx2/3 (pcm1) to rear */
2042d056fa04SAlexander Leidinger 			EFX_CACHE(C_REAR_L);
2043d056fa04SAlexander Leidinger 			EFX_CACHE(C_REAR_R);
2044d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(2), M_FX2_REAR_L, C_REAR_L, 100);
2045d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(3), M_FX3_REAR_R, C_REAR_R, 100);
2046d056fa04SAlexander Leidinger 
2047d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_REAR_L, M_MASTER_REAR_L, A_OUT_A_REAR_L, 100);
2048d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_REAR_R, M_MASTER_REAR_R, A_OUT_A_REAR_R, 100);
2049d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_REAR_L, M_MASTER_REAR_L, A_OUT_D_REAR_L);
2050507ec6d5SAlexander Leidinger 			EFX_OUTPUTD(C_REAR_R, M_MASTER_REAR_R, A_OUT_D_REAR_R);
2051d056fa04SAlexander Leidinger 
2052d056fa04SAlexander Leidinger 			/* fx4 (pcm2) to center */
2053d056fa04SAlexander Leidinger 			EFX_CACHE(C_CENTER);
2054d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(4), M_FX4_CENTER, C_CENTER, 100);
2055d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100);
2056d056fa04SAlexander Leidinger #if 0
2057b28624fdSAriff Abdullah 			/*
2058b28624fdSAriff Abdullah 			 * XXX in digital mode (default) this should be muted
2059b28624fdSAriff Abdullah 			 * because this output is shared with digital out
2060b28624fdSAriff Abdullah 			 */
2061d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER);
2062d056fa04SAlexander Leidinger #endif
2063d056fa04SAlexander Leidinger 			/* fx5 (pcm3) to sub */
2064d056fa04SAlexander Leidinger 			EFX_CACHE(C_SUB);
2065d056fa04SAlexander Leidinger 			EFX_ROUTE(NULL, FX(5), M_FX5_SUBWOOFER, C_SUB, 100);
2066d056fa04SAlexander Leidinger 			EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100);
2067d056fa04SAlexander Leidinger #if 0
2068b28624fdSAriff Abdullah 			/*
2069b28624fdSAriff Abdullah 			 * XXX in digital mode (default) this should be muted
2070b28624fdSAriff Abdullah 			 * because this output is shared with digital out
2071b28624fdSAriff Abdullah 			 */
2072d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB);
2073d056fa04SAlexander Leidinger #endif
2074d056fa04SAlexander Leidinger 			if (sc->has_71) {
2075d056fa04SAlexander Leidinger 				/* XXX this will broke headphones on AudigyDrive */
2076d056fa04SAlexander Leidinger 				/* fx6/7 (pcm4) to side */
2077d056fa04SAlexander Leidinger 				EFX_CACHE(C_SIDE_L);
2078d056fa04SAlexander Leidinger 				EFX_CACHE(C_SIDE_R);
2079d056fa04SAlexander Leidinger 				EFX_ROUTE(NULL, FX(6), M_FX6_SIDE_L, C_SIDE_L, 100);
2080d056fa04SAlexander Leidinger 				EFX_ROUTE(NULL, FX(7), M_FX7_SIDE_R, C_SIDE_R, 100);
2081d056fa04SAlexander Leidinger 				EFX_OUTPUT(NULL, C_SIDE_L, M_MASTER_SIDE_L, A_OUT_A_SIDE_L, 100);
2082d056fa04SAlexander Leidinger 				EFX_OUTPUT(NULL, C_SIDE_R, M_MASTER_SIDE_R, A_OUT_A_SIDE_R, 100);
2083d056fa04SAlexander Leidinger 				EFX_OUTPUTD(C_SIDE_L, M_MASTER_SIDE_L, A_OUT_D_SIDE_L);
2084d056fa04SAlexander Leidinger 				EFX_OUTPUTD(C_SIDE_R, M_MASTER_SIDE_R, A_OUT_D_SIDE_R);
2085d056fa04SAlexander Leidinger 			}
2086b28624fdSAriff Abdullah 		} else {	/* mch_disabled */
2087d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_A_REAR_L);
2088d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_A_REAR_R);
2089d056fa04SAlexander Leidinger 
2090d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_FRONT_L, M_MASTER_FRONT_L, A_OUT_D_REAR_L);
2091d056fa04SAlexander Leidinger 			EFX_OUTPUTD(C_FRONT_R, M_MASTER_FRONT_R, A_OUT_D_REAR_R);
2092b28624fdSAriff Abdullah 
2093b28624fdSAriff Abdullah 			if (sc->has_51) {
2094b28624fdSAriff Abdullah 				/* (fx0+fx1)/2 to center */
2095b28624fdSAriff Abdullah 				EFX_CACHE(C_CENTER);
2096b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
2097b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
2098b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
2099b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
2100b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_L]),
2101b28624fdSAriff Abdullah 					&pc);
2102b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
2103b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
2104b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_CENTER]),
2105b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
2106b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_R]),
2107b28624fdSAriff Abdullah 					&pc);
2108b28624fdSAriff Abdullah 				EFX_OUTPUT(NULL, C_CENTER, M_MASTER_CENTER, A_OUT_D_CENTER, 100);
2109b28624fdSAriff Abdullah 
2110b28624fdSAriff Abdullah 				/* XXX in digital mode (default) this should be muted because
2111b28624fdSAriff Abdullah 				this output is shared with digital out */
2112b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
2113b28624fdSAriff Abdullah 				EFX_OUTPUTD(C_CENTER, M_MASTER_CENTER, A_OUT_A_CENTER);
2114b28624fdSAriff Abdullah 
2115b28624fdSAriff Abdullah 				/* (fx0+fx1)/2  to sub */
2116b28624fdSAriff Abdullah 				EFX_CACHE(C_SUB);
2117b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
2118b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_SUB]),
2119b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_SUB]),
2120b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
2121b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_L]),
2122b28624fdSAriff Abdullah 					&pc);
2123b28624fdSAriff Abdullah 				emu_addefxop(sc, MACS,
2124b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_SUB]),
2125b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_SUB]),
2126b28624fdSAriff Abdullah 					DSP_CONST(0xd), /* = 1/2 */
2127b28624fdSAriff Abdullah 					GPR(sc->cache_gpr[C_FRONT_R]),
2128b28624fdSAriff Abdullah 					&pc);
2129b28624fdSAriff Abdullah 				/* XXX add lowpass filter here */
2130b28624fdSAriff Abdullah 
2131b28624fdSAriff Abdullah 				EFX_OUTPUT(NULL, C_SUB, M_MASTER_SUBWOOFER, A_OUT_D_SUB, 100);
2132b28624fdSAriff Abdullah 
2133b28624fdSAriff Abdullah 				/* XXX in digital mode (default) this should be muted because
2134b28624fdSAriff Abdullah 				this output is shared with digital out */
2135b28624fdSAriff Abdullah 				EFX_SKIP(1, ANALOGMUTE);
2136b28624fdSAriff Abdullah 				EFX_OUTPUTD(C_SUB, M_MASTER_SUBWOOFER, A_OUT_A_SUB);
2137b28624fdSAriff Abdullah 			}
2138b28624fdSAriff Abdullah 		} /* mch_disabled */
2139b28624fdSAriff Abdullah 		if (sc->mch_rec) {
2140b28624fdSAriff Abdullah 			/* MCH RECORDING, high 32 slots */
2141b28624fdSAriff Abdullah 
2142b28624fdSAriff Abdullah 			/*
2143b28624fdSAriff Abdullah 			 * Stream map (in byte offsets):
2144b28624fdSAriff Abdullah 			 *	0x00..0x3E - outputs
2145b28624fdSAriff Abdullah 			 *	0x40..0x7E - FX, inputs
2146b28624fdSAriff Abdullah 			 *	each substream is 2 bytes.
2147b28624fdSAriff Abdullah 			 */
2148b28624fdSAriff Abdullah 			/*
2149b28624fdSAriff Abdullah 			 * XXX Audigy 2 Value cards (and, possibly,
2150b28624fdSAriff Abdullah 			 * Audigy 4) write some unknown data in place of
2151b28624fdSAriff Abdullah 			 * some outputs (offsets 0x20..0x3F) and one
2152b28624fdSAriff Abdullah 			 * input (offset 0x7E).
2153b28624fdSAriff Abdullah 			 */
2154b28624fdSAriff Abdullah 
2155b28624fdSAriff Abdullah 			/* PCM Playback monitoring, offsets 0x40..0x5E */
2156b28624fdSAriff Abdullah 			for(i = 0; i < 16; i++)
2157b28624fdSAriff Abdullah 				EFX_COPY(FX2(i), FX(i));
2158b28624fdSAriff Abdullah 
2159b28624fdSAriff Abdullah 			/* Copy of all inputs, offsets 0x60..0x7E */
2160b28624fdSAriff Abdullah 			for(i = 0; i < 16; i++)
2161b28624fdSAriff Abdullah 				EFX_COPY(FX2(i+16), INP(i));
2162b28624fdSAriff Abdullah #if 0
2163b28624fdSAriff Abdullah 			/* XXX Audigy seems to work correct and does not need this */
2164b28624fdSAriff Abdullah 			/* sync data (0xc0de), offset 0x7E */
2165b28624fdSAriff Abdullah 			sc->dummy_gpr = emu_rm_gpr_alloc(sc->rm, 1);
2166b28624fdSAriff Abdullah 			emumix_set_gpr(sc, sc->dummy_gpr, 0xc0de0000);
2167b28624fdSAriff Abdullah 			EFX_COPY(FX2(31), GPR(sc->dummy_gpr));
2168d056fa04SAlexander Leidinger #endif
2169b28624fdSAriff Abdullah 		} /* mch_rec */
2170d056fa04SAlexander Leidinger 	}
2171d056fa04SAlexander Leidinger 
2172d056fa04SAlexander Leidinger 	sc->routing_code_end = pc;
2173d056fa04SAlexander Leidinger 
2174d056fa04SAlexander Leidinger 	/* start DSP */
2175d056fa04SAlexander Leidinger 	if (sc->is_emu10k1) {
217670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_DBG, 0);
2177d056fa04SAlexander Leidinger 	} else {
217870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_A_DBG, 0);
2179d056fa04SAlexander Leidinger 	}
2180d056fa04SAlexander Leidinger }
2181d056fa04SAlexander Leidinger 
2182d056fa04SAlexander Leidinger /* /dev/em10kx */
2183d056fa04SAlexander Leidinger static d_open_t		emu10kx_open;
2184d056fa04SAlexander Leidinger static d_close_t	emu10kx_close;
2185d056fa04SAlexander Leidinger static d_read_t		emu10kx_read;
2186d056fa04SAlexander Leidinger 
2187d056fa04SAlexander Leidinger static struct cdevsw emu10kx_cdevsw = {
2188d056fa04SAlexander Leidinger 	.d_open = 	emu10kx_open,
2189d056fa04SAlexander Leidinger 	.d_close =	emu10kx_close,
2190d056fa04SAlexander Leidinger 	.d_read = 	emu10kx_read,
2191d056fa04SAlexander Leidinger 	.d_name = 	"emu10kx",
2192d056fa04SAlexander Leidinger 	.d_version = 	D_VERSION,
2193d056fa04SAlexander Leidinger };
2194d056fa04SAlexander Leidinger 
2195d056fa04SAlexander Leidinger 
2196d056fa04SAlexander Leidinger static int
2197d056fa04SAlexander Leidinger emu10kx_open(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused)
2198d056fa04SAlexander Leidinger {
2199d056fa04SAlexander Leidinger 	int error;
2200d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
2201d056fa04SAlexander Leidinger 
2202d056fa04SAlexander Leidinger 	sc = i_dev->si_drv1;
2203d056fa04SAlexander Leidinger 	mtx_lock(&sc->emu10kx_lock);
2204d056fa04SAlexander Leidinger 	if (sc->emu10kx_isopen) {
2205d056fa04SAlexander Leidinger 		mtx_unlock(&sc->emu10kx_lock);
2206d056fa04SAlexander Leidinger 		return (EBUSY);
2207d056fa04SAlexander Leidinger 	}
2208d056fa04SAlexander Leidinger 	sc->emu10kx_isopen = 1;
2209d056fa04SAlexander Leidinger 	mtx_unlock(&sc->emu10kx_lock);
2210d056fa04SAlexander Leidinger 	if (sbuf_new(&sc->emu10kx_sbuf, NULL, 4096, 0) == NULL) {
2211d056fa04SAlexander Leidinger 		error = ENXIO;
2212d056fa04SAlexander Leidinger 		goto out;
2213d056fa04SAlexander Leidinger 	}
2214d056fa04SAlexander Leidinger 	sc->emu10kx_bufptr = 0;
2215d056fa04SAlexander Leidinger 	error = (emu10kx_prepare(sc, &sc->emu10kx_sbuf) > 0) ? 0 : ENOMEM;
2216d056fa04SAlexander Leidinger out:
2217d056fa04SAlexander Leidinger 	if (error) {
2218d056fa04SAlexander Leidinger 		mtx_lock(&sc->emu10kx_lock);
2219d056fa04SAlexander Leidinger 		sc->emu10kx_isopen = 0;
2220d056fa04SAlexander Leidinger 		mtx_unlock(&sc->emu10kx_lock);
2221d056fa04SAlexander Leidinger 	}
2222d056fa04SAlexander Leidinger 	return (error);
2223d056fa04SAlexander Leidinger }
2224d056fa04SAlexander Leidinger 
2225d056fa04SAlexander Leidinger static int
2226d056fa04SAlexander Leidinger emu10kx_close(struct cdev *i_dev, int flags __unused, int mode __unused, struct thread *td __unused)
2227d056fa04SAlexander Leidinger {
2228d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
2229d056fa04SAlexander Leidinger 
2230d056fa04SAlexander Leidinger 	sc = i_dev->si_drv1;
2231d056fa04SAlexander Leidinger 
2232d056fa04SAlexander Leidinger 	mtx_lock(&sc->emu10kx_lock);
2233d056fa04SAlexander Leidinger 	if (!(sc->emu10kx_isopen)) {
2234d056fa04SAlexander Leidinger 		mtx_unlock(&sc->emu10kx_lock);
2235d056fa04SAlexander Leidinger 		return (EBADF);
2236d056fa04SAlexander Leidinger 	}
2237d056fa04SAlexander Leidinger 	sbuf_delete(&sc->emu10kx_sbuf);
2238d056fa04SAlexander Leidinger 	sc->emu10kx_isopen = 0;
2239d056fa04SAlexander Leidinger 	mtx_unlock(&sc->emu10kx_lock);
2240d056fa04SAlexander Leidinger 
2241d056fa04SAlexander Leidinger 	return (0);
2242d056fa04SAlexander Leidinger }
2243d056fa04SAlexander Leidinger 
2244d056fa04SAlexander Leidinger static int
2245d056fa04SAlexander Leidinger emu10kx_read(struct cdev *i_dev, struct uio *buf, int flag __unused)
2246d056fa04SAlexander Leidinger {
2247d056fa04SAlexander Leidinger 	int l, err;
2248d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
2249d056fa04SAlexander Leidinger 
2250d056fa04SAlexander Leidinger 	sc = i_dev->si_drv1;
2251d056fa04SAlexander Leidinger 	mtx_lock(&sc->emu10kx_lock);
2252d056fa04SAlexander Leidinger 	if (!(sc->emu10kx_isopen)) {
2253d056fa04SAlexander Leidinger 		mtx_unlock(&sc->emu10kx_lock);
2254d056fa04SAlexander Leidinger 		return (EBADF);
2255d056fa04SAlexander Leidinger 	}
2256d056fa04SAlexander Leidinger 	mtx_unlock(&sc->emu10kx_lock);
2257d056fa04SAlexander Leidinger 
2258d056fa04SAlexander Leidinger 	l = min(buf->uio_resid, sbuf_len(&sc->emu10kx_sbuf) - sc->emu10kx_bufptr);
2259d056fa04SAlexander Leidinger 	err = (l > 0) ? uiomove(sbuf_data(&sc->emu10kx_sbuf) + sc->emu10kx_bufptr, l, buf) : 0;
2260d056fa04SAlexander Leidinger 	sc->emu10kx_bufptr += l;
2261d056fa04SAlexander Leidinger 
2262d056fa04SAlexander Leidinger 	return (err);
2263d056fa04SAlexander Leidinger }
2264d056fa04SAlexander Leidinger 
2265d056fa04SAlexander Leidinger static int
2266d056fa04SAlexander Leidinger emu10kx_prepare(struct emu_sc_info *sc, struct sbuf *s)
2267d056fa04SAlexander Leidinger {
2268d056fa04SAlexander Leidinger 	int i;
2269d056fa04SAlexander Leidinger 
2270d056fa04SAlexander Leidinger 	sbuf_printf(s, "FreeBSD EMU10Kx Audio Driver\n");
2271d056fa04SAlexander Leidinger 	sbuf_printf(s, "\nHardware resource usage:\n");
2272d056fa04SAlexander Leidinger 	sbuf_printf(s, "DSP General Purpose Registers: %d used, %d total\n", sc->rm->num_used, sc->rm->num_gprs);
2273d056fa04SAlexander Leidinger 	sbuf_printf(s, "DSP Instruction Registers: %d used, %d total\n", sc->routing_code_end, sc->code_size);
2274d056fa04SAlexander Leidinger 	sbuf_printf(s, "Card supports");
2275d056fa04SAlexander Leidinger 	if (sc->has_ac97) {
2276d056fa04SAlexander Leidinger 		sbuf_printf(s, " AC97 codec");
2277d056fa04SAlexander Leidinger 	} else {
2278d056fa04SAlexander Leidinger 		sbuf_printf(s, " NO AC97 codec");
2279d056fa04SAlexander Leidinger 	}
2280d056fa04SAlexander Leidinger 	if (sc->has_51) {
2281d056fa04SAlexander Leidinger 		if (sc->has_71)
2282d056fa04SAlexander Leidinger 			sbuf_printf(s, " and 7.1 output");
2283d056fa04SAlexander Leidinger 		else
2284d056fa04SAlexander Leidinger 			sbuf_printf(s, " and 5.1 output");
2285d056fa04SAlexander Leidinger 	}
2286d056fa04SAlexander Leidinger 	if (sc->is_emu10k1)
2287d056fa04SAlexander Leidinger 		sbuf_printf(s, ", SBLive! DSP code");
2288d056fa04SAlexander Leidinger 	if (sc->is_emu10k2)
2289d056fa04SAlexander Leidinger 		sbuf_printf(s, ", Audigy DSP code");
2290d056fa04SAlexander Leidinger 	if (sc->is_ca0102)
2291d056fa04SAlexander Leidinger 		sbuf_printf(s, ", Audigy DSP code with Audigy2 hacks");
2292d056fa04SAlexander Leidinger 	if (sc->is_ca0108)
2293d056fa04SAlexander Leidinger 		sbuf_printf(s, ", Audigy DSP code with Audigy2Value hacks");
2294d056fa04SAlexander Leidinger 	sbuf_printf(s, "\n");
2295d056fa04SAlexander Leidinger 	if (sc->broken_digital)
2296d056fa04SAlexander Leidinger 		sbuf_printf(s, "Digital mode unsupported\n");
2297d056fa04SAlexander Leidinger 	sbuf_printf(s, "\nInstalled devices:\n");
2298f856af04SAlexander Leidinger 	for (i = 0; i < RT_COUNT; i++)
2299d056fa04SAlexander Leidinger 		if (sc->pcm[i] != NULL)
2300d056fa04SAlexander Leidinger 			if (device_is_attached(sc->pcm[i])) {
2301d056fa04SAlexander Leidinger 				sbuf_printf(s, "%s on %s\n", device_get_desc(sc->pcm[i]), device_get_nameunit(sc->pcm[i]));
2302d056fa04SAlexander Leidinger 			}
2303d056fa04SAlexander Leidinger 	if (sc->midi[0] != NULL)
2304d056fa04SAlexander Leidinger 		if (device_is_attached(sc->midi[0])) {
2305d056fa04SAlexander Leidinger 			sbuf_printf(s, "EMU10Kx MIDI Interface\n");
2306d056fa04SAlexander Leidinger 			sbuf_printf(s, "\tOn-card connector on %s\n", device_get_nameunit(sc->midi[0]));
2307d056fa04SAlexander Leidinger 		}
2308d056fa04SAlexander Leidinger 	if (sc->midi[1] != NULL)
2309d056fa04SAlexander Leidinger 		if (device_is_attached(sc->midi[1])) {
2310d056fa04SAlexander Leidinger 			sbuf_printf(s, "\tOn-Drive connector on %s\n", device_get_nameunit(sc->midi[1]));
2311d056fa04SAlexander Leidinger 		}
2312d056fa04SAlexander Leidinger 	if (sc->midi[0] != NULL)
2313d056fa04SAlexander Leidinger 		if (device_is_attached(sc->midi[0])) {
2314d056fa04SAlexander Leidinger 			sbuf_printf(s, "\tIR reciever MIDI events %s\n", sc->enable_ir ? "enabled" : "disabled");
2315d056fa04SAlexander Leidinger 		}
2316b28624fdSAriff Abdullah 	sbuf_printf(s, "Card is in %s mode\n", (sc->mode == MODE_ANALOG) ? "analog" : "digital");
2317b28624fdSAriff Abdullah 
2318d056fa04SAlexander Leidinger 	sbuf_finish(s);
2319d056fa04SAlexander Leidinger 	return (sbuf_len(s));
2320d056fa04SAlexander Leidinger }
2321d056fa04SAlexander Leidinger 
2322d056fa04SAlexander Leidinger /* INIT & UNINIT */
2323d056fa04SAlexander Leidinger static int
2324d056fa04SAlexander Leidinger emu10kx_dev_init(struct emu_sc_info *sc)
2325d056fa04SAlexander Leidinger {
2326d056fa04SAlexander Leidinger 	int unit;
2327d056fa04SAlexander Leidinger 
2328b28624fdSAriff Abdullah 	mtx_init(&sc->emu10kx_lock, device_get_nameunit(sc->dev), "kxdevlock", 0);
2329d056fa04SAlexander Leidinger 	unit = device_get_unit(sc->dev);
2330d056fa04SAlexander Leidinger 
233190da2b28SAriff Abdullah 	sc->cdev = make_dev(&emu10kx_cdevsw, PCMMINOR(unit), UID_ROOT, GID_WHEEL, 0640, "emu10kx%d", unit);
2332d056fa04SAlexander Leidinger 	if (sc->cdev != NULL) {
2333d056fa04SAlexander Leidinger 		sc->cdev->si_drv1 = sc;
2334d056fa04SAlexander Leidinger 		return (0);
2335d056fa04SAlexander Leidinger 	}
2336d056fa04SAlexander Leidinger 	return (ENXIO);
2337d056fa04SAlexander Leidinger }
2338d056fa04SAlexander Leidinger 
2339d056fa04SAlexander Leidinger static int
2340d056fa04SAlexander Leidinger emu10kx_dev_uninit(struct emu_sc_info *sc)
2341d056fa04SAlexander Leidinger {
2342d056fa04SAlexander Leidinger 	mtx_lock(&sc->emu10kx_lock);
2343d056fa04SAlexander Leidinger 	if (sc->emu10kx_isopen) {
2344d056fa04SAlexander Leidinger 		mtx_unlock(&sc->emu10kx_lock);
2345d056fa04SAlexander Leidinger 		return (EBUSY);
2346d056fa04SAlexander Leidinger 	}
2347d056fa04SAlexander Leidinger 	if (sc->cdev)
2348d056fa04SAlexander Leidinger 		destroy_dev(sc->cdev);
2349d056fa04SAlexander Leidinger 	sc->cdev = 0;
2350d056fa04SAlexander Leidinger 
2351d056fa04SAlexander Leidinger 	mtx_destroy(&sc->emu10kx_lock);
2352d056fa04SAlexander Leidinger 	return (0);
2353d056fa04SAlexander Leidinger }
2354d056fa04SAlexander Leidinger 
2355d056fa04SAlexander Leidinger /* resource manager */
2356d056fa04SAlexander Leidinger int
2357d056fa04SAlexander Leidinger emu_rm_init(struct emu_sc_info *sc)
2358d056fa04SAlexander Leidinger {
2359d056fa04SAlexander Leidinger 	int i;
2360d056fa04SAlexander Leidinger 	int maxcount;
2361d056fa04SAlexander Leidinger 	struct emu_rm *rm;
2362d056fa04SAlexander Leidinger 
2363d056fa04SAlexander Leidinger 	rm = malloc(sizeof(struct emu_rm), M_DEVBUF, M_NOWAIT | M_ZERO);
2364d056fa04SAlexander Leidinger 	if (rm == NULL) {
2365d056fa04SAlexander Leidinger 		return (ENOMEM);
2366d056fa04SAlexander Leidinger 	}
2367d056fa04SAlexander Leidinger 	sc->rm = rm;
2368d056fa04SAlexander Leidinger 	rm->card = sc;
2369d056fa04SAlexander Leidinger 	maxcount = sc->num_gprs;
2370d056fa04SAlexander Leidinger 	rm->num_used = 0;
2371b28624fdSAriff Abdullah 	mtx_init(&(rm->gpr_lock), device_get_nameunit(sc->dev), "gpr alloc", MTX_DEF);
2372d056fa04SAlexander Leidinger 	rm->num_gprs = (maxcount < EMU_MAX_GPR ? maxcount : EMU_MAX_GPR);
2373d056fa04SAlexander Leidinger 	for (i = 0; i < rm->num_gprs; i++)
2374d056fa04SAlexander Leidinger 		rm->allocmap[i] = 0;
2375b28624fdSAriff Abdullah 	/* pre-allocate gpr[0] */
2376b28624fdSAriff Abdullah 	rm->allocmap[0] = 1;
2377b28624fdSAriff Abdullah 	rm->last_free_gpr = 1;
2378d056fa04SAlexander Leidinger 
2379d056fa04SAlexander Leidinger 	return (0);
2380d056fa04SAlexander Leidinger }
2381d056fa04SAlexander Leidinger 
2382d056fa04SAlexander Leidinger int
2383d056fa04SAlexander Leidinger emu_rm_uninit(struct emu_sc_info *sc)
2384d056fa04SAlexander Leidinger {
2385d056fa04SAlexander Leidinger 	int i;
2386d056fa04SAlexander Leidinger 
2387b28624fdSAriff Abdullah 	if (sc->dbg_level > 1) {
2388d056fa04SAlexander Leidinger 		mtx_lock(&(sc->rm->gpr_lock));
2389b28624fdSAriff Abdullah 		for (i = 1; i < sc->rm->last_free_gpr; i++)
2390d056fa04SAlexander Leidinger 			if (sc->rm->allocmap[i] > 0)
2391d056fa04SAlexander Leidinger 				device_printf(sc->dev, "rm: gpr %d not free before uninit\n", i);
2392d056fa04SAlexander Leidinger 		mtx_unlock(&(sc->rm->gpr_lock));
2393b28624fdSAriff Abdullah 	}
2394b28624fdSAriff Abdullah 
2395d056fa04SAlexander Leidinger 	mtx_destroy(&(sc->rm->gpr_lock));
2396d056fa04SAlexander Leidinger 	free(sc->rm, M_DEVBUF);
2397d056fa04SAlexander Leidinger 	return (0);
2398d056fa04SAlexander Leidinger }
2399d056fa04SAlexander Leidinger 
2400d056fa04SAlexander Leidinger static int
2401d056fa04SAlexander Leidinger emu_rm_gpr_alloc(struct emu_rm *rm, int count)
2402d056fa04SAlexander Leidinger {
2403d056fa04SAlexander Leidinger 	int i, j;
2404d056fa04SAlexander Leidinger 	int allocated_gpr;
2405d056fa04SAlexander Leidinger 
2406d056fa04SAlexander Leidinger 	allocated_gpr = rm->num_gprs;
2407d056fa04SAlexander Leidinger 	/* try fast way first */
2408d056fa04SAlexander Leidinger 	mtx_lock(&(rm->gpr_lock));
2409d056fa04SAlexander Leidinger 	if (rm->last_free_gpr + count <= rm->num_gprs) {
2410d056fa04SAlexander Leidinger 		allocated_gpr = rm->last_free_gpr;
2411d056fa04SAlexander Leidinger 		rm->last_free_gpr += count;
2412d056fa04SAlexander Leidinger 		rm->allocmap[allocated_gpr] = count;
2413d056fa04SAlexander Leidinger 		for (i = 1; i < count; i++)
2414d056fa04SAlexander Leidinger 			rm->allocmap[allocated_gpr + i] = -(count - i);
2415d056fa04SAlexander Leidinger 	} else {
2416d056fa04SAlexander Leidinger 		/* longer */
2417d056fa04SAlexander Leidinger 		i = 0;
2418d056fa04SAlexander Leidinger 		allocated_gpr = rm->num_gprs;
2419d056fa04SAlexander Leidinger 		while (i < rm->last_free_gpr - count) {
2420d056fa04SAlexander Leidinger 			if (rm->allocmap[i] > 0) {
2421d056fa04SAlexander Leidinger 				i += rm->allocmap[i];
2422d056fa04SAlexander Leidinger 			} else {
2423d056fa04SAlexander Leidinger 				allocated_gpr = i;
2424d056fa04SAlexander Leidinger 				for (j = 1; j < count; j++) {
2425d056fa04SAlexander Leidinger 					if (rm->allocmap[i + j] != 0)
2426d056fa04SAlexander Leidinger 						allocated_gpr = rm->num_gprs;
2427d056fa04SAlexander Leidinger 				}
2428d056fa04SAlexander Leidinger 				if (allocated_gpr == i)
2429d056fa04SAlexander Leidinger 					break;
2430d056fa04SAlexander Leidinger 			}
2431d056fa04SAlexander Leidinger 		}
2432d056fa04SAlexander Leidinger 		if (allocated_gpr + count < rm->last_free_gpr) {
2433d056fa04SAlexander Leidinger 			rm->allocmap[allocated_gpr] = count;
2434d056fa04SAlexander Leidinger 			for (i = 1; i < count; i++)
2435d056fa04SAlexander Leidinger 				rm->allocmap[allocated_gpr + i] = -(count - i);
2436d056fa04SAlexander Leidinger 
2437d056fa04SAlexander Leidinger 		}
2438d056fa04SAlexander Leidinger 	}
2439d056fa04SAlexander Leidinger 	if (allocated_gpr == rm->num_gprs)
2440d056fa04SAlexander Leidinger 		allocated_gpr = (-1);
2441d056fa04SAlexander Leidinger 	if (allocated_gpr >= 0)
2442d056fa04SAlexander Leidinger 		rm->num_used += count;
2443d056fa04SAlexander Leidinger 	mtx_unlock(&(rm->gpr_lock));
2444d056fa04SAlexander Leidinger 	return (allocated_gpr);
2445d056fa04SAlexander Leidinger }
2446d056fa04SAlexander Leidinger 
2447d056fa04SAlexander Leidinger /* mixer */
2448d056fa04SAlexander Leidinger void
2449d056fa04SAlexander Leidinger emumix_set_mode(struct emu_sc_info *sc, int mode)
2450d056fa04SAlexander Leidinger {
2451d056fa04SAlexander Leidinger 	uint32_t a_iocfg;
2452d056fa04SAlexander Leidinger 	uint32_t hcfg;
2453d056fa04SAlexander Leidinger 	uint32_t tmp;
2454d056fa04SAlexander Leidinger 
2455d056fa04SAlexander Leidinger 	switch (mode) {
2456d056fa04SAlexander Leidinger 	case MODE_DIGITAL:
2457d056fa04SAlexander Leidinger 		/* FALLTHROUGH */
2458d056fa04SAlexander Leidinger 	case MODE_ANALOG:
2459d056fa04SAlexander Leidinger 		break;
2460d056fa04SAlexander Leidinger 	default:
2461d056fa04SAlexander Leidinger 		return;
2462d056fa04SAlexander Leidinger 	}
2463d056fa04SAlexander Leidinger 
246470e0bbedSPedro F. Giffuni 	hcfg = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE;
2465d056fa04SAlexander Leidinger 	a_iocfg = 0;
2466d056fa04SAlexander Leidinger 
2467d056fa04SAlexander Leidinger 	if (sc->rev >= 6)
246870e0bbedSPedro F. Giffuni 		hcfg |= EMU_HCFG_JOYENABLE;
2469d056fa04SAlexander Leidinger 
2470d056fa04SAlexander Leidinger 	if (sc->is_emu10k1)
247170e0bbedSPedro F. Giffuni 		hcfg |= EMU_HCFG_LOCKTANKCACHE_MASK;
2472d056fa04SAlexander Leidinger 	else
247370e0bbedSPedro F. Giffuni 		hcfg |= EMU_HCFG_CODECFMT_I2S | EMU_HCFG_JOYENABLE;
2474d056fa04SAlexander Leidinger 
2475d056fa04SAlexander Leidinger 
2476d056fa04SAlexander Leidinger 	if (mode == MODE_DIGITAL) {
2477d056fa04SAlexander Leidinger 		if (sc->broken_digital) {
2478b28624fdSAriff Abdullah 			device_printf(sc->dev, "Digital mode is reported as broken on this card.\n");
2479d056fa04SAlexander Leidinger 		}
248070e0bbedSPedro F. Giffuni 		a_iocfg |= EMU_A_IOCFG_GPOUT1;
248170e0bbedSPedro F. Giffuni 		hcfg |= EMU_HCFG_GPOUT0;
2482d056fa04SAlexander Leidinger 	}
2483d056fa04SAlexander Leidinger 
2484d056fa04SAlexander Leidinger 	if (mode == MODE_ANALOG)
2485d056fa04SAlexander Leidinger 		emumix_set_spdif_mode(sc, SPDIF_MODE_PCM);
2486d056fa04SAlexander Leidinger 
2487d056fa04SAlexander Leidinger 	if (sc->is_emu10k2)
2488d056fa04SAlexander Leidinger 		a_iocfg |= 0x80; /* XXX */
2489d056fa04SAlexander Leidinger 
2490d056fa04SAlexander Leidinger 	if ((sc->is_ca0102) || (sc->is_ca0108))
2491b28624fdSAriff Abdullah 		/*
249270e0bbedSPedro F. Giffuni 		 * Setting EMU_A_IOCFG_DISABLE_ANALOG will do opposite things
2493b28624fdSAriff Abdullah 		 * on diffrerent cards.
2494b28624fdSAriff Abdullah 		 * "don't disable analog outs" on Audigy 2 (ca0102/ca0108)
2495b28624fdSAriff Abdullah 		 * "disable analog outs" on Audigy (emu10k2)
2496b28624fdSAriff Abdullah 		 */
249770e0bbedSPedro F. Giffuni 		a_iocfg |= EMU_A_IOCFG_DISABLE_ANALOG;
2498d056fa04SAlexander Leidinger 
2499d056fa04SAlexander Leidinger 	if (sc->is_ca0108)
2500d056fa04SAlexander Leidinger 		a_iocfg |= 0x20; /* XXX */
2501d056fa04SAlexander Leidinger 
2502b28624fdSAriff Abdullah 	/* Mute analog center & subwoofer before mode change */
2503b28624fdSAriff Abdullah 	if (mode == MODE_DIGITAL)
2504b28624fdSAriff Abdullah 		emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 1);
2505b28624fdSAriff Abdullah 
250670e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_HCFG, hcfg, 4);
2507d056fa04SAlexander Leidinger 
2508d056fa04SAlexander Leidinger 	if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
250970e0bbedSPedro F. Giffuni 		tmp = emu_rd(sc, EMU_A_IOCFG, 2);
2510d056fa04SAlexander Leidinger 		tmp = a_iocfg;
251170e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_A_IOCFG, tmp, 2);
2512d056fa04SAlexander Leidinger 	}
2513d056fa04SAlexander Leidinger 
2514b28624fdSAriff Abdullah 	/* Unmute if we have changed mode to analog. */
2515b28624fdSAriff Abdullah 
2516b28624fdSAriff Abdullah 	if (mode == MODE_ANALOG)
2517b28624fdSAriff Abdullah 		emumix_set_gpr(sc, sc->mute_gpr[ANALOGMUTE], 0);
2518b28624fdSAriff Abdullah 
2519b28624fdSAriff Abdullah 	sc->mode = mode;
2520d056fa04SAlexander Leidinger }
2521d056fa04SAlexander Leidinger 
2522d056fa04SAlexander Leidinger void
2523d056fa04SAlexander Leidinger emumix_set_spdif_mode(struct emu_sc_info *sc, int mode)
2524d056fa04SAlexander Leidinger {
2525d056fa04SAlexander Leidinger 	uint32_t spcs;
2526d056fa04SAlexander Leidinger 
2527d056fa04SAlexander Leidinger 	switch (mode) {
2528d056fa04SAlexander Leidinger 	case SPDIF_MODE_PCM:
2529d056fa04SAlexander Leidinger 		break;
2530d056fa04SAlexander Leidinger 	case SPDIF_MODE_AC3:
2531d056fa04SAlexander Leidinger 		device_printf(sc->dev, "AC3 mode does not work and disabled\n");
2532d056fa04SAlexander Leidinger 		return;
2533d056fa04SAlexander Leidinger 	default:
2534d056fa04SAlexander Leidinger 		return;
2535d056fa04SAlexander Leidinger 	}
2536d056fa04SAlexander Leidinger 
253770e0bbedSPedro F. Giffuni 	spcs = EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
253870e0bbedSPedro F. Giffuni 	    EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
253970e0bbedSPedro F. Giffuni 	    EMU_SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 |
254070e0bbedSPedro F. Giffuni 	    EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT;
2541d056fa04SAlexander Leidinger 
2542d056fa04SAlexander Leidinger 	mode = SPDIF_MODE_PCM;
2543d056fa04SAlexander Leidinger 
254470e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SPCS0, spcs);
254570e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SPCS1, spcs);
254670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SPCS2, spcs);
2547d056fa04SAlexander Leidinger }
2548d056fa04SAlexander Leidinger 
2549d056fa04SAlexander Leidinger #define	L2L_POINTS	10
2550d056fa04SAlexander Leidinger 
2551d056fa04SAlexander Leidinger static int l2l_df[L2L_POINTS] = {
2552d056fa04SAlexander Leidinger 	0x572C5CA,		/* 100..90 */
2553d056fa04SAlexander Leidinger 	0x3211625,		/* 90..80 */
2554d056fa04SAlexander Leidinger 	0x1CC1A76,		/* 80..70 */
2555d056fa04SAlexander Leidinger 	0x108428F,		/* 70..60 */
2556d056fa04SAlexander Leidinger 	0x097C70A,		/* 60..50 */
2557d056fa04SAlexander Leidinger 	0x0572C5C,		/* 50..40 */
2558d056fa04SAlexander Leidinger 	0x0321162,		/* 40..30 */
2559d056fa04SAlexander Leidinger 	0x01CC1A7,		/* 30..20 */
2560d056fa04SAlexander Leidinger 	0x0108428,		/* 20..10 */
2561d056fa04SAlexander Leidinger 	0x016493D		/* 10..0 */
2562d056fa04SAlexander Leidinger };
2563d056fa04SAlexander Leidinger 
2564d056fa04SAlexander Leidinger static int l2l_f[L2L_POINTS] = {
2565d056fa04SAlexander Leidinger 	0x4984461A,		/* 90 */
2566d056fa04SAlexander Leidinger 	0x2A3968A7,		/* 80 */
2567d056fa04SAlexander Leidinger 	0x18406003,		/* 70 */
2568d056fa04SAlexander Leidinger 	0x0DEDC66D,		/* 60 */
2569d056fa04SAlexander Leidinger 	0x07FFFFFF,		/* 50 */
2570d056fa04SAlexander Leidinger 	0x04984461,		/* 40 */
2571d056fa04SAlexander Leidinger 	0x02A3968A,		/* 30 */
2572d056fa04SAlexander Leidinger 	0x01840600,		/* 20 */
2573d056fa04SAlexander Leidinger 	0x00DEDC66,		/* 10 */
2574d056fa04SAlexander Leidinger 	0x00000000		/* 0 */
2575d056fa04SAlexander Leidinger };
2576d056fa04SAlexander Leidinger 
2577d056fa04SAlexander Leidinger 
2578d056fa04SAlexander Leidinger static int
2579d056fa04SAlexander Leidinger log2lin(int log_t)
2580d056fa04SAlexander Leidinger {
2581d056fa04SAlexander Leidinger 	int lin_t;
2582d056fa04SAlexander Leidinger 	int idx, lin;
2583d056fa04SAlexander Leidinger 
2584d056fa04SAlexander Leidinger 	if (log_t <= 0) {
2585d056fa04SAlexander Leidinger 		lin_t = 0x00000000;
2586d056fa04SAlexander Leidinger 		return (lin_t);
2587d056fa04SAlexander Leidinger 	}
2588d056fa04SAlexander Leidinger 
2589d056fa04SAlexander Leidinger 	if (log_t >= 100) {
2590d056fa04SAlexander Leidinger 		lin_t = 0x7fffffff;
2591d056fa04SAlexander Leidinger 		return (lin_t);
2592d056fa04SAlexander Leidinger 	}
2593d056fa04SAlexander Leidinger 
2594d056fa04SAlexander Leidinger 	idx = (L2L_POINTS - 1) - log_t / (L2L_POINTS);
2595d056fa04SAlexander Leidinger 	lin = log_t % (L2L_POINTS);
2596d056fa04SAlexander Leidinger 	lin_t = l2l_df[idx] * lin + l2l_f[idx];
2597d056fa04SAlexander Leidinger 	return (lin_t);
2598d056fa04SAlexander Leidinger }
2599d056fa04SAlexander Leidinger 
2600d056fa04SAlexander Leidinger 
2601d056fa04SAlexander Leidinger void
2602d056fa04SAlexander Leidinger emumix_set_fxvol(struct emu_sc_info *sc, unsigned gpr, int32_t vol)
2603d056fa04SAlexander Leidinger {
2604d056fa04SAlexander Leidinger 
2605d056fa04SAlexander Leidinger 	vol = log2lin(vol);
2606d056fa04SAlexander Leidinger 	emumix_set_gpr(sc, gpr, vol);
2607d056fa04SAlexander Leidinger }
2608d056fa04SAlexander Leidinger 
2609d056fa04SAlexander Leidinger void
2610d056fa04SAlexander Leidinger emumix_set_gpr(struct emu_sc_info *sc, unsigned gpr, int32_t val)
2611d056fa04SAlexander Leidinger {
2612b28624fdSAriff Abdullah 	if (sc->dbg_level > 1)
2613b28624fdSAriff Abdullah 		if (gpr == 0) {
2614b28624fdSAriff Abdullah 			device_printf(sc->dev, "Zero gpr write access\n");
2615b28624fdSAriff Abdullah #ifdef KDB
2616b28624fdSAriff Abdullah 			kdb_backtrace();
2617b28624fdSAriff Abdullah #endif
2618b28624fdSAriff Abdullah 			return;
2619b28624fdSAriff Abdullah 			}
2620d056fa04SAlexander Leidinger 
2621d056fa04SAlexander Leidinger 	emu_wrptr(sc, 0, GPR(gpr), val);
2622d056fa04SAlexander Leidinger }
2623d056fa04SAlexander Leidinger 
2624d056fa04SAlexander Leidinger void
2625d056fa04SAlexander Leidinger emumix_set_volume(struct emu_sc_info *sc, int mixer_idx, int volume)
2626d056fa04SAlexander Leidinger {
2627d056fa04SAlexander Leidinger 
2628d056fa04SAlexander Leidinger 	RANGE(volume, 0, 100);
2629d056fa04SAlexander Leidinger 	if (mixer_idx < NUM_MIXERS) {
2630d056fa04SAlexander Leidinger 		sc->mixer_volcache[mixer_idx] = volume;
2631d056fa04SAlexander Leidinger 		emumix_set_fxvol(sc, sc->mixer_gpr[mixer_idx], volume);
2632d056fa04SAlexander Leidinger 	}
2633d056fa04SAlexander Leidinger }
2634d056fa04SAlexander Leidinger 
2635d056fa04SAlexander Leidinger int
2636d056fa04SAlexander Leidinger emumix_get_volume(struct emu_sc_info *sc, int mixer_idx)
2637d056fa04SAlexander Leidinger {
2638d056fa04SAlexander Leidinger 	if ((mixer_idx < NUM_MIXERS) && (mixer_idx >= 0))
2639d056fa04SAlexander Leidinger 		return (sc->mixer_volcache[mixer_idx]);
2640d056fa04SAlexander Leidinger 	return (-1);
2641d056fa04SAlexander Leidinger }
2642d056fa04SAlexander Leidinger 
2643d056fa04SAlexander Leidinger /* Init CardBus part */
2644d056fa04SAlexander Leidinger static int
2645d056fa04SAlexander Leidinger emu_cardbus_init(struct emu_sc_info *sc)
2646d056fa04SAlexander Leidinger {
2647d056fa04SAlexander Leidinger 
2648d056fa04SAlexander Leidinger 	/*
264970e0bbedSPedro F. Giffuni 	 * XXX May not need this if we have EMU_IPR3 handler.
265070e0bbedSPedro F. Giffuni 	 * Is it a real init calls, or EMU_IPR3 interrupt acknowledgments?
2651d056fa04SAlexander Leidinger 	 * Looks much like "(data << 16) | register".
2652d056fa04SAlexander Leidinger 	 */
2653d056fa04SAlexander Leidinger 	emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0000);
2654d056fa04SAlexander Leidinger 	emu_wr_cbptr(sc, (0x00d0 << 16) | 0x0001);
2655d056fa04SAlexander Leidinger 	emu_wr_cbptr(sc, (0x00d0 << 16) | 0x005f);
2656d056fa04SAlexander Leidinger 	emu_wr_cbptr(sc, (0x00d0 << 16) | 0x007f);
2657d056fa04SAlexander Leidinger 
2658d056fa04SAlexander Leidinger 	emu_wr_cbptr(sc, (0x0090 << 16) | 0x007f);
2659d056fa04SAlexander Leidinger 
2660d056fa04SAlexander Leidinger 	return (0);
2661d056fa04SAlexander Leidinger }
2662d056fa04SAlexander Leidinger 
2663d056fa04SAlexander Leidinger /* Probe and attach the card */
2664d056fa04SAlexander Leidinger static int
266555837609SAriff Abdullah emu_init(struct emu_sc_info *sc)
2666d056fa04SAlexander Leidinger {
2667d056fa04SAlexander Leidinger 	uint32_t ch, tmp;
2668d056fa04SAlexander Leidinger 	uint32_t spdif_sr;
2669d056fa04SAlexander Leidinger 	uint32_t ac97slot;
2670d056fa04SAlexander Leidinger 	int def_mode;
2671d056fa04SAlexander Leidinger 	int i;
2672d056fa04SAlexander Leidinger 
2673d056fa04SAlexander Leidinger 	/* disable audio and lock cache */
267470e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4);
2675d056fa04SAlexander Leidinger 
2676d056fa04SAlexander Leidinger 	/* reset recording buffers */
267770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
267870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_MICBA, 0);
267970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
268070e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_FXBA, 0);
268170e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
268270e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_ADCBA, 0);
2683d056fa04SAlexander Leidinger 
2684d056fa04SAlexander Leidinger 	/* disable channel interrupt */
268570e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_INTE, EMU_INTE_INTERTIMERENB | EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE, 4);
268670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_CLIEL, 0);
268770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_CLIEH, 0);
268870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SOLEL, 0);
268970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SOLEH, 0);
2690d056fa04SAlexander Leidinger 
2691d056fa04SAlexander Leidinger 	/* disable P16V and S/PDIF interrupts */
2692d056fa04SAlexander Leidinger 	if ((sc->is_ca0102) || (sc->is_ca0108))
269370e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_INTE2, 0, 4);
2694d056fa04SAlexander Leidinger 
2695d056fa04SAlexander Leidinger 	if (sc->is_ca0102)
269670e0bbedSPedro F. Giffuni 		emu_wr(sc, EMU_INTE3, 0, 4);
2697d056fa04SAlexander Leidinger 
2698d056fa04SAlexander Leidinger 	/* init phys inputs and outputs */
2699d056fa04SAlexander Leidinger 	ac97slot = 0;
2700d056fa04SAlexander Leidinger 	if (sc->has_51)
270170e0bbedSPedro F. Giffuni 		ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE;
2702d056fa04SAlexander Leidinger 	if (sc->has_71)
270370e0bbedSPedro F. Giffuni 		ac97slot = EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE | EMU_AC97SLOT_REAR_LEFT | EMU_AC97SLOT_REAR_RIGHT;
2704d056fa04SAlexander Leidinger 	if (sc->is_emu10k2)
2705d056fa04SAlexander Leidinger 		ac97slot |= 0x40;
270670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_AC97SLOT, ac97slot);
2707d056fa04SAlexander Leidinger 
2708d056fa04SAlexander Leidinger 	if (sc->is_emu10k2)	/* XXX for later cards? */
270970e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_SPBYPASS, 0xf00);	/* What will happen if
2710d056fa04SAlexander Leidinger 							 * we write 1 here? */
2711d056fa04SAlexander Leidinger 
271255837609SAriff Abdullah 	if (bus_dma_tag_create( /* parent */ bus_get_dma_tag(sc->dev),
27130b989078SAlexander Leidinger 	     /* alignment */ 2, /* boundary */ 0,
27141115e138SMarius Strobl 	     /* lowaddr */ (1U << 31) - 1,	/* can only access 0-2gb */
2715d056fa04SAlexander Leidinger 	     /* highaddr */ BUS_SPACE_MAXADDR,
2716d056fa04SAlexander Leidinger 	     /* filter */ NULL, /* filterarg */ NULL,
2717e4c87b14SAlexander Leidinger 	     /* maxsize */ EMU_MAX_BUFSZ, /* nsegments */ 1, /* maxsegz */ 0x3ffff,
2718d056fa04SAlexander Leidinger 	     /* flags */ 0, /* lockfunc */ busdma_lock_mutex,
2719d056fa04SAlexander Leidinger 	     /* lockarg */ &Giant, &(sc->mem.dmat)) != 0) {
2720d056fa04SAlexander Leidinger 		device_printf(sc->dev, "unable to create dma tag\n");
2721d056fa04SAlexander Leidinger 		bus_dma_tag_destroy(sc->mem.dmat);
2722d056fa04SAlexander Leidinger 		return (ENOMEM);
2723d056fa04SAlexander Leidinger 	}
2724d056fa04SAlexander Leidinger 
2725b28624fdSAriff Abdullah 	sc->mem.card = sc;
2726d056fa04SAlexander Leidinger 	SLIST_INIT(&sc->mem.blocks);
2727e4c87b14SAlexander Leidinger 	sc->mem.ptb_pages = emu_malloc(&sc->mem, EMU_MAXPAGES * sizeof(uint32_t), &sc->mem.ptb_pages_addr);
2728d056fa04SAlexander Leidinger 	if (sc->mem.ptb_pages == NULL)
2729d056fa04SAlexander Leidinger 		return (ENOMEM);
2730d056fa04SAlexander Leidinger 
2731d056fa04SAlexander Leidinger 	sc->mem.silent_page = emu_malloc(&sc->mem, EMUPAGESIZE, &sc->mem.silent_page_addr);
2732d056fa04SAlexander Leidinger 	if (sc->mem.silent_page == NULL) {
2733d056fa04SAlexander Leidinger 		emu_free(&sc->mem, sc->mem.ptb_pages);
2734d056fa04SAlexander Leidinger 		return (ENOMEM);
2735d056fa04SAlexander Leidinger 	}
2736d056fa04SAlexander Leidinger 	/* Clear page with silence & setup all pointers to this page */
2737d056fa04SAlexander Leidinger 	bzero(sc->mem.silent_page, EMUPAGESIZE);
2738d056fa04SAlexander Leidinger 	tmp = (uint32_t) (sc->mem.silent_page_addr) << 1;
2739e4c87b14SAlexander Leidinger 	for (i = 0; i < EMU_MAXPAGES; i++)
2740d056fa04SAlexander Leidinger 		sc->mem.ptb_pages[i] = tmp | i;
2741d056fa04SAlexander Leidinger 
2742d056fa04SAlexander Leidinger 	for (ch = 0; ch < NUM_G; ch++) {
274370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_MAPA, tmp | EMU_CHAN_MAP_PTI_MASK);
274470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_MAPB, tmp | EMU_CHAN_MAP_PTI_MASK);
2745d056fa04SAlexander Leidinger 	}
274670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_PTB, (sc->mem.ptb_pages_addr));
274770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_TCB, 0);	/* taken from original driver */
274870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_TCBS, 0);	/* taken from original driver */
2749d056fa04SAlexander Leidinger 
2750d056fa04SAlexander Leidinger 	/* init envelope engine */
2751d056fa04SAlexander Leidinger 	for (ch = 0; ch < NUM_G; ch++) {
275270e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0);
275370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_IP, 0);
275470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0xffff);
275570e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0xffff);
275670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
275770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
275870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CCR, 0);
2759d056fa04SAlexander Leidinger 
276070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_PSST, 0);
276170e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_DSL, 0x10);
276270e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CCCA, 0);
276370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_Z1, 0);
276470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_Z2, 0);
276570e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_FXRT, 0xd01c0000);
2766d056fa04SAlexander Leidinger 
276770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_ATKHLDM, 0);
276870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSM, 0);
276970e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_IFATN, 0xffff);
277070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_PEFE, 0);
277170e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_FMMOD, 0);
277270e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_TREMFRQ, 24);	/* 1 Hz */
277370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_FM2FRQ2, 24);	/* 1 Hz */
277470e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_TEMPENV, 0);
2775d056fa04SAlexander Leidinger 
2776d056fa04SAlexander Leidinger 		/*** these are last so OFF prevents writing ***/
277770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_LFOVAL2, 0);
277870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_LFOVAL1, 0);
277970e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_ATKHLDV, 0);
278070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_ENVVOL, 0);
278170e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_ENVVAL, 0);
2782d056fa04SAlexander Leidinger 
2783d056fa04SAlexander Leidinger 		if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
2784d056fa04SAlexander Leidinger 			emu_wrptr(sc, ch, 0x4c, 0x0);
2785d056fa04SAlexander Leidinger 			emu_wrptr(sc, ch, 0x4d, 0x0);
2786d056fa04SAlexander Leidinger 			emu_wrptr(sc, ch, 0x4e, 0x0);
2787d056fa04SAlexander Leidinger 			emu_wrptr(sc, ch, 0x4f, 0x0);
278870e0bbedSPedro F. Giffuni 			emu_wrptr(sc, ch, EMU_A_CHAN_FXRT1, 0x3f3f3f3f);
278970e0bbedSPedro F. Giffuni 			emu_wrptr(sc, ch, EMU_A_CHAN_FXRT2, 0x3f3f3f3f);
279070e0bbedSPedro F. Giffuni 			emu_wrptr(sc, ch, EMU_A_CHAN_SENDAMOUNTS, 0x0);
2791d056fa04SAlexander Leidinger 		}
2792d056fa04SAlexander Leidinger 	}
2793d056fa04SAlexander Leidinger 
2794d056fa04SAlexander Leidinger 	emumix_set_spdif_mode(sc, SPDIF_MODE_PCM);
2795d056fa04SAlexander Leidinger 
2796d056fa04SAlexander Leidinger 	if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108))
279770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, EMU_A_SPDIF_48000);
2798d056fa04SAlexander Leidinger 
2799d056fa04SAlexander Leidinger 	/*
2800d056fa04SAlexander Leidinger 	 * CAxxxx cards needs additional setup:
2801d056fa04SAlexander Leidinger 	 * 1. Set I2S capture sample rate to 96000
2802d056fa04SAlexander Leidinger 	 * 2. Disable P16v / P17v proceesing
2803d056fa04SAlexander Leidinger 	 * 3. Allow EMU10K DSP inputs
2804d056fa04SAlexander Leidinger 	 */
2805d056fa04SAlexander Leidinger 	if ((sc->is_ca0102) || (sc->is_ca0108)) {
2806d056fa04SAlexander Leidinger 
280770e0bbedSPedro F. Giffuni 		spdif_sr = emu_rdptr(sc, 0, EMU_A_SPDIF_SAMPLERATE);
2808d056fa04SAlexander Leidinger 		spdif_sr &= 0xfffff1ff;
280970e0bbedSPedro F. Giffuni 		spdif_sr |= EMU_A_I2S_CAPTURE_96000;
281070e0bbedSPedro F. Giffuni 		emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, spdif_sr);
2811d056fa04SAlexander Leidinger 
2812d056fa04SAlexander Leidinger 		/* Disable P16v processing */
281370e0bbedSPedro F. Giffuni 		emu_wr_p16vptr(sc, 0, EMU_A2_SRCSel, 0x14);
2814d056fa04SAlexander Leidinger 
2815d056fa04SAlexander Leidinger 		/* Setup P16v/P17v sound routing */
2816d056fa04SAlexander Leidinger 		if (sc->is_ca0102)
281770e0bbedSPedro F. Giffuni 			emu_wr_p16vptr(sc, 0, EMU_A2_SRCMULTI_ENABLE, 0xFF00FF00);
2818d056fa04SAlexander Leidinger 		else {
281970e0bbedSPedro F. Giffuni 			emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_I2S_ENABLE, 0xFF000000);
282070e0bbedSPedro F. Giffuni 			emu_wr_p16vptr(sc, 0, EMU_A2_MIXER_SPDIF_ENABLE, 0xFF000000);
2821d056fa04SAlexander Leidinger 
282270e0bbedSPedro F. Giffuni 			tmp = emu_rd(sc, EMU_A_IOCFG, 2);
282370e0bbedSPedro F. Giffuni 			emu_wr(sc, EMU_A_IOCFG, tmp & ~0x8, 2);
2824d056fa04SAlexander Leidinger 		}
2825d056fa04SAlexander Leidinger 	}
2826d056fa04SAlexander Leidinger 	emu_initefx(sc);
2827d056fa04SAlexander Leidinger 
2828d056fa04SAlexander Leidinger 	def_mode = MODE_ANALOG;
2829d056fa04SAlexander Leidinger 	if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108))
2830d056fa04SAlexander Leidinger 		def_mode = MODE_DIGITAL;
2831d056fa04SAlexander Leidinger 	if (((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) && (sc->broken_digital)) {
2832d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Audigy card initialized in analog mode.\n");
2833d056fa04SAlexander Leidinger 		def_mode = MODE_ANALOG;
2834d056fa04SAlexander Leidinger 	}
2835d056fa04SAlexander Leidinger 	emumix_set_mode(sc, def_mode);
2836d056fa04SAlexander Leidinger 
2837d056fa04SAlexander Leidinger 	if (bootverbose) {
283870e0bbedSPedro F. Giffuni 		tmp = emu_rd(sc, EMU_HCFG, 4);
2839d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Card Configuration (   0x%08x )\n", tmp);
2840d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Card Configuration ( & 0xff000000 ) : %s%s%s%s%s%s%s%s\n",
2841d056fa04SAlexander Leidinger 		    (tmp & 0x80000000 ? "[Legacy MPIC] " : ""),
2842d056fa04SAlexander Leidinger 		    (tmp & 0x40000000 ? "[0x40] " : ""),
2843d056fa04SAlexander Leidinger 		    (tmp & 0x20000000 ? "[0x20] " : ""),
2844d056fa04SAlexander Leidinger 		    (tmp & 0x10000000 ? "[0x10] " : ""),
2845d056fa04SAlexander Leidinger 		    (tmp & 0x08000000 ? "[0x08] " : ""),
2846d056fa04SAlexander Leidinger 		    (tmp & 0x04000000 ? "[0x04] " : ""),
2847d056fa04SAlexander Leidinger 		    (tmp & 0x02000000 ? "[0x02] " : ""),
2848d056fa04SAlexander Leidinger 		    (tmp & 0x01000000 ? "[0x01]" : " "));
2849d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Card Configuration ( & 0x00ff0000 ) : %s%s%s%s%s%s%s%s\n",
2850d056fa04SAlexander Leidinger 		    (tmp & 0x00800000 ? "[0x80] " : ""),
2851d056fa04SAlexander Leidinger 		    (tmp & 0x00400000 ? "[0x40] " : ""),
2852d056fa04SAlexander Leidinger 		    (tmp & 0x00200000 ? "[Legacy INT] " : ""),
2853d056fa04SAlexander Leidinger 		    (tmp & 0x00100000 ? "[0x10] " : ""),
2854d056fa04SAlexander Leidinger 		    (tmp & 0x00080000 ? "[0x08] " : ""),
2855d056fa04SAlexander Leidinger 		    (tmp & 0x00040000 ? "[Codec4] " : ""),
2856d056fa04SAlexander Leidinger 		    (tmp & 0x00020000 ? "[Codec2] " : ""),
2857d056fa04SAlexander Leidinger 		    (tmp & 0x00010000 ? "[I2S Codec]" : " "));
2858d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Card Configuration ( & 0x0000ff00 ) : %s%s%s%s%s%s%s%s\n",
2859d056fa04SAlexander Leidinger 		    (tmp & 0x00008000 ? "[0x80] " : ""),
2860d056fa04SAlexander Leidinger 		    (tmp & 0x00004000 ? "[GPINPUT0] " : ""),
2861d056fa04SAlexander Leidinger 		    (tmp & 0x00002000 ? "[GPINPUT1] " : ""),
2862d056fa04SAlexander Leidinger 		    (tmp & 0x00001000 ? "[GPOUT0] " : ""),
2863d056fa04SAlexander Leidinger 		    (tmp & 0x00000800 ? "[GPOUT1] " : ""),
2864d056fa04SAlexander Leidinger 		    (tmp & 0x00000400 ? "[GPOUT2] " : ""),
2865d056fa04SAlexander Leidinger 		    (tmp & 0x00000200 ? "[Joystick] " : ""),
2866d056fa04SAlexander Leidinger 		    (tmp & 0x00000100 ? "[0x01]" : " "));
2867d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Card Configuration ( & 0x000000ff ) : %s%s%s%s%s%s%s%s\n",
2868d056fa04SAlexander Leidinger 		    (tmp & 0x00000080 ? "[0x80] " : ""),
2869d056fa04SAlexander Leidinger 		    (tmp & 0x00000040 ? "[0x40] " : ""),
2870d056fa04SAlexander Leidinger 		    (tmp & 0x00000020 ? "[0x20] " : ""),
2871d056fa04SAlexander Leidinger 		    (tmp & 0x00000010 ? "[AUTOMUTE] " : ""),
2872d056fa04SAlexander Leidinger 		    (tmp & 0x00000008 ? "[LOCKSOUNDCACHE] " : ""),
2873d056fa04SAlexander Leidinger 		    (tmp & 0x00000004 ? "[LOCKTANKCACHE] " : ""),
2874d056fa04SAlexander Leidinger 		    (tmp & 0x00000002 ? "[MUTEBUTTONENABLE] " : ""),
2875d056fa04SAlexander Leidinger 		    (tmp & 0x00000001 ? "[AUDIOENABLE]" : " "));
2876d056fa04SAlexander Leidinger 
2877d056fa04SAlexander Leidinger 		if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
287870e0bbedSPedro F. Giffuni 			tmp = emu_rd(sc, EMU_A_IOCFG, 2);
2879d056fa04SAlexander Leidinger 			device_printf(sc->dev, "Audigy Card Configuration (    0x%04x )\n", tmp);
2880d056fa04SAlexander Leidinger 			device_printf(sc->dev, "Audigy Card Configuration (  & 0xff00 )");
2881d056fa04SAlexander Leidinger 			printf(" : %s%s%s%s%s%s%s%s\n",
2882d056fa04SAlexander Leidinger 			    (tmp & 0x8000 ? "[Rear Speakers] " : ""),
2883d056fa04SAlexander Leidinger 			    (tmp & 0x4000 ? "[Front Speakers] " : ""),
2884d056fa04SAlexander Leidinger 			    (tmp & 0x2000 ? "[0x20] " : ""),
2885d056fa04SAlexander Leidinger 			    (tmp & 0x1000 ? "[0x10] " : ""),
2886d056fa04SAlexander Leidinger 			    (tmp & 0x0800 ? "[0x08] " : ""),
2887d056fa04SAlexander Leidinger 			    (tmp & 0x0400 ? "[0x04] " : ""),
2888d056fa04SAlexander Leidinger 			    (tmp & 0x0200 ? "[0x02] " : ""),
2889d056fa04SAlexander Leidinger 			    (tmp & 0x0100 ? "[AudigyDrive Phones]" : " "));
2890d056fa04SAlexander Leidinger 			device_printf(sc->dev, "Audigy Card Configuration (  & 0x00ff )");
2891d056fa04SAlexander Leidinger 			printf(" : %s%s%s%s%s%s%s%s\n",
2892d056fa04SAlexander Leidinger 			    (tmp & 0x0080 ? "[0x80] " : ""),
2893d056fa04SAlexander Leidinger 			    (tmp & 0x0040 ? "[Mute AnalogOut] " : ""),
2894d056fa04SAlexander Leidinger 			    (tmp & 0x0020 ? "[0x20] " : ""),
2895d056fa04SAlexander Leidinger 			    (tmp & 0x0010 ? "[0x10] " : ""),
2896d056fa04SAlexander Leidinger 			    (tmp & 0x0008 ? "[0x08] " : ""),
2897d056fa04SAlexander Leidinger 			    (tmp & 0x0004 ? "[GPOUT0] " : ""),
2898d056fa04SAlexander Leidinger 			    (tmp & 0x0002 ? "[GPOUT1] " : ""),
2899d056fa04SAlexander Leidinger 			    (tmp & 0x0001 ? "[GPOUT2]" : " "));
2900d056fa04SAlexander Leidinger 		}		/* is_emu10k2 or ca* */
2901d056fa04SAlexander Leidinger 	}			/* bootverbose */
2902d056fa04SAlexander Leidinger 	return (0);
2903d056fa04SAlexander Leidinger }
2904d056fa04SAlexander Leidinger 
2905d056fa04SAlexander Leidinger static int
2906d056fa04SAlexander Leidinger emu_uninit(struct emu_sc_info *sc)
2907d056fa04SAlexander Leidinger {
2908d056fa04SAlexander Leidinger 	uint32_t ch;
2909d056fa04SAlexander Leidinger 	struct emu_memblk *blk;
2910d056fa04SAlexander Leidinger 
291170e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_INTE, 0, 4);
2912d056fa04SAlexander Leidinger 	for (ch = 0; ch < NUM_G; ch++)
291370e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, 0);
2914d056fa04SAlexander Leidinger 	for (ch = 0; ch < NUM_G; ch++) {
291570e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0);
291670e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0);
291770e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
291870e0bbedSPedro F. Giffuni 		emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
2919d056fa04SAlexander Leidinger 	}
2920d056fa04SAlexander Leidinger 
2921d056fa04SAlexander Leidinger 	/* disable audio and lock cache */
292270e0bbedSPedro F. Giffuni 	emu_wr(sc, EMU_HCFG, EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE, 4);
2923d056fa04SAlexander Leidinger 
292470e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_PTB, 0);
2925d056fa04SAlexander Leidinger 	/* reset recording buffers */
292670e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
292770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_MICBA, 0);
292870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
292970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_FXBA, 0);
293070e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_FXWC, 0);
293170e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
293270e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_ADCBA, 0);
293370e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_TCB, 0);
293470e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_TCBS, 0);
2935d056fa04SAlexander Leidinger 
2936d056fa04SAlexander Leidinger 	/* disable channel interrupt */
293770e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_CLIEL, 0);
293870e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_CLIEH, 0);
293970e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SOLEL, 0);
294070e0bbedSPedro F. Giffuni 	emu_wrptr(sc, 0, EMU_SOLEH, 0);
2941d056fa04SAlexander Leidinger 
2942d056fa04SAlexander Leidinger 	if (!SLIST_EMPTY(&sc->mem.blocks))
2943d056fa04SAlexander Leidinger 		device_printf(sc->dev, "warning: memblock list not empty\n");
2944d056fa04SAlexander Leidinger 
2945d056fa04SAlexander Leidinger 	SLIST_FOREACH(blk, &sc->mem.blocks, link)
2946d056fa04SAlexander Leidinger 		if (blk != NULL)
2947d056fa04SAlexander Leidinger 		device_printf(sc->dev, "lost %d for %s\n", blk->pte_size, blk->owner);
2948d056fa04SAlexander Leidinger 
2949d056fa04SAlexander Leidinger 	emu_free(&sc->mem, sc->mem.ptb_pages);
2950d056fa04SAlexander Leidinger 	emu_free(&sc->mem, sc->mem.silent_page);
2951d056fa04SAlexander Leidinger 
2952d056fa04SAlexander Leidinger 	return (0);
2953d056fa04SAlexander Leidinger }
2954d056fa04SAlexander Leidinger 
2955d056fa04SAlexander Leidinger static int
2956d056fa04SAlexander Leidinger emu_read_ivar(device_t bus, device_t dev, int ivar_index, uintptr_t * result)
2957d056fa04SAlexander Leidinger {
2958d056fa04SAlexander Leidinger 	struct sndcard_func *func = device_get_ivars(dev);
2959d056fa04SAlexander Leidinger 	struct emu_sc_info *sc = device_get_softc(bus);
2960d056fa04SAlexander Leidinger 
2961b28624fdSAriff Abdullah 	if (func==NULL)
2962b28624fdSAriff Abdullah 		return (ENOMEM);
2963b28624fdSAriff Abdullah 	if (sc == NULL)
2964b28624fdSAriff Abdullah 		return (ENOMEM);
2965b28624fdSAriff Abdullah 
2966d056fa04SAlexander Leidinger 	switch (ivar_index) {
2967d056fa04SAlexander Leidinger 	case EMU_VAR_FUNC:
2968d056fa04SAlexander Leidinger 		*result = func->func;
2969d056fa04SAlexander Leidinger 		break;
2970d056fa04SAlexander Leidinger 	case EMU_VAR_ROUTE:
2971b28624fdSAriff Abdullah 		if (func->varinfo == NULL)
2972b28624fdSAriff Abdullah 			return (ENOMEM);
2973d056fa04SAlexander Leidinger 		*result = ((struct emu_pcminfo *)func->varinfo)->route;
2974d056fa04SAlexander Leidinger 		break;
2975d056fa04SAlexander Leidinger 	case EMU_VAR_ISEMU10K1:
2976d056fa04SAlexander Leidinger 		*result = sc->is_emu10k1;
2977d056fa04SAlexander Leidinger 		break;
2978b28624fdSAriff Abdullah 	case EMU_VAR_MCH_DISABLED:
2979b28624fdSAriff Abdullah 		*result = sc->mch_disabled;
2980b28624fdSAriff Abdullah 		break;
2981b28624fdSAriff Abdullah 	case EMU_VAR_MCH_REC:
2982b28624fdSAriff Abdullah 		*result = sc->mch_rec;
2983b28624fdSAriff Abdullah 		break;
2984d056fa04SAlexander Leidinger 	default:
2985d056fa04SAlexander Leidinger 		return (ENOENT);
2986d056fa04SAlexander Leidinger 	}
2987d056fa04SAlexander Leidinger 
2988d056fa04SAlexander Leidinger 	return (0);
2989d056fa04SAlexander Leidinger }
2990d056fa04SAlexander Leidinger 
2991d056fa04SAlexander Leidinger static int
2992d056fa04SAlexander Leidinger emu_write_ivar(device_t bus __unused, device_t dev __unused,
2993d056fa04SAlexander Leidinger     int ivar_index, uintptr_t value __unused)
2994d056fa04SAlexander Leidinger {
2995d056fa04SAlexander Leidinger 
2996d056fa04SAlexander Leidinger 	switch (ivar_index) {
2997d056fa04SAlexander Leidinger 		case 0:
2998d056fa04SAlexander Leidinger 		return (EINVAL);
2999d056fa04SAlexander Leidinger 
3000d056fa04SAlexander Leidinger 	default:
3001d056fa04SAlexander Leidinger 		return (ENOENT);
3002d056fa04SAlexander Leidinger 	}
3003d056fa04SAlexander Leidinger }
3004d056fa04SAlexander Leidinger 
3005d056fa04SAlexander Leidinger static int
3006d056fa04SAlexander Leidinger emu_pci_probe(device_t dev)
3007d056fa04SAlexander Leidinger {
3008d056fa04SAlexander Leidinger 	struct sbuf *s;
3009f856af04SAlexander Leidinger 	unsigned int thiscard = 0;
3010d056fa04SAlexander Leidinger 	uint16_t vendor;
3011d056fa04SAlexander Leidinger 
3012d056fa04SAlexander Leidinger 	vendor = pci_read_config(dev, PCIR_DEVVENDOR, /* bytes */ 2);
3013d056fa04SAlexander Leidinger 	if (vendor != 0x1102)
3014d056fa04SAlexander Leidinger 		return (ENXIO);	/* Not Creative */
3015d056fa04SAlexander Leidinger 
3016d056fa04SAlexander Leidinger 	thiscard = emu_getcard(dev);
3017f856af04SAlexander Leidinger 	if (thiscard == 0)
3018d056fa04SAlexander Leidinger 		return (ENXIO);
3019d056fa04SAlexander Leidinger 
3020d056fa04SAlexander Leidinger 	s = sbuf_new(NULL, NULL, 4096, 0);
3021d056fa04SAlexander Leidinger 	if (s == NULL)
3022d056fa04SAlexander Leidinger 		return (ENOMEM);
3023d056fa04SAlexander Leidinger 	sbuf_printf(s, "Creative %s [%s]", emu_cards[thiscard].desc, emu_cards[thiscard].SBcode);
3024d056fa04SAlexander Leidinger 	sbuf_finish(s);
3025d056fa04SAlexander Leidinger 
3026d056fa04SAlexander Leidinger 	device_set_desc_copy(dev, sbuf_data(s));
3027b28624fdSAriff Abdullah 
3028b28624fdSAriff Abdullah 	sbuf_delete(s);
3029b28624fdSAriff Abdullah 
3030d056fa04SAlexander Leidinger 	return (BUS_PROBE_DEFAULT);
3031d056fa04SAlexander Leidinger }
3032d056fa04SAlexander Leidinger 
3033d056fa04SAlexander Leidinger 
3034d056fa04SAlexander Leidinger static int
3035d056fa04SAlexander Leidinger emu_pci_attach(device_t dev)
3036d056fa04SAlexander Leidinger {
3037d056fa04SAlexander Leidinger 	struct sndcard_func *func;
3038d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
3039d056fa04SAlexander Leidinger 	struct emu_pcminfo *pcminfo;
3040b28624fdSAriff Abdullah #if 0
3041b28624fdSAriff Abdullah 	struct emu_midiinfo *midiinfo;
3042b28624fdSAriff Abdullah #endif
3043d056fa04SAlexander Leidinger 	uint32_t data;
3044d056fa04SAlexander Leidinger 	int i;
3045d056fa04SAlexander Leidinger 	int device_flags;
3046d056fa04SAlexander Leidinger 	char status[255];
3047d056fa04SAlexander Leidinger 	int error = ENXIO;
3048b28624fdSAriff Abdullah 	int unit;
3049d056fa04SAlexander Leidinger 
3050d056fa04SAlexander Leidinger 	sc = device_get_softc(dev);
3051b28624fdSAriff Abdullah 	unit = device_get_unit(dev);
3052b28624fdSAriff Abdullah 
3053b28624fdSAriff Abdullah 	if (resource_disabled("emu10kx", unit)) {
3054b28624fdSAriff Abdullah 		device_printf(dev, "disabled by kernel hints\n");
3055b28624fdSAriff Abdullah 		return (ENXIO); /* XXX to avoid unit reuse */
3056b28624fdSAriff Abdullah 	}
3057b28624fdSAriff Abdullah 
3058b28624fdSAriff Abdullah 	/* Get configuration */
3059b28624fdSAriff Abdullah 
3060b28624fdSAriff Abdullah 	sc->ctx = device_get_sysctl_ctx(dev);
3061b28624fdSAriff Abdullah 	if (sc->ctx == NULL)
3062b28624fdSAriff Abdullah 		goto bad;
3063b28624fdSAriff Abdullah 	sc->root = device_get_sysctl_tree(dev);
3064b28624fdSAriff Abdullah 	if (sc->root == NULL)
3065b28624fdSAriff Abdullah 		goto bad;
3066b28624fdSAriff Abdullah 
3067b28624fdSAriff Abdullah 	if (resource_int_value("emu10kx", unit, "multichannel_disabled", &(sc->mch_disabled)))
3068b28624fdSAriff Abdullah 		RANGE(sc->mch_disabled, 0, 1);
3069b28624fdSAriff Abdullah 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
3070b28624fdSAriff Abdullah 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
3071b28624fdSAriff Abdullah             OID_AUTO, "multichannel_disabled", CTLFLAG_RD, &(sc->mch_disabled), 0, "Multichannel playback setting");
3072b28624fdSAriff Abdullah 
3073b28624fdSAriff Abdullah 	if (resource_int_value("emu10kx", unit, "multichannel_recording", &(sc->mch_rec)))
3074b28624fdSAriff Abdullah 		RANGE(sc->mch_rec, 0, 1);
3075b28624fdSAriff Abdullah 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
3076b28624fdSAriff Abdullah 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
3077b28624fdSAriff Abdullah             OID_AUTO, "multichannel_recording", CTLFLAG_RD,  &(sc->mch_rec), 0, "Multichannel recording setting");
3078b28624fdSAriff Abdullah 
3079b28624fdSAriff Abdullah 	if (resource_int_value("emu10kx", unit, "debug", &(sc->dbg_level)))
3080b28624fdSAriff Abdullah 		RANGE(sc->mch_rec, 0, 2);
3081b28624fdSAriff Abdullah 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
3082b28624fdSAriff Abdullah 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
3083b28624fdSAriff Abdullah             OID_AUTO, "debug", CTLFLAG_RW, &(sc->dbg_level), 0, "Debug level");
3084d056fa04SAlexander Leidinger 
3085d056fa04SAlexander Leidinger 	/* Fill in the softc. */
3086b28624fdSAriff Abdullah 	mtx_init(&sc->lock, device_get_nameunit(dev), "bridge conf", MTX_DEF);
3087b28624fdSAriff Abdullah 	mtx_init(&sc->rw, device_get_nameunit(dev), "exclusive io", MTX_DEF);
3088d056fa04SAlexander Leidinger 	sc->dev = dev;
3089d056fa04SAlexander Leidinger 	sc->type = pci_get_devid(dev);
3090d056fa04SAlexander Leidinger 	sc->rev = pci_get_revid(dev);
3091d056fa04SAlexander Leidinger 	sc->enable_ir = 0;
3092d056fa04SAlexander Leidinger 	sc->has_ac97 = 0;
3093d056fa04SAlexander Leidinger 	sc->has_51 = 0;
3094d056fa04SAlexander Leidinger 	sc->has_71 = 0;
3095d056fa04SAlexander Leidinger 	sc->broken_digital = 0;
3096d056fa04SAlexander Leidinger 	sc->is_emu10k1 = 0;
3097d056fa04SAlexander Leidinger 	sc->is_emu10k2 = 0;
3098d056fa04SAlexander Leidinger 	sc->is_ca0102 = 0;
3099d056fa04SAlexander Leidinger 	sc->is_ca0108 = 0;
3100d056fa04SAlexander Leidinger 	sc->is_cardbus = 0;
3101d056fa04SAlexander Leidinger 
3102d056fa04SAlexander Leidinger 	device_flags = emu_cards[emu_getcard(dev)].flags;
3103d056fa04SAlexander Leidinger 	if (device_flags & HAS_51)
3104d056fa04SAlexander Leidinger 		sc->has_51 = 1;
3105d056fa04SAlexander Leidinger 	if (device_flags & HAS_71) {
3106d056fa04SAlexander Leidinger 		sc->has_51 = 1;
3107d056fa04SAlexander Leidinger 		sc->has_71 = 1;
3108d056fa04SAlexander Leidinger 	}
3109d056fa04SAlexander Leidinger 	if (device_flags & IS_EMU10K1)
3110d056fa04SAlexander Leidinger 		sc->is_emu10k1 = 1;
3111d056fa04SAlexander Leidinger 	if (device_flags & IS_EMU10K2)
3112d056fa04SAlexander Leidinger 		sc->is_emu10k2 = 1;
3113d056fa04SAlexander Leidinger 	if (device_flags & IS_CA0102)
3114d056fa04SAlexander Leidinger 		sc->is_ca0102 = 1;
3115d056fa04SAlexander Leidinger 	if (device_flags & IS_CA0108)
3116d056fa04SAlexander Leidinger 		sc->is_ca0108 = 1;
3117d056fa04SAlexander Leidinger 	if ((sc->is_emu10k2) && (sc->rev == 4)) {
3118d056fa04SAlexander Leidinger 		sc->is_emu10k2 = 0;
3119d056fa04SAlexander Leidinger 		sc->is_ca0102 = 1;	/* for unknown Audigy 2 cards */
3120d056fa04SAlexander Leidinger 	}
3121d056fa04SAlexander Leidinger 	if ((sc->is_ca0102 == 1) || (sc->is_ca0108 == 1))
3122d056fa04SAlexander Leidinger 		if (device_flags & IS_CARDBUS)
3123d056fa04SAlexander Leidinger 			sc->is_cardbus = 1;
3124d056fa04SAlexander Leidinger 
3125d056fa04SAlexander Leidinger 	if ((sc->is_emu10k1 + sc->is_emu10k2 + sc->is_ca0102 + sc->is_ca0108) != 1) {
3126d056fa04SAlexander Leidinger 		device_printf(sc->dev, "Unable to detect HW chipset\n");
3127d056fa04SAlexander Leidinger 		goto bad;
3128d056fa04SAlexander Leidinger 	}
3129d056fa04SAlexander Leidinger 	if (device_flags & BROKEN_DIGITAL)
3130d056fa04SAlexander Leidinger 		sc->broken_digital = 1;
3131d056fa04SAlexander Leidinger 	if (device_flags & HAS_AC97)
3132d056fa04SAlexander Leidinger 		sc->has_ac97 = 1;
3133d056fa04SAlexander Leidinger 
3134d056fa04SAlexander Leidinger 	sc->opcode_shift = 0;
3135d056fa04SAlexander Leidinger 	if ((sc->is_emu10k2) || (sc->is_ca0102) || (sc->is_ca0108)) {
3136d056fa04SAlexander Leidinger 		sc->opcode_shift = 24;
3137d056fa04SAlexander Leidinger 		sc->high_operand_shift = 12;
3138f856af04SAlexander Leidinger 
3139f856af04SAlexander Leidinger 	/*	DSP map				*/
3140f856af04SAlexander Leidinger 	/*	sc->fx_base = 0x0		*/
3141d056fa04SAlexander Leidinger 		sc->input_base = 0x40;
3142d056fa04SAlexander Leidinger 	/*	sc->p16vinput_base = 0x50;	*/
3143d056fa04SAlexander Leidinger 		sc->output_base = 0x60;
3144d056fa04SAlexander Leidinger 		sc->efxc_base = 0x80;
3145d056fa04SAlexander Leidinger 	/*	sc->output32h_base = 0xa0;	*/
3146d056fa04SAlexander Leidinger 	/*	sc->output32l_base = 0xb0;	*/
3147d056fa04SAlexander Leidinger 		sc->dsp_zero = 0xc0;
3148f856af04SAlexander Leidinger 	/*	0xe0...0x100 are unknown	*/
3149f856af04SAlexander Leidinger 	/*	sc->tram_base = 0x200		*/
3150f856af04SAlexander Leidinger 	/*	sc->tram_addr_base = 0x300	*/
315170e0bbedSPedro F. Giffuni 		sc->gpr_base = EMU_A_FXGPREGBASE;
3152f856af04SAlexander Leidinger 		sc->num_gprs = 0x200;
315370e0bbedSPedro F. Giffuni 		sc->code_base = EMU_A_MICROCODEBASE;
3154f856af04SAlexander Leidinger 		sc->code_size = 0x800 / 2;	/* 0x600-0xdff,  2048 words,
3155f856af04SAlexander Leidinger 						 * 1024 instructions */
3156f856af04SAlexander Leidinger 
3157d056fa04SAlexander Leidinger 		sc->mchannel_fx = 8;
3158d056fa04SAlexander Leidinger 		sc->num_fxbuses = 16;
3159d056fa04SAlexander Leidinger 		sc->num_inputs = 8;
3160d056fa04SAlexander Leidinger 		sc->num_outputs = 16;
316170e0bbedSPedro F. Giffuni 		sc->address_mask = EMU_A_PTR_ADDR_MASK;
3162d056fa04SAlexander Leidinger 	}
3163d056fa04SAlexander Leidinger 	if (sc->is_emu10k1) {
3164b28624fdSAriff Abdullah 		sc->has_51 = 0;	/* We don't support 5.1 sound on SB Live! 5.1 */
3165d056fa04SAlexander Leidinger 		sc->opcode_shift = 20;
3166d056fa04SAlexander Leidinger 		sc->high_operand_shift = 10;
316770e0bbedSPedro F. Giffuni 		sc->code_base = EMU_MICROCODEBASE;
3168d056fa04SAlexander Leidinger 		sc->code_size = 0x400 / 2;	/* 0x400-0x7ff,  1024 words,
3169d056fa04SAlexander Leidinger 						 * 512 instructions */
317070e0bbedSPedro F. Giffuni 		sc->gpr_base = EMU_FXGPREGBASE;
3171d056fa04SAlexander Leidinger 		sc->num_gprs = 0x100;
3172d056fa04SAlexander Leidinger 		sc->input_base = 0x10;
3173d056fa04SAlexander Leidinger 		sc->output_base = 0x20;
3174f856af04SAlexander Leidinger 		/*
3175f856af04SAlexander Leidinger 		 * XXX 5.1 Analog outputs are inside efxc address space!
3176f856af04SAlexander Leidinger 		 * They use ouput+0x11/+0x12 (=efxc+1/+2).
3177f856af04SAlexander Leidinger 		 * Don't use this efx registers for recording on SB Live! 5.1!
3178f856af04SAlexander Leidinger 		 */
3179d056fa04SAlexander Leidinger 		sc->efxc_base = 0x30;
3180d056fa04SAlexander Leidinger 		sc->dsp_zero = 0x40;
3181d056fa04SAlexander Leidinger 		sc->mchannel_fx = 0;
3182d056fa04SAlexander Leidinger 		sc->num_fxbuses = 8;
3183d056fa04SAlexander Leidinger 		sc->num_inputs = 8;
3184d056fa04SAlexander Leidinger 		sc->num_outputs = 16;
318570e0bbedSPedro F. Giffuni 		sc->address_mask = EMU_PTR_ADDR_MASK;
3186d056fa04SAlexander Leidinger 	}
3187d056fa04SAlexander Leidinger 	if (sc->opcode_shift == 0)
3188d056fa04SAlexander Leidinger 		goto bad;
3189d056fa04SAlexander Leidinger 
3190d056fa04SAlexander Leidinger 	data = pci_read_config(dev, PCIR_COMMAND, 2);
3191d056fa04SAlexander Leidinger 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
3192d056fa04SAlexander Leidinger 	pci_write_config(dev, PCIR_COMMAND, data, 2);
3193d056fa04SAlexander Leidinger 	data = pci_read_config(dev, PCIR_COMMAND, 2);
3194d056fa04SAlexander Leidinger 
3195d056fa04SAlexander Leidinger 	pci_enable_busmaster(dev);
3196d056fa04SAlexander Leidinger 
3197d056fa04SAlexander Leidinger 	i = PCIR_BAR(0);
3198d056fa04SAlexander Leidinger 	sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE);
3199d056fa04SAlexander Leidinger 	if (sc->reg == NULL) {
3200d056fa04SAlexander Leidinger 		device_printf(dev, "unable to map register space\n");
3201d056fa04SAlexander Leidinger 		goto bad;
3202d056fa04SAlexander Leidinger 	}
3203d056fa04SAlexander Leidinger 	sc->st = rman_get_bustag(sc->reg);
3204d056fa04SAlexander Leidinger 	sc->sh = rman_get_bushandle(sc->reg);
3205d056fa04SAlexander Leidinger 
3206d056fa04SAlexander Leidinger 	for (i = 0; i < EMU_MAX_IRQ_CONSUMERS; i++)
3207d056fa04SAlexander Leidinger 		sc->timer[i] = 0;	/* disable it */
3208d056fa04SAlexander Leidinger 
3209d056fa04SAlexander Leidinger 	i = 0;
3210d056fa04SAlexander Leidinger 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE | RF_SHAREABLE);
321190da2b28SAriff Abdullah 	if ((sc->irq == NULL) || bus_setup_intr(dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV,
321290da2b28SAriff Abdullah #if __FreeBSD_version >= 700031
321390da2b28SAriff Abdullah 	    NULL,
321490da2b28SAriff Abdullah #endif
321590da2b28SAriff Abdullah 	    emu_intr, sc, &sc->ih)) {
3216d056fa04SAlexander Leidinger 		device_printf(dev, "unable to map interrupt\n");
3217d056fa04SAlexander Leidinger 		goto bad;
3218d056fa04SAlexander Leidinger 	}
3219d056fa04SAlexander Leidinger 	if (emu_rm_init(sc) != 0) {
3220d056fa04SAlexander Leidinger 		device_printf(dev, "unable to create resource manager\n");
3221d056fa04SAlexander Leidinger 		goto bad;
3222d056fa04SAlexander Leidinger 	}
3223d056fa04SAlexander Leidinger 	if (sc->is_cardbus)
3224d056fa04SAlexander Leidinger 		if (emu_cardbus_init(sc) != 0) {
3225d056fa04SAlexander Leidinger 			device_printf(dev, "unable to initialize CardBus interface\n");
3226d056fa04SAlexander Leidinger 			goto bad;
3227d056fa04SAlexander Leidinger 		}
3228b28624fdSAriff Abdullah 	if (emu_init(sc) != 0) {
3229d056fa04SAlexander Leidinger 		device_printf(dev, "unable to initialize the card\n");
3230d056fa04SAlexander Leidinger 		goto bad;
3231d056fa04SAlexander Leidinger 	}
3232b28624fdSAriff Abdullah 	if (emu10kx_dev_init(sc) != 0) {
3233d056fa04SAlexander Leidinger 		device_printf(dev, "unable to create control device\n");
3234d056fa04SAlexander Leidinger 		goto bad;
3235d056fa04SAlexander Leidinger 	}
3236d056fa04SAlexander Leidinger 	snprintf(status, 255, "rev %d at io 0x%lx irq %ld", sc->rev, rman_get_start(sc->reg), rman_get_start(sc->irq));
3237d056fa04SAlexander Leidinger 
3238d056fa04SAlexander Leidinger 	/* Voices */
3239d056fa04SAlexander Leidinger 	for (i = 0; i < NUM_G; i++) {
3240d056fa04SAlexander Leidinger 		sc->voice[i].vnum = i;
3241d056fa04SAlexander Leidinger 		sc->voice[i].slave = NULL;
3242d056fa04SAlexander Leidinger 		sc->voice[i].busy = 0;
3243d056fa04SAlexander Leidinger 		sc->voice[i].ismaster = 0;
3244d056fa04SAlexander Leidinger 		sc->voice[i].running = 0;
3245d056fa04SAlexander Leidinger 		sc->voice[i].b16 = 0;
3246d056fa04SAlexander Leidinger 		sc->voice[i].stereo = 0;
3247d056fa04SAlexander Leidinger 		sc->voice[i].speed = 0;
3248d056fa04SAlexander Leidinger 		sc->voice[i].start = 0;
3249d056fa04SAlexander Leidinger 		sc->voice[i].end = 0;
3250d056fa04SAlexander Leidinger 	}
3251d056fa04SAlexander Leidinger 
3252d056fa04SAlexander Leidinger 	/* PCM Audio */
3253b28624fdSAriff Abdullah 	for (i = 0; i < RT_COUNT; i++)
3254b28624fdSAriff Abdullah 		sc->pcm[i] = NULL;
3255b28624fdSAriff Abdullah 
3256d056fa04SAlexander Leidinger 	/* FRONT */
3257d056fa04SAlexander Leidinger 	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3258d056fa04SAlexander Leidinger 	if (func == NULL) {
3259d056fa04SAlexander Leidinger 		error = ENOMEM;
3260d056fa04SAlexander Leidinger 		goto bad;
3261d056fa04SAlexander Leidinger 	}
3262d056fa04SAlexander Leidinger 	pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3263d056fa04SAlexander Leidinger 	if (pcminfo == NULL) {
3264d056fa04SAlexander Leidinger 		error = ENOMEM;
3265d056fa04SAlexander Leidinger 		goto bad;
3266d056fa04SAlexander Leidinger 	}
3267d056fa04SAlexander Leidinger 	pcminfo->card = sc;
3268d056fa04SAlexander Leidinger 	pcminfo->route = RT_FRONT;
3269d056fa04SAlexander Leidinger 
3270d056fa04SAlexander Leidinger 	func->func = SCF_PCM;
3271d056fa04SAlexander Leidinger 	func->varinfo = pcminfo;
3272d056fa04SAlexander Leidinger 	sc->pcm[RT_FRONT] = device_add_child(dev, "pcm", -1);
3273d056fa04SAlexander Leidinger 	device_set_ivars(sc->pcm[RT_FRONT], func);
3274f856af04SAlexander Leidinger 
3275b28624fdSAriff Abdullah 	if (!(sc->mch_disabled)) {
3276d056fa04SAlexander Leidinger 		/* REAR */
3277d056fa04SAlexander Leidinger 		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3278d056fa04SAlexander Leidinger 		if (func == NULL) {
3279d056fa04SAlexander Leidinger 			error = ENOMEM;
3280d056fa04SAlexander Leidinger 			goto bad;
3281d056fa04SAlexander Leidinger 		}
3282d056fa04SAlexander Leidinger 		pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3283d056fa04SAlexander Leidinger 		if (pcminfo == NULL) {
3284d056fa04SAlexander Leidinger 			error = ENOMEM;
3285d056fa04SAlexander Leidinger 			goto bad;
3286d056fa04SAlexander Leidinger 		}
3287d056fa04SAlexander Leidinger 		pcminfo->card = sc;
3288d056fa04SAlexander Leidinger 		pcminfo->route = RT_REAR;
3289d056fa04SAlexander Leidinger 
3290d056fa04SAlexander Leidinger 		func->func = SCF_PCM;
3291d056fa04SAlexander Leidinger 		func->varinfo = pcminfo;
3292d056fa04SAlexander Leidinger 		sc->pcm[RT_REAR] = device_add_child(dev, "pcm", -1);
3293d056fa04SAlexander Leidinger 		device_set_ivars(sc->pcm[RT_REAR], func);
3294d056fa04SAlexander Leidinger 		if (sc->has_51) {
3295d056fa04SAlexander Leidinger 			/* CENTER */
3296d056fa04SAlexander Leidinger 			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3297d056fa04SAlexander Leidinger 			if (func == NULL) {
3298d056fa04SAlexander Leidinger 				error = ENOMEM;
3299d056fa04SAlexander Leidinger 				goto bad;
3300d056fa04SAlexander Leidinger 			}
3301d056fa04SAlexander Leidinger 			pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3302d056fa04SAlexander Leidinger 			if (pcminfo == NULL) {
3303d056fa04SAlexander Leidinger 				error = ENOMEM;
3304d056fa04SAlexander Leidinger 				goto bad;
3305d056fa04SAlexander Leidinger 			}
3306d056fa04SAlexander Leidinger 			pcminfo->card = sc;
3307d056fa04SAlexander Leidinger 			pcminfo->route = RT_CENTER;
3308d056fa04SAlexander Leidinger 
3309d056fa04SAlexander Leidinger 			func->func = SCF_PCM;
3310d056fa04SAlexander Leidinger 			func->varinfo = pcminfo;
3311d056fa04SAlexander Leidinger 			sc->pcm[RT_CENTER] = device_add_child(dev, "pcm", -1);
3312d056fa04SAlexander Leidinger 			device_set_ivars(sc->pcm[RT_CENTER], func);
3313d056fa04SAlexander Leidinger 			/* SUB */
3314d056fa04SAlexander Leidinger 			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3315d056fa04SAlexander Leidinger 			if (func == NULL) {
3316d056fa04SAlexander Leidinger 				error = ENOMEM;
3317d056fa04SAlexander Leidinger 				goto bad;
3318d056fa04SAlexander Leidinger 			}
3319d056fa04SAlexander Leidinger 			pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3320d056fa04SAlexander Leidinger 			if (pcminfo == NULL) {
3321d056fa04SAlexander Leidinger 				error = ENOMEM;
3322d056fa04SAlexander Leidinger 				goto bad;
3323d056fa04SAlexander Leidinger 			}
3324d056fa04SAlexander Leidinger 			pcminfo->card = sc;
3325d056fa04SAlexander Leidinger 			pcminfo->route = RT_SUB;
3326d056fa04SAlexander Leidinger 
3327d056fa04SAlexander Leidinger 			func->func = SCF_PCM;
3328d056fa04SAlexander Leidinger 			func->varinfo = pcminfo;
3329d056fa04SAlexander Leidinger 			sc->pcm[RT_SUB] = device_add_child(dev, "pcm", -1);
3330d056fa04SAlexander Leidinger 			device_set_ivars(sc->pcm[RT_SUB], func);
3331d056fa04SAlexander Leidinger 		}
3332d056fa04SAlexander Leidinger 		if (sc->has_71) {
3333d056fa04SAlexander Leidinger 			/* SIDE */
3334d056fa04SAlexander Leidinger 			func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3335d056fa04SAlexander Leidinger 			if (func == NULL) {
3336d056fa04SAlexander Leidinger 				error = ENOMEM;
3337d056fa04SAlexander Leidinger 				goto bad;
3338d056fa04SAlexander Leidinger 			}
3339d056fa04SAlexander Leidinger 			pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3340d056fa04SAlexander Leidinger 			if (pcminfo == NULL) {
3341d056fa04SAlexander Leidinger 				error = ENOMEM;
3342d056fa04SAlexander Leidinger 				goto bad;
3343d056fa04SAlexander Leidinger 			}
3344d056fa04SAlexander Leidinger 			pcminfo->card = sc;
3345d056fa04SAlexander Leidinger 			pcminfo->route = RT_SIDE;
3346d056fa04SAlexander Leidinger 
3347d056fa04SAlexander Leidinger 			func->func = SCF_PCM;
3348d056fa04SAlexander Leidinger 			func->varinfo = pcminfo;
3349d056fa04SAlexander Leidinger 			sc->pcm[RT_SIDE] = device_add_child(dev, "pcm", -1);
3350d056fa04SAlexander Leidinger 			device_set_ivars(sc->pcm[RT_SIDE], func);
3351b28624fdSAriff Abdullah 		}
3352b28624fdSAriff Abdullah 	} /* mch_disabled */
3353b28624fdSAriff Abdullah 
3354b28624fdSAriff Abdullah 	if (sc->mch_rec) {
3355f856af04SAlexander Leidinger 		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3356f856af04SAlexander Leidinger 		if (func == NULL) {
3357f856af04SAlexander Leidinger 			error = ENOMEM;
3358f856af04SAlexander Leidinger 			goto bad;
3359f856af04SAlexander Leidinger 		}
3360f856af04SAlexander Leidinger 		pcminfo = malloc(sizeof(struct emu_pcminfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3361f856af04SAlexander Leidinger 		if (pcminfo == NULL) {
3362f856af04SAlexander Leidinger 			error = ENOMEM;
3363f856af04SAlexander Leidinger 			goto bad;
3364f856af04SAlexander Leidinger 		}
3365f856af04SAlexander Leidinger 		pcminfo->card = sc;
3366f856af04SAlexander Leidinger 		pcminfo->route = RT_MCHRECORD;
3367f856af04SAlexander Leidinger 
3368f856af04SAlexander Leidinger 		func->func = SCF_PCM;
3369f856af04SAlexander Leidinger 		func->varinfo = pcminfo;
3370f856af04SAlexander Leidinger 		sc->pcm[RT_MCHRECORD] = device_add_child(dev, "pcm", -1);
3371f856af04SAlexander Leidinger 		device_set_ivars(sc->pcm[RT_MCHRECORD], func);
3372b28624fdSAriff Abdullah 	} /*mch_rec */
3373f856af04SAlexander Leidinger 
3374b28624fdSAriff Abdullah 	for (i = 0; i < 2; i++)
3375b28624fdSAriff Abdullah 		sc->midi[i] = NULL;
3376d056fa04SAlexander Leidinger 
3377b28624fdSAriff Abdullah 	/* MIDI has some memory mangament and (possible) locking problems */
3378b28624fdSAriff Abdullah #if 0
3379d056fa04SAlexander Leidinger 	/* Midi Interface 1: Live!, Audigy, Audigy 2 */
3380d056fa04SAlexander Leidinger 	if ((sc->is_emu10k1) || (sc->is_emu10k2) || (sc->is_ca0102)) {
3381d056fa04SAlexander Leidinger 		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3382d056fa04SAlexander Leidinger 		if (func == NULL) {
3383d056fa04SAlexander Leidinger 			error = ENOMEM;
3384d056fa04SAlexander Leidinger 			goto bad;
3385d056fa04SAlexander Leidinger 		}
3386b28624fdSAriff Abdullah 		midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3387b28624fdSAriff Abdullah 		if (midiinfo == NULL) {
3388d056fa04SAlexander Leidinger 			error = ENOMEM;
3389d056fa04SAlexander Leidinger 			goto bad;
3390d056fa04SAlexander Leidinger 		}
3391b28624fdSAriff Abdullah 		midiinfo->card = sc;
3392d056fa04SAlexander Leidinger 		if (sc->is_emu10k2 || (sc->is_ca0102)) {
339370e0bbedSPedro F. Giffuni 			midiinfo->port = EMU_A_MUDATA1;
3394b28624fdSAriff Abdullah 			midiinfo->portnr = 1;
3395d056fa04SAlexander Leidinger 		}
3396d056fa04SAlexander Leidinger 		if (sc->is_emu10k1) {
3397b28624fdSAriff Abdullah 			midiinfo->port = MUDATA;
3398b28624fdSAriff Abdullah 			midiinfo->portnr = 1;
3399d056fa04SAlexander Leidinger 		}
3400d056fa04SAlexander Leidinger 		func->func = SCF_MIDI;
3401b28624fdSAriff Abdullah 		func->varinfo = midiinfo;
3402d056fa04SAlexander Leidinger 		sc->midi[0] = device_add_child(dev, "midi", -1);
3403d056fa04SAlexander Leidinger 		device_set_ivars(sc->midi[0], func);
3404d056fa04SAlexander Leidinger 	}
3405d056fa04SAlexander Leidinger 	/* Midi Interface 2: Audigy, Audigy 2 (on AudigyDrive) */
3406d056fa04SAlexander Leidinger 	if (sc->is_emu10k2 || (sc->is_ca0102)) {
3407d056fa04SAlexander Leidinger 		func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
3408d056fa04SAlexander Leidinger 		if (func == NULL) {
3409d056fa04SAlexander Leidinger 			error = ENOMEM;
3410d056fa04SAlexander Leidinger 			goto bad;
3411d056fa04SAlexander Leidinger 		}
3412b28624fdSAriff Abdullah 		midiinfo = malloc(sizeof(struct emu_midiinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
3413b28624fdSAriff Abdullah 		if (midiinfo == NULL) {
3414d056fa04SAlexander Leidinger 			error = ENOMEM;
3415d056fa04SAlexander Leidinger 			goto bad;
3416d056fa04SAlexander Leidinger 		}
3417b28624fdSAriff Abdullah 		midiinfo->card = sc;
3418d056fa04SAlexander Leidinger 
341970e0bbedSPedro F. Giffuni 		midiinfo->port = EMU_A_MUDATA2;
3420b28624fdSAriff Abdullah 		midiinfo->portnr = 2;
3421d056fa04SAlexander Leidinger 
3422d056fa04SAlexander Leidinger 		func->func = SCF_MIDI;
3423b28624fdSAriff Abdullah 		func->varinfo = midiinfo;
3424d056fa04SAlexander Leidinger 		sc->midi[1] = device_add_child(dev, "midi", -1);
3425d056fa04SAlexander Leidinger 		device_set_ivars(sc->midi[1], func);
3426d056fa04SAlexander Leidinger 	}
3427b28624fdSAriff Abdullah #endif
3428d056fa04SAlexander Leidinger 	return (bus_generic_attach(dev));
3429d056fa04SAlexander Leidinger 
3430d056fa04SAlexander Leidinger bad:
3431d056fa04SAlexander Leidinger 	/* XXX can we just call emu_pci_detach here? */
3432d056fa04SAlexander Leidinger 	if (sc->cdev)
3433d056fa04SAlexander Leidinger 		emu10kx_dev_uninit(sc);
3434d056fa04SAlexander Leidinger 	if (sc->rm != NULL)
3435d056fa04SAlexander Leidinger 		emu_rm_uninit(sc);
3436d056fa04SAlexander Leidinger 	if (sc->reg)
3437d056fa04SAlexander Leidinger 		bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
3438d056fa04SAlexander Leidinger 	if (sc->ih)
3439d056fa04SAlexander Leidinger 		bus_teardown_intr(dev, sc->irq, sc->ih);
3440d056fa04SAlexander Leidinger 	if (sc->irq)
3441d056fa04SAlexander Leidinger 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
3442d056fa04SAlexander Leidinger 	mtx_destroy(&sc->rw);
3443b28624fdSAriff Abdullah 	mtx_destroy(&sc->lock);
3444d056fa04SAlexander Leidinger 	return (error);
3445d056fa04SAlexander Leidinger }
3446d056fa04SAlexander Leidinger 
3447d056fa04SAlexander Leidinger static int
3448d056fa04SAlexander Leidinger emu_pci_detach(device_t dev)
3449d056fa04SAlexander Leidinger {
3450d056fa04SAlexander Leidinger 	struct emu_sc_info *sc;
3451b28624fdSAriff Abdullah 	struct sndcard_func *func;
3452d056fa04SAlexander Leidinger 	int devcount, i;
3453d056fa04SAlexander Leidinger 	device_t *childlist;
3454d056fa04SAlexander Leidinger 	int r = 0;
3455d056fa04SAlexander Leidinger 
3456d056fa04SAlexander Leidinger 	sc = device_get_softc(dev);
3457d056fa04SAlexander Leidinger 
3458f856af04SAlexander Leidinger 	for (i = 0; i < RT_COUNT; i++) {
3459b28624fdSAriff Abdullah 		if (sc->pcm[i] != NULL) {
3460b28624fdSAriff Abdullah 			func = device_get_ivars(sc->pcm[i]);
3461b28624fdSAriff Abdullah 			if (func != NULL && func->func == SCF_PCM) {
3462b28624fdSAriff Abdullah 				device_set_ivars(sc->pcm[i], NULL);
3463b28624fdSAriff Abdullah 				free(func->varinfo, M_DEVBUF);
3464b28624fdSAriff Abdullah 				free(func, M_DEVBUF);
3465d056fa04SAlexander Leidinger 			}
3466b28624fdSAriff Abdullah 			r = device_delete_child(dev, sc->pcm[i]);
3467b28624fdSAriff Abdullah 			if (r)	return (r);
3468b28624fdSAriff Abdullah 		}
3469b28624fdSAriff Abdullah 	}
3470b28624fdSAriff Abdullah 
3471b28624fdSAriff Abdullah 	if (sc->midi[0] != NULL) {
3472b28624fdSAriff Abdullah 		func = device_get_ivars(sc->midi[0]);
3473b28624fdSAriff Abdullah 		if (func != NULL && func->func == SCF_MIDI) {
3474b28624fdSAriff Abdullah 			device_set_ivars(sc->midi[0], NULL);
3475b28624fdSAriff Abdullah 			free(func->varinfo, M_DEVBUF);
3476b28624fdSAriff Abdullah 			free(func, M_DEVBUF);
3477b28624fdSAriff Abdullah 		}
3478d056fa04SAlexander Leidinger 		r = device_delete_child(dev, sc->midi[0]);
3479b28624fdSAriff Abdullah 		if (r)	return (r);
3480b28624fdSAriff Abdullah 	}
3481b28624fdSAriff Abdullah 
3482b28624fdSAriff Abdullah 	if (sc->midi[1] != NULL) {
3483b28624fdSAriff Abdullah 		func = device_get_ivars(sc->midi[1]);
3484b28624fdSAriff Abdullah 		if (func != NULL && func->func == SCF_MIDI) {
3485b28624fdSAriff Abdullah 			device_set_ivars(sc->midi[1], NULL);
3486b28624fdSAriff Abdullah 			free(func->varinfo, M_DEVBUF);
3487b28624fdSAriff Abdullah 			free(func, M_DEVBUF);
3488b28624fdSAriff Abdullah 		}
3489d056fa04SAlexander Leidinger 		r = device_delete_child(dev, sc->midi[1]);
3490b28624fdSAriff Abdullah 		if (r)	return (r);
3491b28624fdSAriff Abdullah 	}
3492b28624fdSAriff Abdullah 
3493b28624fdSAriff Abdullah 	if (device_get_children(dev, &childlist, &devcount) == 0)
3494d056fa04SAlexander Leidinger 		for (i = 0; i < devcount - 1; i++) {
3495d056fa04SAlexander Leidinger 			device_printf(dev, "removing stale child %d (unit %d)\n", i, device_get_unit(childlist[i]));
3496b28624fdSAriff Abdullah 			func = device_get_ivars(childlist[i]);
3497b28624fdSAriff Abdullah 			if (func != NULL && (func->func == SCF_MIDI || func->func == SCF_PCM)) {
3498b28624fdSAriff Abdullah 				device_set_ivars(childlist[i], NULL);
3499b28624fdSAriff Abdullah 				free(func->varinfo, M_DEVBUF);
3500b28624fdSAriff Abdullah 				free(func, M_DEVBUF);
3501b28624fdSAriff Abdullah 			}
3502d056fa04SAlexander Leidinger 			device_delete_child(dev, childlist[i]);
3503d056fa04SAlexander Leidinger 		}
3504b28624fdSAriff Abdullah 	if (childlist != NULL)
3505d056fa04SAlexander Leidinger 		free(childlist, M_TEMP);
3506d056fa04SAlexander Leidinger 
3507d056fa04SAlexander Leidinger 	r = emu10kx_dev_uninit(sc);
3508d056fa04SAlexander Leidinger 	if (r)
3509d056fa04SAlexander Leidinger 		return (r);
3510b28624fdSAriff Abdullah 
3511b28624fdSAriff Abdullah 	/* shutdown chip */
3512b28624fdSAriff Abdullah 	emu_uninit(sc);
3513d056fa04SAlexander Leidinger 	emu_rm_uninit(sc);
351453bc1d83SAriff Abdullah 
351553bc1d83SAriff Abdullah 	if (sc->mem.dmat)
351653bc1d83SAriff Abdullah 		bus_dma_tag_destroy(sc->mem.dmat);
351753bc1d83SAriff Abdullah 
3518d056fa04SAlexander Leidinger 	if (sc->reg)
3519d056fa04SAlexander Leidinger 		bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
3520d056fa04SAlexander Leidinger 	bus_teardown_intr(dev, sc->irq, sc->ih);
3521d056fa04SAlexander Leidinger 	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
3522d056fa04SAlexander Leidinger 	mtx_destroy(&sc->rw);
3523b28624fdSAriff Abdullah 	mtx_destroy(&sc->lock);
3524b28624fdSAriff Abdullah 
3525d056fa04SAlexander Leidinger 	return (bus_generic_detach(dev));
3526d056fa04SAlexander Leidinger }
3527d056fa04SAlexander Leidinger /* add suspend, resume */
3528d056fa04SAlexander Leidinger static device_method_t emu_methods[] = {
3529d056fa04SAlexander Leidinger 	/* Device interface */
3530d056fa04SAlexander Leidinger 	DEVMETHOD(device_probe, emu_pci_probe),
3531d056fa04SAlexander Leidinger 	DEVMETHOD(device_attach, emu_pci_attach),
3532d056fa04SAlexander Leidinger 	DEVMETHOD(device_detach, emu_pci_detach),
3533d056fa04SAlexander Leidinger 	/* Bus methods */
3534d056fa04SAlexander Leidinger 	DEVMETHOD(bus_read_ivar, emu_read_ivar),
3535d056fa04SAlexander Leidinger 	DEVMETHOD(bus_write_ivar, emu_write_ivar),
3536d056fa04SAlexander Leidinger 
3537d056fa04SAlexander Leidinger 	{0, 0}
3538d056fa04SAlexander Leidinger };
3539d056fa04SAlexander Leidinger 
3540d056fa04SAlexander Leidinger 
3541d056fa04SAlexander Leidinger static driver_t emu_driver = {
3542d056fa04SAlexander Leidinger 	"emu10kx",
3543d056fa04SAlexander Leidinger 	emu_methods,
3544d056fa04SAlexander Leidinger 	sizeof(struct emu_sc_info),
3545d056fa04SAlexander Leidinger 	NULL,
3546d056fa04SAlexander Leidinger 	0,
3547d056fa04SAlexander Leidinger 	NULL
3548d056fa04SAlexander Leidinger };
3549d056fa04SAlexander Leidinger 
3550d056fa04SAlexander Leidinger static int
3551d056fa04SAlexander Leidinger emu_modevent(module_t mod __unused, int cmd, void *data __unused)
3552d056fa04SAlexander Leidinger {
3553d056fa04SAlexander Leidinger 	int err = 0;
3554d056fa04SAlexander Leidinger 
3555d056fa04SAlexander Leidinger 	switch (cmd) {
3556d056fa04SAlexander Leidinger 	case MOD_LOAD:
3557d056fa04SAlexander Leidinger 		break;		/* Success */
3558d056fa04SAlexander Leidinger 
3559d056fa04SAlexander Leidinger 	case MOD_UNLOAD:
3560d056fa04SAlexander Leidinger 	case MOD_SHUTDOWN:
3561d056fa04SAlexander Leidinger 
3562d056fa04SAlexander Leidinger 		/* XXX  Should we check state of pcm & midi subdevices here? */
3563d056fa04SAlexander Leidinger 
3564d056fa04SAlexander Leidinger 		break;		/* Success */
3565d056fa04SAlexander Leidinger 
3566d056fa04SAlexander Leidinger 	default:
3567d056fa04SAlexander Leidinger 		err = EINVAL;
3568d056fa04SAlexander Leidinger 		break;
3569d056fa04SAlexander Leidinger 	}
3570d056fa04SAlexander Leidinger 
3571d056fa04SAlexander Leidinger 	return (err);
3572d056fa04SAlexander Leidinger 
3573d056fa04SAlexander Leidinger }
3574d056fa04SAlexander Leidinger 
3575d056fa04SAlexander Leidinger static devclass_t emu_devclass;
3576d056fa04SAlexander Leidinger 
3577d056fa04SAlexander Leidinger DRIVER_MODULE(snd_emu10kx, pci, emu_driver, emu_devclass, emu_modevent, NULL);
3578d056fa04SAlexander Leidinger MODULE_VERSION(snd_emu10kx, SND_EMU10KX_PREFVER);
3579