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