1178481Sjb/*-
2178481Sjb * Copyright (c) 2004 David O'Brien <obrien@FreeBSD.org>
3178481Sjb * Copyright (c) 2003 Orlando Bassotto <orlando.bassotto@ieo-research.it>
4178481Sjb * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5178481Sjb * All rights reserved.
6178481Sjb *
7178481Sjb * Redistribution and use in source and binary forms, with or without
8178481Sjb * modification, are permitted provided that the following conditions
9178481Sjb * are met:
10178481Sjb * 1. Redistributions of source code must retain the above copyright
11178481Sjb *    notice, this list of conditions and the following disclaimer.
12178481Sjb * 2. Redistributions in binary form must reproduce the above copyright
13178481Sjb *    notice, this list of conditions and the following disclaimer in the
14178481Sjb *    documentation and/or other materials provided with the distribution.
15178481Sjb *
16178481Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17178481Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18178481Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19178481Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20178481Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21178481Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22210767Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23178481Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
24178481Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25178481Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26178481Sjb * SUCH DAMAGE.
27178481Sjb */
28178481Sjb
29178481Sjb#ifdef HAVE_KERNEL_OPTION_HEADERS
30178481Sjb#include "opt_snd.h"
31178481Sjb#endif
32178481Sjb
33178481Sjb#include <dev/sound/pcm/sound.h>
34178481Sjb#include <dev/sound/pcm/ac97.h>
35178481Sjb#include <dev/sound/pci/emuxkireg.h>
36178481Sjb
37178481Sjb#include <dev/pci/pcireg.h>
38178481Sjb#include <dev/pci/pcivar.h>
39178481Sjb#include <sys/queue.h>
40178481Sjb
41178481Sjb#include <dev/sound/midi/mpu401.h>
42178481Sjb#include "mpufoi_if.h"
43178481Sjb
44178481SjbSND_DECLARE_FILE("$FreeBSD$");
45178481Sjb
46178481Sjb/* -------------------------------------------------------------------- */
47178481Sjb
48178481Sjb#define	NUM_G		64	/* use all channels */
49178481Sjb#define	WAVEOUT_MAXBUFSIZE 32768
50249656Sed#define	EMUPAGESIZE	4096	/* don't change */
51178481Sjb#define	EMUMAXPAGES	(WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE)
52178481Sjb#define	EMU10K1_PCI_ID	0x00021102	/* 1102 => Creative Labs Vendor ID */
53178481Sjb#define	EMU10K2_PCI_ID	0x00041102
54178481Sjb#define	EMU10K3_PCI_ID	0x00081102
55253678Spfg#define	EMU_DEFAULT_BUFSZ	4096
56253661Spfg#define EMU_MAX_CHANS	8
57178481Sjb#define	EMU_CHANS	4
58178481Sjb
59178481Sjb#define	MAXREQVOICES	8
60178481Sjb#define	RESERVED	0
61178481Sjb#define	NUM_MIDI	16
62178481Sjb#define	NUM_FXSENDS	4
63178481Sjb
64178481Sjb#define	TMEMSIZE	256*1024
65178481Sjb#define	TMEMSIZEREG	4
66178481Sjb
67233407Sgonzo#define	ENABLE		0xffffffff
68233407Sgonzo#define	DISABLE		0x00000000
69233407Sgonzo#define	ENV_ON		EMU_CHAN_DCYSUSV_CHANNELENABLE_MASK
70233407Sgonzo#define	ENV_OFF		0x00	/* XXX: should this be 1? */
71233407Sgonzo
72233407Sgonzo#define	EMU_A_IOCFG_GPOUT_A	0x40
73233407Sgonzo#define	EMU_A_IOCFG_GPOUT_D	0x04
74233407Sgonzo#define	EMU_A_IOCFG_GPOUT_AD (EMU_A_IOCFG_GPOUT_A|EMU_A_IOCFG_GPOUT_D)  /* EMU_A_IOCFG_GPOUT0 */
75233407Sgonzo
76233407Sgonzo#define	EMU_HCFG_GPOUT1		0x00000800
77233407Sgonzo
78233407Sgonzo/* instruction set */
79178481Sjb#define iACC3	 0x06
80178481Sjb#define iMACINT0 0x04
81178546Sjb#define iINTERP  0x0e
82178481Sjb
83178481Sjb#define C_00000000	0x40
84178481Sjb#define C_00000001	0x41
85178481Sjb#define C_00000004	0x44
86178481Sjb#define C_40000000	0x4d
87178481Sjb/* Audigy constants */
88178481Sjb#define A_C_00000000	0xc0
89178481Sjb#define A_C_40000000	0xcd
90178481Sjb
91178481Sjb/* GPRs */
92178481Sjb#define FXBUS(x)	(0x00 + (x))
93178546Sjb#define EXTIN(x)	(0x10 + (x))
94178481Sjb#define EXTOUT(x)	(0x20 + (x))
95178481Sjb
96178481Sjb#define GPR(x)		(EMU_FXGPREGBASE + (x))
97178481Sjb#define A_EXTIN(x)	(0x40 + (x))
98178481Sjb#define A_FXBUS(x)	(0x00 + (x))
99178481Sjb#define A_EXTOUT(x)	(0x60 + (x))
100178481Sjb#define A_GPR(x)	(EMU_A_FXGPREGBASE + (x))
101178481Sjb
102178481Sjb/* FX buses */
103178481Sjb#define FXBUS_PCM_LEFT		0x00
104178546Sjb#define FXBUS_PCM_RIGHT		0x01
105178481Sjb#define FXBUS_MIDI_LEFT		0x04
106178481Sjb#define FXBUS_MIDI_RIGHT	0x05
107178481Sjb#define FXBUS_MIDI_REVERB	0x0c
108178481Sjb#define FXBUS_MIDI_CHORUS	0x0d
109178481Sjb
110178481Sjb/* Inputs */
111178481Sjb#define EXTIN_AC97_L		0x00
112178481Sjb#define EXTIN_AC97_R		0x01
113178481Sjb#define EXTIN_SPDIF_CD_L	0x02
114178481Sjb#define EXTIN_SPDIF_CD_R	0x03
115178546Sjb#define EXTIN_TOSLINK_L		0x06
116178481Sjb#define EXTIN_TOSLINK_R		0x07
117178481Sjb#define EXTIN_COAX_SPDIF_L	0x0a
118178481Sjb#define EXTIN_COAX_SPDIF_R	0x0b
119178481Sjb/* Audigy Inputs */
120178481Sjb#define A_EXTIN_AC97_L		0x00
121178481Sjb#define A_EXTIN_AC97_R		0x01
122178481Sjb
123178546Sjb/* Outputs */
124178481Sjb#define EXTOUT_AC97_L	   0x00
125178481Sjb#define EXTOUT_AC97_R	   0x01
126178481Sjb#define EXTOUT_TOSLINK_L   0x02
127178481Sjb#define EXTOUT_TOSLINK_R   0x03
128178481Sjb#define EXTOUT_AC97_CENTER 0x04
129178546Sjb#define EXTOUT_AC97_LFE	   0x05
130178546Sjb#define EXTOUT_HEADPHONE_L 0x06
131178481Sjb#define EXTOUT_HEADPHONE_R 0x07
132178481Sjb#define EXTOUT_REAR_L	   0x08
133178481Sjb#define EXTOUT_REAR_R	   0x09
134178481Sjb#define EXTOUT_ADC_CAP_L   0x0a
135178481Sjb#define EXTOUT_ADC_CAP_R   0x0b
136178481Sjb#define EXTOUT_ACENTER	   0x11
137178481Sjb#define EXTOUT_ALFE	   0x12
138178481Sjb/* Audigy Outputs */
139178481Sjb#define A_EXTOUT_FRONT_L	0x00
140178481Sjb#define A_EXTOUT_FRONT_R	0x01
141178481Sjb#define A_EXTOUT_CENTER		0x02
142178546Sjb#define A_EXTOUT_LFE		0x03
143178481Sjb#define A_EXTOUT_HEADPHONE_L	0x04
144178481Sjb#define A_EXTOUT_HEADPHONE_R	0x05
145178481Sjb#define A_EXTOUT_REAR_L		0x06
146178481Sjb#define A_EXTOUT_REAR_R		0x07
147178481Sjb#define A_EXTOUT_AFRONT_L	0x08
148178546Sjb#define A_EXTOUT_AFRONT_R	0x09
149178481Sjb#define A_EXTOUT_ACENTER	0x0a
150178546Sjb#define A_EXTOUT_ALFE		0x0b
151178546Sjb#define A_EXTOUT_AREAR_L	0x0e
152178481Sjb#define A_EXTOUT_AREAR_R	0x0f
153178481Sjb#define A_EXTOUT_AC97_L		0x10
154178481Sjb#define A_EXTOUT_AC97_R		0x11
155178481Sjb#define A_EXTOUT_ADC_CAP_L	0x16
156178481Sjb#define A_EXTOUT_ADC_CAP_R	0x17
157233407Sgonzo
158233407Sgonzostruct emu_memblk {
159233407Sgonzo	SLIST_ENTRY(emu_memblk) link;
160233407Sgonzo	void *buf;
161233407Sgonzo	bus_addr_t buf_addr;
162178481Sjb	u_int32_t pte_start, pte_size;
163178481Sjb};
164178481Sjb
165178481Sjbstruct emu_mem {
166178481Sjb	u_int8_t bmap[EMUMAXPAGES / 8];
167178481Sjb	u_int32_t *ptb_pages;
168178481Sjb	void *silent_page;
169178481Sjb	bus_addr_t silent_page_addr;
170178481Sjb	bus_addr_t ptb_pages_addr;
171178481Sjb	SLIST_HEAD(, emu_memblk) blocks;
172178481Sjb};
173178481Sjb
174233407Sgonzostruct emu_voice {
175233407Sgonzo	int vnum;
176233407Sgonzo	unsigned int b16:1, stereo:1, busy:1, running:1, ismaster:1;
177233407Sgonzo	int speed;
178178481Sjb	int start, end, vol;
179178481Sjb	int fxrt1;	/* FX routing */
180178481Sjb	int fxrt2;	/* FX routing (only for audigy) */
181178481Sjb	u_int32_t buf;
182178481Sjb	struct emu_voice *slave;
183178481Sjb	struct pcm_channel *channel;
184178481Sjb};
185178481Sjb
186178481Sjbstruct sc_info;
187178481Sjb
188178481Sjb/* channel registers */
189178481Sjbstruct sc_pchinfo {
190178481Sjb	int spd, fmt, blksz, run;
191178481Sjb	struct emu_voice *master, *slave;
192178481Sjb	struct snd_dbuf *buffer;
193178481Sjb	struct pcm_channel *channel;
194178481Sjb	struct sc_info *parent;
195178481Sjb};
196178481Sjb
197178481Sjbstruct sc_rchinfo {
198210767Srpaulo	int spd, fmt, run, blksz, num;
199210767Srpaulo	u_int32_t idxreg, basereg, sizereg, setupreg, irqmask;
200210767Srpaulo	struct snd_dbuf *buffer;
201210767Srpaulo	struct pcm_channel *channel;
202210767Srpaulo	struct sc_info *parent;
203210767Srpaulo};
204178481Sjb
205178481Sjb/* device private data */
206233407Sgonzostruct sc_info {
207233407Sgonzo	device_t	dev;
208233407Sgonzo	u_int32_t	type, rev;
209233407Sgonzo	u_int32_t	tos_link:1, APS:1, audigy:1, audigy2:1;
210233407Sgonzo	u_int32_t	addrmask;	/* wider if audigy */
211233407Sgonzo
212178481Sjb	bus_space_tag_t st;
213178481Sjb	bus_space_handle_t sh;
214178481Sjb	bus_dma_tag_t parent_dmat;
215178481Sjb
216233407Sgonzo	struct resource *reg, *irq;
217233407Sgonzo	void		*ih;
218233407Sgonzo	struct mtx	*lock;
219233407Sgonzo
220233407Sgonzo	unsigned int bufsz;
221178481Sjb	int timer, timerinterval;
222178481Sjb	int pnum, rnum;
223178481Sjb	int nchans;
224178481Sjb	struct emu_mem mem;
225178481Sjb	struct emu_voice voice[64];
226178481Sjb	struct sc_pchinfo pch[EMU_MAX_CHANS];
227178481Sjb	struct sc_rchinfo rch[3];
228178481Sjb	struct mpu401   *mpu;
229178481Sjb	mpu401_intr_t           *mpu_intr;
230178481Sjb	int mputx;
231178481Sjb};
232178481Sjb
233178481Sjb/* -------------------------------------------------------------------- */
234178481Sjb
235178481Sjb/*
236178481Sjb * prototypes
237178481Sjb */
238178481Sjb
239178481Sjb/* stuff */
240178481Sjbstatic int emu_init(struct sc_info *);
241178481Sjbstatic void emu_intr(void *);
242178481Sjbstatic void *emu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr);
243178481Sjbstatic void *emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr);
244178481Sjbstatic int emu_memfree(struct sc_info *sc, void *buf);
245233407Sgonzostatic int emu_memstart(struct sc_info *sc, void *buf);
246233407Sgonzo#ifdef EMUDEBUG
247233407Sgonzostatic void emu_vdump(struct sc_info *sc, struct emu_voice *v);
248233407Sgonzo#endif
249233407Sgonzo
250233407Sgonzo/* talk to the card */
251233407Sgonzostatic u_int32_t emu_rd(struct sc_info *, int, int);
252178481Sjbstatic void emu_wr(struct sc_info *, int, u_int32_t, int);
253178481Sjb
254178481Sjb/* -------------------------------------------------------------------- */
255178481Sjb
256178481Sjbstatic u_int32_t emu_rfmt_ac97[] = {
257233407Sgonzo	SND_FORMAT(AFMT_S16_LE, 1, 0),
258233407Sgonzo	SND_FORMAT(AFMT_S16_LE, 2, 0),
259233407Sgonzo	0
260233407Sgonzo};
261233407Sgonzo
262233407Sgonzostatic u_int32_t emu_rfmt_mic[] = {
263233407Sgonzo	SND_FORMAT(AFMT_U8, 1, 0),
264178481Sjb	0
265178481Sjb};
266178481Sjb
267178481Sjbstatic u_int32_t emu_rfmt_efx[] = {
268178481Sjb	SND_FORMAT(AFMT_S16_LE, 2, 0),
269178481Sjb	0
270178481Sjb};
271178481Sjb
272178481Sjbstatic struct pcmchan_caps emu_reccaps[3] = {
273233407Sgonzo	{8000, 48000, emu_rfmt_ac97, 0},
274233407Sgonzo	{8000, 8000, emu_rfmt_mic, 0},
275233407Sgonzo	{48000, 48000, emu_rfmt_efx, 0},
276233407Sgonzo};
277233407Sgonzo
278233407Sgonzostatic u_int32_t emu_pfmt[] = {
279178481Sjb	SND_FORMAT(AFMT_U8, 1, 0),
280178481Sjb	SND_FORMAT(AFMT_U8, 2, 0),
281178481Sjb	SND_FORMAT(AFMT_S16_LE, 1, 0),
282178481Sjb	SND_FORMAT(AFMT_S16_LE, 2, 0),
283178546Sjb	0
284178481Sjb};
285178546Sjb
286178546Sjbstatic struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
287178481Sjb
288178481Sjbstatic int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000};
289178481Sjb/* audigy supports 12kHz. */
290178481Sjbstatic int audigy_adcspeed[9] = {
291178481Sjb	48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
292178481Sjb};
293178481Sjb
294178481Sjb/* -------------------------------------------------------------------- */
295178481Sjb/* Hardware */
296178481Sjbstatic u_int32_t
297178481Sjbemu_rd(struct sc_info *sc, int regno, int size)
298178481Sjb{
299178481Sjb	switch (size) {
300178481Sjb	case 1:
301178481Sjb		return bus_space_read_1(sc->st, sc->sh, regno);
302178481Sjb	case 2:
303178481Sjb		return bus_space_read_2(sc->st, sc->sh, regno);
304178481Sjb	case 4:
305178481Sjb		return bus_space_read_4(sc->st, sc->sh, regno);
306178481Sjb	default:
307178481Sjb		return 0xffffffff;
308178481Sjb	}
309178481Sjb}
310178481Sjb
311178481Sjbstatic void
312178481Sjbemu_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
313178481Sjb{
314178481Sjb	switch (size) {
315178481Sjb	case 1:
316178481Sjb		bus_space_write_1(sc->st, sc->sh, regno, data);
317178481Sjb		break;
318178481Sjb	case 2:
319178481Sjb		bus_space_write_2(sc->st, sc->sh, regno, data);
320178481Sjb		break;
321178481Sjb	case 4:
322178481Sjb		bus_space_write_4(sc->st, sc->sh, regno, data);
323178481Sjb		break;
324178481Sjb	}
325178481Sjb}
326178481Sjb
327178481Sjbstatic u_int32_t
328178481Sjbemu_rdptr(struct sc_info *sc, int chn, int reg)
329178481Sjb{
330178481Sjb	u_int32_t ptr, val, mask, size, offset;
331178481Sjb
332178481Sjb	ptr = ((reg << 16) & sc->addrmask) | (chn & EMU_PTR_CHNO_MASK);
333178481Sjb	emu_wr(sc, EMU_PTR, ptr, 4);
334178481Sjb	val = emu_rd(sc, EMU_DATA, 4);
335178481Sjb	if (reg & 0xff000000) {
336178481Sjb		size = (reg >> 24) & 0x3f;
337178481Sjb		offset = (reg >> 16) & 0x1f;
338178481Sjb		mask = ((1 << size) - 1) << offset;
339178481Sjb		val &= mask;
340178481Sjb		val >>= offset;
341178481Sjb	}
342178481Sjb	return val;
343178481Sjb}
344178481Sjb
345178481Sjbstatic void
346178481Sjbemu_wrptr(struct sc_info *sc, int chn, int reg, u_int32_t data)
347178481Sjb{
348178481Sjb	u_int32_t ptr, mask, size, offset;
349178481Sjb
350178481Sjb	ptr = ((reg << 16) & sc->addrmask) | (chn & EMU_PTR_CHNO_MASK);
351178481Sjb	emu_wr(sc, EMU_PTR, ptr, 4);
352178481Sjb	if (reg & 0xff000000) {
353233407Sgonzo		size = (reg >> 24) & 0x3f;
354233407Sgonzo		offset = (reg >> 16) & 0x1f;
355233407Sgonzo		mask = ((1 << size) - 1) << offset;
356178481Sjb		data <<= offset;
357178481Sjb		data &= mask;
358178481Sjb		data |= emu_rd(sc, EMU_DATA, 4) & ~mask;
359178481Sjb	}
360178481Sjb	emu_wr(sc, EMU_DATA, data, 4);
361178481Sjb}
362178481Sjb
363178481Sjbstatic void
364178481Sjbemu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data)
365178481Sjb{
366178481Sjb	pc += sc->audigy ? EMU_A_MICROCODEBASE : EMU_MICROCODEBASE;
367178481Sjb	emu_wrptr(sc, 0, pc, data);
368178481Sjb}
369178481Sjb
370178481Sjb/* -------------------------------------------------------------------- */
371178481Sjb/* ac97 codec */
372233407Sgonzo/* no locking needed */
373233407Sgonzo
374233407Sgonzostatic int
375233407Sgonzoemu_rdcd(kobj_t obj, void *devinfo, int regno)
376233407Sgonzo{
377178481Sjb	struct sc_info *sc = (struct sc_info *)devinfo;
378178481Sjb
379178481Sjb	emu_wr(sc, EMU_AC97ADDR, regno, 1);
380178481Sjb	return emu_rd(sc, EMU_AC97DATA, 2);
381178481Sjb}
382178481Sjb
383178481Sjbstatic int
384178481Sjbemu_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
385210767Srpaulo{
386210767Srpaulo	struct sc_info *sc = (struct sc_info *)devinfo;
387210767Srpaulo
388210767Srpaulo	emu_wr(sc, EMU_AC97ADDR, regno, 1);
389210767Srpaulo	emu_wr(sc, EMU_AC97DATA, data, 2);
390178481Sjb	return 0;
391178481Sjb}
392178481Sjb
393178481Sjbstatic kobj_method_t emu_ac97_methods[] = {
394178481Sjb	KOBJMETHOD(ac97_read,		emu_rdcd),
395178481Sjb	KOBJMETHOD(ac97_write,		emu_wrcd),
396178481Sjb	KOBJMETHOD_END
397178481Sjb};
398178481SjbAC97_DECLARE(emu_ac97);
399178481Sjb
400178481Sjb/* -------------------------------------------------------------------- */
401178481Sjb/* stuff */
402178481Sjbstatic int
403178481Sjbemu_settimer(struct sc_info *sc)
404178481Sjb{
405178481Sjb	struct sc_pchinfo *pch;
406233407Sgonzo	struct sc_rchinfo *rch;
407233407Sgonzo	int i, tmp, rate;
408233407Sgonzo
409233407Sgonzo	rate = 0;
410233407Sgonzo	for (i = 0; i < sc->nchans; i++) {
411178481Sjb		pch = &sc->pch[i];
412178481Sjb		if (pch->buffer) {
413178481Sjb			tmp = (pch->spd * sndbuf_getalign(pch->buffer))
414178481Sjb			    / pch->blksz;
415178481Sjb			if (tmp > rate)
416178481Sjb				rate = tmp;
417178481Sjb		}
418178481Sjb	}
419178481Sjb
420178481Sjb	for (i = 0; i < 3; i++) {
421178481Sjb		rch = &sc->rch[i];
422178481Sjb		if (rch->buffer) {
423178481Sjb			tmp = (rch->spd * sndbuf_getalign(rch->buffer))
424178481Sjb			    / rch->blksz;
425233407Sgonzo			if (tmp > rate)
426233407Sgonzo				rate = tmp;
427233407Sgonzo		}
428233407Sgonzo	}
429233407Sgonzo	RANGE(rate, 48, 9600);
430233407Sgonzo	sc->timerinterval = 48000 / rate;
431233407Sgonzo	emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
432233407Sgonzo
433178481Sjb	return sc->timerinterval;
434178481Sjb}
435178481Sjb
436178481Sjbstatic int
437178481Sjbemu_enatimer(struct sc_info *sc, int go)
438178481Sjb{
439178481Sjb	u_int32_t x;
440178481Sjb	if (go) {
441178481Sjb		if (sc->timer++ == 0) {
442207578Skan			x = emu_rd(sc, EMU_INTE, 4);
443207578Skan			x |= EMU_INTE_INTERTIMERENB;
444207578Skan			emu_wr(sc, EMU_INTE, x, 4);
445207578Skan		}
446207578Skan	} else {
447207578Skan		sc->timer = 0;
448178481Sjb		x = emu_rd(sc, EMU_INTE, 4);
449178481Sjb		x &= ~EMU_INTE_INTERTIMERENB;
450178481Sjb		emu_wr(sc, EMU_INTE, x, 4);
451207578Skan	}
452178481Sjb	return 0;
453178481Sjb}
454178481Sjb
455233407Sgonzostatic void
456233407Sgonzoemu_enastop(struct sc_info *sc, char channel, int enable)
457233407Sgonzo{
458233407Sgonzo	int reg = (channel & 0x20) ? EMU_SOLEH : EMU_SOLEL;
459233407Sgonzo	channel &= 0x1f;
460233407Sgonzo	reg |= 1 << 24;
461178481Sjb	reg |= channel << 16;
462207578Skan	emu_wrptr(sc, 0, reg, enable);
463178481Sjb}
464178481Sjb
465178481Sjbstatic int
466178481Sjbemu_recval(int speed) {
467178481Sjb	int val;
468178481Sjb
469178481Sjb	val = 0;
470178481Sjb	while (val < 7 && speed < adcspeed[val])
471178481Sjb		val++;
472178481Sjb	return val;
473178481Sjb}
474178481Sjb
475178481Sjbstatic int
476178481Sjbaudigy_recval(int speed) {
477178481Sjb	int val;
478178481Sjb
479178481Sjb	val = 0;
480178481Sjb	while (val < 8 && speed < audigy_adcspeed[val])
481178481Sjb		val++;
482178481Sjb	return val;
483178481Sjb}
484178481Sjb
485178481Sjbstatic u_int32_t
486178481Sjbemu_rate_to_pitch(u_int32_t rate)
487178481Sjb{
488178481Sjb	static u_int32_t logMagTable[128] = {
489178481Sjb		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
490178481Sjb		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
491210767Srpaulo		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
492210767Srpaulo		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
493210767Srpaulo		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
494210767Srpaulo		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
495280201Smarkj		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
496210767Srpaulo		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
497210767Srpaulo		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
498210767Srpaulo		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
499178481Sjb		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
500178481Sjb		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
501178481Sjb		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
502178546Sjb		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
503178481Sjb		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
504233407Sgonzo		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
505233407Sgonzo	};
506233407Sgonzo	static char logSlopeTable[128] = {
507233407Sgonzo		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
508233407Sgonzo		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
509178481Sjb		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
510178481Sjb		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
511178481Sjb		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
512178481Sjb		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
513178481Sjb		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
514178481Sjb		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
515178481Sjb		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
516178481Sjb		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
517178481Sjb		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
518178481Sjb		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
519178481Sjb		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
520178481Sjb		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
521178481Sjb		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
522178481Sjb		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
523178481Sjb	};
524178481Sjb	int i;
525178481Sjb
526178481Sjb	if (rate == 0)
527178481Sjb		return 0;	/* Bail out if no leading "1" */
528178481Sjb	rate *= 11185;	/* Scale 48000 to 0x20002380 */
529178481Sjb	for (i = 31; i > 0; i--) {
530178481Sjb		if (rate & 0x80000000) {	/* Detect leading "1" */
531178481Sjb			return (((u_int32_t) (i - 15) << 20) +
532178481Sjb			    logMagTable[0x7f & (rate >> 24)] +
533178481Sjb			    (0x7f & (rate >> 17)) *
534178481Sjb			    logSlopeTable[0x7f & (rate >> 24)]);
535178481Sjb		}
536178481Sjb		rate <<= 1;
537178481Sjb	}
538178481Sjb
539178481Sjb	return 0;		/* Should never reach this point */
540178481Sjb}
541178481Sjb
542178481Sjbstatic u_int32_t
543178481Sjbemu_rate_to_linearpitch(u_int32_t rate)
544178481Sjb{
545178481Sjb	rate = (rate << 8) / 375;
546178481Sjb	return (rate >> 1) + (rate & 1);
547178481Sjb}
548178481Sjb
549178481Sjbstatic struct emu_voice *
550178481Sjbemu_valloc(struct sc_info *sc)
551178481Sjb{
552178481Sjb	struct emu_voice *v;
553178481Sjb	int i;
554178481Sjb
555178481Sjb	v = NULL;
556178481Sjb	for (i = 0; i < 64 && sc->voice[i].busy; i++);
557178481Sjb	if (i < 64) {
558178481Sjb		v = &sc->voice[i];
559178481Sjb		v->busy = 1;
560178481Sjb	}
561178481Sjb	return v;
562178481Sjb}
563178481Sjb
564178481Sjbstatic int
565178481Sjbemu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
566178481Sjb	  u_int32_t sz, struct snd_dbuf *b)
567178481Sjb{
568178481Sjb	void *buf;
569178481Sjb	bus_addr_t tmp_addr;
570178481Sjb
571178481Sjb	buf = emu_memalloc(sc, sz, &tmp_addr);
572178546Sjb	if (buf == NULL)
573178481Sjb		return -1;
574178481Sjb	if (b != NULL)
575178481Sjb		sndbuf_setup(b, buf, sz);
576178481Sjb	m->start = emu_memstart(sc, buf) * EMUPAGESIZE;
577178481Sjb	m->end = m->start + sz;
578178481Sjb	m->channel = NULL;
579178546Sjb	m->speed = 0;
580178481Sjb	m->b16 = 0;
581178481Sjb	m->stereo = 0;
582178481Sjb	m->running = 0;
583178481Sjb	m->ismaster = 1;
584178481Sjb	m->vol = 0xff;
585178481Sjb	m->buf = tmp_addr;
586178481Sjb	m->slave = s;
587178481Sjb	if (sc->audigy) {
588178481Sjb		m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 8 |
589178481Sjb		    FXBUS_PCM_LEFT << 16 | FXBUS_MIDI_REVERB << 24;
590178481Sjb		m->fxrt2 = 0x3f3f3f3f;	/* No effects on second route */
591178481Sjb	} else {
592178481Sjb		m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 4 |
593178481Sjb		    FXBUS_PCM_LEFT << 8 | FXBUS_MIDI_REVERB << 12;
594178481Sjb		m->fxrt2 = 0;
595178481Sjb	}
596178481Sjb
597178481Sjb	if (s != NULL) {
598178481Sjb		s->start = m->start;
599178481Sjb		s->end = m->end;
600178481Sjb		s->channel = NULL;
601178481Sjb		s->speed = 0;
602178481Sjb		s->b16 = 0;
603178481Sjb		s->stereo = 0;
604178481Sjb		s->running = 0;
605178481Sjb		s->ismaster = 0;
606178481Sjb		s->vol = m->vol;
607178481Sjb		s->buf = m->buf;
608178481Sjb		s->fxrt1 = m->fxrt1;
609178481Sjb		s->fxrt2 = m->fxrt2;
610178481Sjb		s->slave = NULL;
611178481Sjb	}
612178481Sjb	return 0;
613178481Sjb}
614178481Sjb
615178481Sjbstatic void
616178481Sjbemu_vsetup(struct sc_pchinfo *ch)
617178481Sjb{
618178481Sjb	struct emu_voice *v = ch->master;
619178481Sjb
620178481Sjb	if (ch->fmt) {
621178481Sjb		v->b16 = (ch->fmt & AFMT_16BIT) ? 1 : 0;
622178481Sjb		v->stereo = (AFMT_CHANNEL(ch->fmt) > 1) ? 1 : 0;
623178481Sjb		if (v->slave != NULL) {
624178481Sjb			v->slave->b16 = v->b16;
625178481Sjb			v->slave->stereo = v->stereo;
626178481Sjb		}
627178481Sjb	}
628178481Sjb	if (ch->spd) {
629178481Sjb		v->speed = ch->spd;
630178481Sjb		if (v->slave != NULL)
631178481Sjb			v->slave->speed = v->speed;
632178481Sjb	}
633178481Sjb}
634178481Sjb
635178481Sjbstatic void
636178481Sjbemu_vwrite(struct sc_info *sc, struct emu_voice *v)
637178481Sjb{
638178481Sjb	int s;
639178481Sjb	int l, r, x, y;
640178481Sjb	u_int32_t sa, ea, start, val, silent_page;
641178546Sjb
642178481Sjb	s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0);
643178481Sjb
644178481Sjb	sa = v->start >> s;
645178481Sjb	ea = v->end >> s;
646178481Sjb
647178481Sjb	l = r = x = y = v->vol;
648178481Sjb	if (v->stereo) {
649178481Sjb		l = v->ismaster ? l : 0;
650178481Sjb		r = v->ismaster ? 0 : r;
651178481Sjb	}
652178481Sjb
653178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, v->stereo ? EMU_CHAN_CPF_STEREO_MASK : 0);
654178481Sjb	val = v->stereo ? 28 : 30;
655178481Sjb	val *= v->b16 ? 1 : 2;
656178481Sjb	start = sa + val;
657178481Sjb
658178481Sjb	if (sc->audigy) {
659178481Sjb		emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT1, v->fxrt1);
660178481Sjb		emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT2, v->fxrt2);
661178481Sjb		emu_wrptr(sc, v->vnum, EMU_A_CHAN_SENDAMOUNTS, 0);
662178481Sjb	}
663178481Sjb	else
664178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_FXRT, v->fxrt1 << 16);
665178481Sjb
666178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX, (x << 8) | r);
667178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_DSL, ea | (y << 24));
668178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_PSST, sa | (l << 24));
669178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_CCCA, start | (v->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT));
670178481Sjb
671178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_Z1, 0);
672178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_Z2, 0);
673178481Sjb
674178481Sjb	silent_page = ((u_int32_t)(sc->mem.silent_page_addr) << 1)
675178481Sjb	    | EMU_CHAN_MAP_PTI_MASK;
676178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_MAPA, silent_page);
677178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_MAPB, silent_page);
678178481Sjb
679178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, EMU_CHAN_CVCF_CURRFILTER_MASK);
680178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, EMU_CHAN_VTFT_FILTERTARGET_MASK);
681178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDM, 0);
682178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSM, EMU_CHAN_DCYSUSM_DECAYTIME_MASK);
683178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL1, 0x8000);
684178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL2, 0x8000);
685178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_FMMOD, 0);
686178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_TREMFRQ, 0);
687178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_FM2FRQ2, 0);
688178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVAL, 0x8000);
689178481Sjb
690178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDV,
691178481Sjb	    EMU_CHAN_ATKHLDV_HOLDTIME_MASK | EMU_CHAN_ATKHLDV_ATTACKTIME_MASK);
692178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVOL, 0x8000);
693178481Sjb
694178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_FILTERAMOUNT, 0x7f);
695178481Sjb	emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_PITCHAMOUNT, 0);
696178481Sjb
697178481Sjb	if (v->slave != NULL)
698178481Sjb		emu_vwrite(sc, v->slave);
699178481Sjb}
700178481Sjb
701178481Sjbstatic void
702233407Sgonzoemu_vtrigger(struct sc_info *sc, struct emu_voice *v, int go)
703233407Sgonzo{
704233407Sgonzo	u_int32_t pitch_target, initial_pitch;
705178481Sjb	u_int32_t cra, cs, ccis;
706178481Sjb	u_int32_t sample, i;
707178481Sjb
708178481Sjb	if (go) {
709178481Sjb		cra = 64;
710178481Sjb		cs = v->stereo ? 4 : 2;
711178481Sjb		ccis = v->stereo ? 28 : 30;
712178481Sjb		ccis *= v->b16 ? 1 : 2;
713178481Sjb		sample = v->b16 ? 0x00000000 : 0x80808080;
714178481Sjb
715178481Sjb		for (i = 0; i < cs; i++)
716178481Sjb			emu_wrptr(sc, v->vnum, EMU_CHAN_CD0 + i, sample);
717178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
718178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_READADDRESS, cra);
719178546Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, ccis);
720178481Sjb
721178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xff00);
722178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0xffffffff);
723178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0xffffffff);
724178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSV, 0x00007f7f);
725178481Sjb		emu_enastop(sc, v->vnum, 0);
726178481Sjb
727178481Sjb		pitch_target = emu_rate_to_linearpitch(v->speed);
728178481Sjb		initial_pitch = emu_rate_to_pitch(v->speed) >> 8;
729178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, pitch_target);
730178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, pitch_target);
731178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_IP, initial_pitch);
732178481Sjb	} else {
733178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, 0);
734178546Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, 0);
735178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xffff);
736178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0x0000ffff);
737178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0x0000ffff);
738178481Sjb		emu_wrptr(sc, v->vnum, EMU_CHAN_IP, 0);
739178481Sjb		emu_enastop(sc, v->vnum, 1);
740178481Sjb	}
741233407Sgonzo	if (v->slave != NULL)
742233407Sgonzo		emu_vtrigger(sc, v->slave, go);
743233407Sgonzo}
744233407Sgonzo
745233407Sgonzostatic int
746233407Sgonzoemu_vpos(struct sc_info *sc, struct emu_voice *v)
747233407Sgonzo{
748233407Sgonzo	int s, ptr;
749233407Sgonzo
750233407Sgonzo	s = (v->b16 ? 1 : 0) + (v->stereo ? 1 : 0);
751233407Sgonzo	ptr = (emu_rdptr(sc, v->vnum, EMU_CHAN_CCCA_CURRADDR) - (v->start >> s)) << s;
752233407Sgonzo	return ptr & ~0x0000001f;
753178481Sjb}
754178481Sjb
755178481Sjb#ifdef EMUDEBUG
756178481Sjbstatic void
757178481Sjbemu_vdump(struct sc_info *sc, struct emu_voice *v)
758178481Sjb{
759178481Sjb	char *regname[] = {
760178481Sjb		"cpf", "ptrx", "cvcf", "vtft", "z2", "z1", "psst", "dsl",
761178481Sjb		"ccca", "ccr", "clp", "fxrt", "mapa", "mapb", NULL, NULL,
762178481Sjb		"envvol", "atkhldv", "dcysusv", "lfoval1",
763178481Sjb		"envval", "atkhldm", "dcysusm", "lfoval2",
764178481Sjb		"ip", "ifatn", "pefe", "fmmod", "tremfrq", "fmfrq2",
765178481Sjb		"tempenv"
766178481Sjb	};
767178546Sjb	char *regname2[] = {
768178481Sjb		"mudata1", "mustat1", "mudata2", "mustat2",
769178481Sjb		"fxwc1", "fxwc2", "spdrate", NULL, NULL,
770178481Sjb		NULL, NULL, NULL, "fxrt2", "sndamnt", "fxrt1",
771178481Sjb		NULL, NULL
772178481Sjb	};
773178481Sjb	int i, x;
774178481Sjb
775178481Sjb	printf("voice number %d\n", v->vnum);
776178481Sjb	for (i = 0, x = 0; i <= 0x1e; i++) {
777178481Sjb		if (regname[i] == NULL)
778178481Sjb			continue;
779178481Sjb		printf("%s\t[%08x]", regname[i], emu_rdptr(sc, v->vnum, i));
780178481Sjb		printf("%s", (x == 2) ? "\n" : "\t");
781178481Sjb		x++;
782178481Sjb		if (x > 2)
783178481Sjb			x = 0;
784178481Sjb	}
785178481Sjb
786178481Sjb	/* Print out audigy extra registers */
787178546Sjb	if (sc->audigy) {
788178546Sjb		for (i = 0; i <= 0xe; i++) {
789178481Sjb			if (regname2[i] == NULL)
790178481Sjb				continue;
791178481Sjb			printf("%s\t[%08x]", regname2[i],
792178481Sjb			    emu_rdptr(sc, v->vnum, i + 0x70));
793178481Sjb			printf("%s", (x == 2)? "\n" : "\t");
794178481Sjb			x++;
795178481Sjb			if (x > 2)
796178481Sjb				x = 0;
797178481Sjb		}
798178481Sjb	}
799178481Sjb	printf("\n\n");
800178481Sjb}
801178481Sjb#endif
802178481Sjb
803178481Sjb/* channel interface */
804178481Sjbstatic void *
805178481Sjbemupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
806178481Sjb    struct pcm_channel *c, int dir)
807178481Sjb{
808178481Sjb	struct sc_info *sc = devinfo;
809178481Sjb	struct sc_pchinfo *ch;
810178481Sjb	void *r;
811178481Sjb
812178481Sjb	KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction"));
813178481Sjb	ch = &sc->pch[sc->pnum++];
814178481Sjb	ch->buffer = b;
815178481Sjb	ch->parent = sc;
816178481Sjb	ch->channel = c;
817178481Sjb	ch->blksz = sc->bufsz / 2;
818178481Sjb	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
819178481Sjb	ch->spd = 8000;
820178481Sjb	snd_mtxlock(sc->lock);
821178481Sjb	ch->master = emu_valloc(sc);
822178481Sjb	ch->slave = emu_valloc(sc);
823178481Sjb	snd_mtxunlock(sc->lock);
824178481Sjb	r = (emu_vinit(sc, ch->master, ch->slave, sc->bufsz, ch->buffer))
825178481Sjb	    ? NULL : ch;
826178481Sjb
827178481Sjb	return r;
828178481Sjb}
829178481Sjb
830178481Sjbstatic int
831178481Sjbemupchan_free(kobj_t obj, void *data)
832178481Sjb{
833178481Sjb	struct sc_pchinfo *ch = data;
834178481Sjb	struct sc_info *sc = ch->parent;
835178481Sjb	int r;
836178481Sjb
837178481Sjb	snd_mtxlock(sc->lock);
838178481Sjb	r = emu_memfree(sc, sndbuf_getbuf(ch->buffer));
839178481Sjb	snd_mtxunlock(sc->lock);
840178481Sjb
841178481Sjb	return r;
842178481Sjb}
843178481Sjb
844178481Sjbstatic int
845178481Sjbemupchan_setformat(kobj_t obj, void *data, u_int32_t format)
846178481Sjb{
847178481Sjb	struct sc_pchinfo *ch = data;
848178481Sjb
849178481Sjb	ch->fmt = format;
850178481Sjb	return 0;
851178481Sjb}
852178481Sjb
853178481Sjbstatic u_int32_t
854178481Sjbemupchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
855178481Sjb{
856178481Sjb	struct sc_pchinfo *ch = data;
857178546Sjb
858178481Sjb	ch->spd = speed;
859178546Sjb	return ch->spd;
860178481Sjb}
861178546Sjb
862178481Sjbstatic u_int32_t
863178481Sjbemupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
864178481Sjb{
865178481Sjb	struct sc_pchinfo *ch = data;
866178481Sjb	struct sc_info *sc = ch->parent;
867178481Sjb	int irqrate, blksz;
868178481Sjb
869178481Sjb	ch->blksz = blocksize;
870178481Sjb	snd_mtxlock(sc->lock);
871178481Sjb	emu_settimer(sc);
872178481Sjb	irqrate = 48000 / sc->timerinterval;
873178481Sjb	snd_mtxunlock(sc->lock);
874178481Sjb	blksz = (ch->spd * sndbuf_getalign(ch->buffer)) / irqrate;
875178481Sjb	return blocksize;
876178481Sjb}
877178481Sjb
878178481Sjbstatic int
879178481Sjbemupchan_trigger(kobj_t obj, void *data, int go)
880178481Sjb{
881178481Sjb	struct sc_pchinfo *ch = data;
882178481Sjb	struct sc_info *sc = ch->parent;
883178481Sjb
884178481Sjb	if (!PCMTRIG_COMMON(go))
885178481Sjb		return 0;
886178481Sjb
887178481Sjb	snd_mtxlock(sc->lock);
888178481Sjb	if (go == PCMTRIG_START) {
889178481Sjb		emu_vsetup(ch);
890178481Sjb		emu_vwrite(sc, ch->master);
891178481Sjb		emu_settimer(sc);
892178481Sjb		emu_enatimer(sc, 1);
893178481Sjb#ifdef EMUDEBUG
894178481Sjb		printf("start [%d bit, %s, %d hz]\n",
895178481Sjb			ch->master->b16 ? 16 : 8,
896178481Sjb			ch->master->stereo ? "stereo" : "mono",
897178481Sjb			ch->master->speed);
898178481Sjb		emu_vdump(sc, ch->master);
899178481Sjb		emu_vdump(sc, ch->slave);
900178481Sjb#endif
901178481Sjb	}
902178481Sjb	ch->run = (go == PCMTRIG_START) ? 1 : 0;
903178481Sjb	emu_vtrigger(sc, ch->master, ch->run);
904178481Sjb	snd_mtxunlock(sc->lock);
905178546Sjb	return 0;
906178546Sjb}
907178481Sjb
908178481Sjbstatic u_int32_t
909178481Sjbemupchan_getptr(kobj_t obj, void *data)
910178481Sjb{
911178481Sjb	struct sc_pchinfo *ch = data;
912178481Sjb	struct sc_info *sc = ch->parent;
913178481Sjb	int r;
914178481Sjb
915178481Sjb	snd_mtxlock(sc->lock);
916178481Sjb	r = emu_vpos(sc, ch->master);
917178481Sjb	snd_mtxunlock(sc->lock);
918178481Sjb
919178481Sjb	return r;
920178481Sjb}
921178481Sjb
922178481Sjbstatic struct pcmchan_caps *
923178481Sjbemupchan_getcaps(kobj_t obj, void *data)
924178481Sjb{
925178481Sjb	return &emu_playcaps;
926178481Sjb}
927178481Sjb
928178481Sjbstatic kobj_method_t emupchan_methods[] = {
929178481Sjb	KOBJMETHOD(channel_init,		emupchan_init),
930178481Sjb	KOBJMETHOD(channel_free,		emupchan_free),
931178481Sjb	KOBJMETHOD(channel_setformat,		emupchan_setformat),
932178481Sjb	KOBJMETHOD(channel_setspeed,		emupchan_setspeed),
933178481Sjb	KOBJMETHOD(channel_setblocksize,	emupchan_setblocksize),
934178481Sjb	KOBJMETHOD(channel_trigger,		emupchan_trigger),
935178481Sjb	KOBJMETHOD(channel_getptr,		emupchan_getptr),
936178481Sjb	KOBJMETHOD(channel_getcaps,		emupchan_getcaps),
937178481Sjb	KOBJMETHOD_END
938178481Sjb};
939178481SjbCHANNEL_DECLARE(emupchan);
940178481Sjb
941178481Sjb/* channel interface */
942178481Sjbstatic void *
943178481Sjbemurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
944178481Sjb    struct pcm_channel *c, int dir)
945178481Sjb{
946178481Sjb	struct sc_info *sc = devinfo;
947178481Sjb	struct sc_rchinfo *ch;
948178481Sjb
949178481Sjb	KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction"));
950178481Sjb	ch = &sc->rch[sc->rnum];
951178481Sjb	ch->buffer = b;
952178481Sjb	ch->parent = sc;
953178546Sjb	ch->channel = c;
954178546Sjb	ch->blksz = sc->bufsz / 2;
955178481Sjb	ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
956178481Sjb	ch->spd = 8000;
957178481Sjb	ch->num = sc->rnum;
958178481Sjb	switch(sc->rnum) {
959178481Sjb	case 0:
960178481Sjb		ch->idxreg = sc->audigy ? EMU_A_ADCIDX : EMU_ADCIDX;
961178481Sjb		ch->basereg = EMU_ADCBA;
962178481Sjb		ch->sizereg = EMU_ADCBS;
963178481Sjb		ch->setupreg = EMU_ADCCR;
964178481Sjb		ch->irqmask = EMU_INTE_ADCBUFENABLE;
965178481Sjb		break;
966178546Sjb
967178546Sjb	case 1:
968178481Sjb		ch->idxreg = EMU_FXIDX;
969178481Sjb		ch->basereg = EMU_FXBA;
970178481Sjb		ch->sizereg = EMU_FXBS;
971178481Sjb		ch->setupreg = EMU_FXWC;
972178481Sjb		ch->irqmask = EMU_INTE_EFXBUFENABLE;
973178481Sjb		break;
974178481Sjb
975178481Sjb	case 2:
976178481Sjb		ch->idxreg = EMU_MICIDX;
977178481Sjb		ch->basereg = EMU_MICBA;
978178481Sjb		ch->sizereg = EMU_MICBS;
979178481Sjb		ch->setupreg = 0;
980178481Sjb		ch->irqmask = EMU_INTE_MICBUFENABLE;
981178481Sjb		break;
982178481Sjb	}
983178481Sjb	sc->rnum++;
984178481Sjb	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0)
985178481Sjb		return NULL;
986178546Sjb	else {
987178546Sjb		snd_mtxlock(sc->lock);
988178481Sjb		emu_wrptr(sc, 0, ch->basereg, sndbuf_getbufaddr(ch->buffer));
989178481Sjb		emu_wrptr(sc, 0, ch->sizereg, 0); /* off */
990178481Sjb		snd_mtxunlock(sc->lock);
991178481Sjb		return ch;
992178481Sjb	}
993178481Sjb}
994178481Sjb
995178481Sjbstatic int
996178481Sjbemurchan_setformat(kobj_t obj, void *data, u_int32_t format)
997178481Sjb{
998178481Sjb	struct sc_rchinfo *ch = data;
999178481Sjb
1000178481Sjb	ch->fmt = format;
1001178481Sjb	return 0;
1002178481Sjb}
1003178481Sjb
1004178481Sjbstatic u_int32_t
1005178481Sjbemurchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1006178481Sjb{
1007178481Sjb	struct sc_rchinfo *ch = data;
1008178481Sjb
1009178481Sjb	if (ch->num == 0) {
1010178481Sjb		if (ch->parent->audigy)
1011178481Sjb			speed = audigy_adcspeed[audigy_recval(speed)];
1012178481Sjb		else
1013178481Sjb			speed = adcspeed[emu_recval(speed)];
1014178481Sjb	}
1015178481Sjb	if (ch->num == 1)
1016178481Sjb		speed = 48000;
1017178481Sjb	if (ch->num == 2)
1018178481Sjb		speed = 8000;
1019178481Sjb	ch->spd = speed;
1020178481Sjb	return ch->spd;
1021178481Sjb}
1022178481Sjb
1023178481Sjbstatic u_int32_t
1024178481Sjbemurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1025178481Sjb{
1026178481Sjb	struct sc_rchinfo *ch = data;
1027178481Sjb	struct sc_info *sc = ch->parent;
1028178481Sjb	int irqrate, blksz;
1029178481Sjb
1030178481Sjb	ch->blksz = blocksize;
1031178481Sjb	snd_mtxlock(sc->lock);
1032178481Sjb	emu_settimer(sc);
1033178481Sjb	irqrate = 48000 / sc->timerinterval;
1034178481Sjb	snd_mtxunlock(sc->lock);
1035178481Sjb	blksz = (ch->spd * sndbuf_getalign(ch->buffer)) / irqrate;
1036178481Sjb	return blocksize;
1037178481Sjb}
1038178481Sjb
1039178481Sjb/* semantic note: must start at beginning of buffer */
1040178481Sjbstatic int
1041178481Sjbemurchan_trigger(kobj_t obj, void *data, int go)
1042178481Sjb{
1043178481Sjb	struct sc_rchinfo *ch = data;
1044178481Sjb	struct sc_info *sc = ch->parent;
1045178481Sjb	u_int32_t val, sz;
1046178481Sjb
1047178546Sjb	if (!PCMTRIG_COMMON(go))
1048178546Sjb		return 0;
1049178481Sjb
1050178481Sjb	switch(sc->bufsz) {
1051178481Sjb	case 4096:
1052178481Sjb		sz = EMU_RECBS_BUFSIZE_4096;
1053178481Sjb		break;
1054178481Sjb
1055178481Sjb	case 8192:
1056178481Sjb		sz = EMU_RECBS_BUFSIZE_8192;
1057210767Srpaulo		break;
1058178481Sjb
1059178481Sjb	case 16384:
1060178481Sjb		sz = EMU_RECBS_BUFSIZE_16384;
1061178481Sjb		break;
1062178481Sjb
1063178481Sjb	case 32768:
1064178481Sjb		sz = EMU_RECBS_BUFSIZE_32768;
1065178481Sjb		break;
1066178481Sjb
1067178481Sjb	case 65536:
1068178481Sjb		sz = EMU_RECBS_BUFSIZE_65536;
1069178481Sjb		break;
1070178481Sjb
1071178481Sjb	default:
1072178546Sjb		sz = EMU_RECBS_BUFSIZE_4096;
1073178546Sjb	}
1074178481Sjb
1075178481Sjb	snd_mtxlock(sc->lock);
1076178481Sjb	switch(go) {
1077178481Sjb	case PCMTRIG_START:
1078178481Sjb		ch->run = 1;
1079178481Sjb		emu_wrptr(sc, 0, ch->sizereg, sz);
1080178481Sjb		if (ch->num == 0) {
1081178481Sjb			if (sc->audigy) {
1082178481Sjb				val = EMU_A_ADCCR_LCHANENABLE;
1083178481Sjb				if (AFMT_CHANNEL(ch->fmt) > 1)
1084178481Sjb					val |= EMU_A_ADCCR_RCHANENABLE;
1085178481Sjb				val |= audigy_recval(ch->spd);
1086178481Sjb			} else {
1087178481Sjb				val = EMU_ADCCR_LCHANENABLE;
1088178481Sjb				if (AFMT_CHANNEL(ch->fmt) > 1)
1089178481Sjb					val |= EMU_ADCCR_RCHANENABLE;
1090178481Sjb				val |= emu_recval(ch->spd);
1091178481Sjb			}
1092178481Sjb
1093178481Sjb			emu_wrptr(sc, 0, ch->setupreg, 0);
1094178481Sjb			emu_wrptr(sc, 0, ch->setupreg, val);
1095178481Sjb		}
1096178481Sjb		val = emu_rd(sc, EMU_INTE, 4);
1097178481Sjb		val |= ch->irqmask;
1098178481Sjb		emu_wr(sc, EMU_INTE, val, 4);
1099178546Sjb		break;
1100178546Sjb
1101178481Sjb	case PCMTRIG_STOP:
1102178481Sjb	case PCMTRIG_ABORT:
1103178481Sjb		ch->run = 0;
1104178481Sjb		emu_wrptr(sc, 0, ch->sizereg, 0);
1105178481Sjb		if (ch->setupreg)
1106178481Sjb			emu_wrptr(sc, 0, ch->setupreg, 0);
1107178481Sjb		val = emu_rd(sc, EMU_INTE, 4);
1108178481Sjb		val &= ~ch->irqmask;
1109178481Sjb		emu_wr(sc, EMU_INTE, val, 4);
1110178481Sjb		break;
1111178481Sjb
1112178481Sjb	case PCMTRIG_EMLDMAWR:
1113178481Sjb	case PCMTRIG_EMLDMARD:
1114178481Sjb	default:
1115178481Sjb		break;
1116178481Sjb	}
1117178481Sjb	snd_mtxunlock(sc->lock);
1118178481Sjb
1119178481Sjb	return 0;
1120178546Sjb}
1121178546Sjb
1122178481Sjbstatic u_int32_t
1123178481Sjbemurchan_getptr(kobj_t obj, void *data)
1124178481Sjb{
1125178481Sjb	struct sc_rchinfo *ch = data;
1126178481Sjb	struct sc_info *sc = ch->parent;
1127178481Sjb	int r;
1128178481Sjb
1129178481Sjb	snd_mtxlock(sc->lock);
1130178481Sjb	r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff;
1131178481Sjb	snd_mtxunlock(sc->lock);
1132178481Sjb
1133178481Sjb	return r;
1134178481Sjb}
1135178481Sjb
1136178481Sjbstatic struct pcmchan_caps *
1137178481Sjbemurchan_getcaps(kobj_t obj, void *data)
1138178546Sjb{
1139178546Sjb	struct sc_rchinfo *ch = data;
1140178481Sjb
1141178481Sjb	return &emu_reccaps[ch->num];
1142178481Sjb}
1143178481Sjb
1144178481Sjbstatic kobj_method_t emurchan_methods[] = {
1145178481Sjb	KOBJMETHOD(channel_init,		emurchan_init),
1146178481Sjb	KOBJMETHOD(channel_setformat,		emurchan_setformat),
1147178481Sjb	KOBJMETHOD(channel_setspeed,		emurchan_setspeed),
1148253661Spfg	KOBJMETHOD(channel_setblocksize,	emurchan_setblocksize),
1149253661Spfg	KOBJMETHOD(channel_trigger,		emurchan_trigger),
1150253661Spfg	KOBJMETHOD(channel_getptr,		emurchan_getptr),
1151253661Spfg	KOBJMETHOD(channel_getcaps,		emurchan_getcaps),
1152178481Sjb	KOBJMETHOD_END
1153178481Sjb};
1154178481SjbCHANNEL_DECLARE(emurchan);
1155178481Sjb
1156178546Sjbstatic unsigned char
1157178546Sjbemu_mread(struct mpu401 *arg, void *sc, int reg)
1158178481Sjb{
1159178481Sjb	unsigned int d;
1160178481Sjb
1161178481Sjb	d = emu_rd((struct sc_info *)sc, 0x18 + reg, 1);
1162178481Sjb	return d;
1163178481Sjb}
1164178481Sjb
1165178481Sjbstatic void
1166178481Sjbemu_mwrite(struct mpu401 *arg, void *sc, int reg, unsigned char b)
1167178481Sjb{
1168253661Spfg
1169253661Spfg	emu_wr((struct sc_info *)sc, 0x18 + reg, b, 1);
1170253661Spfg}
1171253661Spfg
1172178481Sjbstatic int
1173178481Sjbemu_muninit(struct mpu401 *arg, void *cookie)
1174178481Sjb{
1175178481Sjb	struct sc_info *sc = cookie;
1176178481Sjb
1177178481Sjb	snd_mtxlock(sc->lock);
1178178481Sjb	sc->mpu_intr = 0;
1179178481Sjb	snd_mtxunlock(sc->lock);
1180178481Sjb
1181178481Sjb	return 0;
1182178481Sjb}
1183178481Sjb
1184178546Sjbstatic kobj_method_t emu_mpu_methods[] = {
1185178546Sjb    	KOBJMETHOD(mpufoi_read,		emu_mread),
1186178481Sjb    	KOBJMETHOD(mpufoi_write,	emu_mwrite),
1187178481Sjb    	KOBJMETHOD(mpufoi_uninit,	emu_muninit),
1188178481Sjb	KOBJMETHOD_END
1189178481Sjb};
1190178481Sjb
1191178481Sjbstatic DEFINE_CLASS(emu_mpu, emu_mpu_methods, 0);
1192178481Sjb
1193178481Sjbstatic void
1194178481Sjbemu_intr2(void *p)
1195178481Sjb{
1196178481Sjb	struct sc_info *sc = (struct sc_info *)p;
1197178481Sjb
1198178481Sjb	if (sc->mpu_intr)
1199178481Sjb	    (sc->mpu_intr)(sc->mpu);
1200178481Sjb}
1201178481Sjb
1202178481Sjbstatic void
1203178481Sjbemu_midiattach(struct sc_info *sc)
1204178481Sjb{
1205178481Sjb	int i;
1206178481Sjb
1207178481Sjb	i = emu_rd(sc, EMU_INTE, 4);
1208178481Sjb	i |= EMU_INTE_MIDIRXENABLE;
1209178481Sjb	emu_wr(sc, EMU_INTE, i, 4);
1210178481Sjb
1211178481Sjb	sc->mpu = mpu401_init(&emu_mpu_class, sc, emu_intr2, &sc->mpu_intr);
1212178481Sjb}
1213178481Sjb/* -------------------------------------------------------------------- */
1214178481Sjb/* The interrupt handler */
1215178481Sjb
1216178481Sjbstatic void
1217178481Sjbemu_intr(void *data)
1218178481Sjb{
1219178481Sjb	struct sc_info *sc = data;
1220178546Sjb	u_int32_t stat, ack, i, x;
1221178546Sjb
1222178481Sjb	snd_mtxlock(sc->lock);
1223178481Sjb	while (1) {
1224178481Sjb		stat = emu_rd(sc, EMU_IPR, 4);
1225178481Sjb		if (stat == 0)
1226178481Sjb			break;
1227178481Sjb		ack = 0;
1228178481Sjb
1229178546Sjb		/* process irq */
1230178546Sjb		if (stat & EMU_IPR_INTERVALTIMER)
1231178481Sjb			ack |= EMU_IPR_INTERVALTIMER;
1232178481Sjb
1233178481Sjb		if (stat & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL))
1234178481Sjb			ack |= stat & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL);
1235178481Sjb
1236178481Sjb		if (stat & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL))
1237178481Sjb			ack |= stat & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL);
1238178481Sjb
1239178481Sjb		if (stat & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL))
1240178481Sjb			ack |= stat & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL);
1241178481Sjb
1242178481Sjb		if (stat & EMU_PCIERROR) {
1243178481Sjb			ack |= EMU_PCIERROR;
1244178481Sjb			device_printf(sc->dev, "pci error\n");
1245178481Sjb			/* we still get an nmi with ecc ram even if we ack this */
1246178481Sjb		}
1247178481Sjb		if (stat & EMU_IPR_RATETRCHANGE) {
1248178481Sjb			ack |= EMU_IPR_RATETRCHANGE;
1249178481Sjb#ifdef EMUDEBUG
1250178481Sjb			device_printf(sc->dev,
1251178481Sjb			    "sample rate tracker lock status change\n");
1252178481Sjb#endif
1253178481Sjb		}
1254178481Sjb
1255178481Sjb	    if (stat & EMU_IPR_MIDIRECVBUFE)
1256178481Sjb		if (sc->mpu_intr) {
1257178481Sjb		    (sc->mpu_intr)(sc->mpu);
1258178481Sjb		    ack |= EMU_IPR_MIDIRECVBUFE | EMU_IPR_MIDITRANSBUFE;
1259178481Sjb 		}
1260178481Sjb		if (stat & ~ack)
1261178481Sjb			device_printf(sc->dev, "dodgy irq: %x (harmless)\n",
1262178481Sjb			    stat & ~ack);
1263178481Sjb
1264178481Sjb		emu_wr(sc, EMU_IPR, stat, 4);
1265178481Sjb
1266178481Sjb		if (ack) {
1267178481Sjb			snd_mtxunlock(sc->lock);
1268178481Sjb
1269178481Sjb			if (ack & EMU_IPR_INTERVALTIMER) {
1270178481Sjb				x = 0;
1271178481Sjb				for (i = 0; i < sc->nchans; i++) {
1272178481Sjb					if (sc->pch[i].run) {
1273178481Sjb						x = 1;
1274178481Sjb						chn_intr(sc->pch[i].channel);
1275178481Sjb					}
1276178481Sjb				}
1277178481Sjb				if (x == 0)
1278178481Sjb					emu_enatimer(sc, 0);
1279178481Sjb			}
1280178481Sjb
1281178481Sjb
1282178481Sjb			if (ack & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL)) {
1283178481Sjb				if (sc->rch[0].channel)
1284178481Sjb					chn_intr(sc->rch[0].channel);
1285178481Sjb			}
1286178481Sjb			if (ack & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL)) {
1287253661Spfg				if (sc->rch[1].channel)
1288253661Spfg					chn_intr(sc->rch[1].channel);
1289178481Sjb			}
1290178481Sjb			if (ack & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL)) {
1291178481Sjb				if (sc->rch[2].channel)
1292178481Sjb					chn_intr(sc->rch[2].channel);
1293178481Sjb			}
1294178481Sjb
1295178481Sjb			snd_mtxlock(sc->lock);
1296178481Sjb		}
1297178481Sjb	}
1298178481Sjb	snd_mtxunlock(sc->lock);
1299178481Sjb}
1300178481Sjb
1301178481Sjb/* -------------------------------------------------------------------- */
1302178481Sjb
1303178481Sjbstatic void
1304178481Sjbemu_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1305178481Sjb{
1306178481Sjb	bus_addr_t *phys = arg;
1307178481Sjb
1308178481Sjb	*phys = error ? 0 : (bus_addr_t)segs->ds_addr;
1309178481Sjb
1310178481Sjb	if (bootverbose) {
1311178481Sjb		printf("emu: setmap (%lx, %lx), nseg=%d, error=%d\n",
1312178481Sjb		    (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
1313178481Sjb		    nseg, error);
1314178481Sjb	}
1315178481Sjb}
1316178481Sjb
1317178481Sjbstatic void *
1318178481Sjbemu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr)
1319178481Sjb{
1320178481Sjb	void *buf;
1321178481Sjb	bus_dmamap_t map;
1322178481Sjb
1323178481Sjb	*addr = 0;
1324178481Sjb	if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map))
1325178481Sjb		return NULL;
1326178481Sjb	if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, emu_setmap, addr, 0)
1327178481Sjb	    || !*addr)
1328178481Sjb		return NULL;
1329178481Sjb	return buf;
1330178481Sjb}
1331178481Sjb
1332178546Sjbstatic void
1333178481Sjbemu_free(struct sc_info *sc, void *buf)
1334178481Sjb{
1335178481Sjb	bus_dmamem_free(sc->parent_dmat, buf, NULL);
1336178481Sjb}
1337178481Sjb
1338178481Sjbstatic void *
1339178481Sjbemu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr)
1340178481Sjb{
1341178481Sjb	u_int32_t blksz, start, idx, ofs, tmp, found;
1342178481Sjb	struct emu_mem *mem = &sc->mem;
1343178481Sjb	struct emu_memblk *blk;
1344178481Sjb	void *buf;
1345178481Sjb
1346178481Sjb	blksz = sz / EMUPAGESIZE;
1347178481Sjb	if (sz > (blksz * EMUPAGESIZE))
1348178481Sjb		blksz++;
1349178481Sjb	/* find a free block in the bitmap */
1350178481Sjb	found = 0;
1351178481Sjb	start = 1;
1352178481Sjb	while (!found && start + blksz < EMUMAXPAGES) {
1353178481Sjb		found = 1;
1354178481Sjb		for (idx = start; idx < start + blksz; idx++)
1355178481Sjb			if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
1356178481Sjb				found = 0;
1357178481Sjb		if (!found)
1358178481Sjb			start++;
1359178481Sjb	}
1360178481Sjb	if (!found)
1361178546Sjb		return NULL;
1362178546Sjb	blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT);
1363178481Sjb	if (blk == NULL)
1364178481Sjb		return NULL;
1365178481Sjb	buf = emu_malloc(sc, sz, &blk->buf_addr);
1366178481Sjb	*addr = blk->buf_addr;
1367178481Sjb	if (buf == NULL) {
1368178481Sjb		free(blk, M_DEVBUF);
1369178481Sjb		return NULL;
1370178481Sjb	}
1371178481Sjb	blk->buf = buf;
1372178481Sjb	blk->pte_start = start;
1373178481Sjb	blk->pte_size = blksz;
1374178481Sjb#ifdef EMUDEBUG
1375178481Sjb	printf("buf %p, pte_start %d, pte_size %d\n", blk->buf,
1376178481Sjb	    blk->pte_start, blk->pte_size);
1377178481Sjb#endif
1378178481Sjb	ofs = 0;
1379178481Sjb	for (idx = start; idx < start + blksz; idx++) {
1380178481Sjb		mem->bmap[idx >> 3] |= 1 << (idx & 7);
1381178481Sjb		tmp = (uint32_t)(blk->buf_addr + ofs);
1382178481Sjb#ifdef EMUDEBUG
1383178481Sjb		printf("pte[%d] -> %x phys, %x virt\n", idx, tmp,
1384178481Sjb		    ((u_int32_t)buf) + ofs);
1385178481Sjb#endif
1386178481Sjb		mem->ptb_pages[idx] = (tmp << 1) | idx;
1387178481Sjb		ofs += EMUPAGESIZE;
1388178481Sjb	}
1389178481Sjb	SLIST_INSERT_HEAD(&mem->blocks, blk, link);
1390178481Sjb	return buf;
1391178481Sjb}
1392178481Sjb
1393178481Sjbstatic int
1394178481Sjbemu_memfree(struct sc_info *sc, void *buf)
1395178481Sjb{
1396	u_int32_t idx, tmp;
1397	struct emu_mem *mem = &sc->mem;
1398	struct emu_memblk *blk, *i;
1399
1400	blk = NULL;
1401	SLIST_FOREACH(i, &mem->blocks, link) {
1402		if (i->buf == buf)
1403			blk = i;
1404	}
1405	if (blk == NULL)
1406		return EINVAL;
1407	SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link);
1408	emu_free(sc, buf);
1409	tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1;
1410	for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) {
1411		mem->bmap[idx >> 3] &= ~(1 << (idx & 7));
1412		mem->ptb_pages[idx] = tmp | idx;
1413	}
1414	free(blk, M_DEVBUF);
1415	return 0;
1416}
1417
1418static int
1419emu_memstart(struct sc_info *sc, void *buf)
1420{
1421	struct emu_mem *mem = &sc->mem;
1422	struct emu_memblk *blk, *i;
1423
1424	blk = NULL;
1425	SLIST_FOREACH(i, &mem->blocks, link) {
1426		if (i->buf == buf)
1427			blk = i;
1428	}
1429	if (blk == NULL)
1430		return -EINVAL;
1431	return blk->pte_start;
1432}
1433
1434static void
1435emu_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
1436    u_int32_t *pc)
1437{
1438	emu_wrefx(sc, (*pc) * 2, (x << 10) | y);
1439	emu_wrefx(sc, (*pc) * 2 + 1, (op << 20) | (z << 10) | w);
1440	(*pc)++;
1441}
1442
1443static void
1444audigy_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
1445    u_int32_t *pc)
1446{
1447	emu_wrefx(sc, (*pc) * 2, (x << 12) | y);
1448	emu_wrefx(sc, (*pc) * 2 + 1, (op << 24) | (z << 12) | w);
1449	(*pc)++;
1450}
1451
1452static void
1453audigy_initefx(struct sc_info *sc)
1454{
1455	int i;
1456	u_int32_t pc = 0;
1457
1458	/* skip 0, 0, -1, 0 - NOPs */
1459	for (i = 0; i < 512; i++)
1460		audigy_addefxop(sc, 0x0f, 0x0c0, 0x0c0, 0x0cf, 0x0c0, &pc);
1461
1462	for (i = 0; i < 512; i++)
1463		emu_wrptr(sc, 0, EMU_A_FXGPREGBASE + i, 0x0);
1464
1465	pc = 16;
1466
1467	/* stop fx processor */
1468	emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
1469
1470	/* Audigy 2 (EMU10K2) DSP Registers:
1471	   FX Bus
1472		0x000-0x00f : 16 registers (?)
1473	   Input
1474		0x040/0x041 : AC97 Codec (l/r)
1475		0x042/0x043 : ADC, S/PDIF (l/r)
1476		0x044/0x045 : Optical S/PDIF in (l/r)
1477		0x046/0x047 : ?
1478		0x048/0x049 : Line/Mic 2 (l/r)
1479		0x04a/0x04b : RCA S/PDIF (l/r)
1480		0x04c/0x04d : Aux 2 (l/r)
1481	   Output
1482		0x060/0x061 : Digital Front (l/r)
1483		0x062/0x063 : Digital Center/LFE
1484		0x064/0x065 : AudigyDrive Heaphone (l/r)
1485		0x066/0x067 : Digital Rear (l/r)
1486		0x068/0x069 : Analog Front (l/r)
1487		0x06a/0x06b : Analog Center/LFE
1488		0x06c/0x06d : ?
1489		0x06e/0x06f : Analog Rear (l/r)
1490		0x070/0x071 : AC97 Output (l/r)
1491		0x072/0x073 : ?
1492		0x074/0x075 : ?
1493		0x076/0x077 : ADC Recording Buffer (l/r)
1494	   Constants
1495		0x0c0 - 0x0c4 = 0 - 4
1496		0x0c5 = 0x8, 0x0c6 = 0x10, 0x0c7 = 0x20
1497		0x0c8 = 0x100, 0x0c9 = 0x10000, 0x0ca = 0x80000
1498		0x0cb = 0x10000000, 0x0cc = 0x20000000, 0x0cd = 0x40000000
1499		0x0ce = 0x80000000, 0x0cf = 0x7fffffff, 0x0d0 = 0xffffffff
1500		0x0d1 = 0xfffffffe, 0x0d2 = 0xc0000000, 0x0d3 = 0x41fbbcdc
1501		0x0d4 = 0x5a7ef9db, 0x0d5 = 0x00100000, 0x0dc = 0x00000001 (?)
1502	   Temporary Values
1503		0x0d6 : Accumulator (?)
1504		0x0d7 : Condition Register
1505		0x0d8 : Noise source
1506		0x0d9 : Noise source
1507	   Tank Memory Data Registers
1508		0x200 - 0x2ff
1509	   Tank Memory Address Registers
1510		0x300 - 0x3ff
1511	   General Purpose Registers
1512		0x400 - 0x5ff
1513	 */
1514
1515	/* AC97Output[l/r] = FXBus PCM[l/r] */
1516	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_L), A_C_00000000,
1517			A_C_00000000, A_FXBUS(FXBUS_PCM_LEFT), &pc);
1518	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_R), A_C_00000000,
1519			A_C_00000000, A_FXBUS(FXBUS_PCM_RIGHT), &pc);
1520
1521	/* GPR[0/1] = RCA S/PDIF[l/r] -- Master volume */
1522	audigy_addefxop(sc, iACC3, A_GPR(0), A_C_00000000,
1523			A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_L), &pc);
1524	audigy_addefxop(sc, iACC3, A_GPR(1), A_C_00000000,
1525			A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_R), &pc);
1526
1527	/* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
1528	audigy_addefxop(sc, iINTERP, A_GPR(2), A_GPR(1),
1529			A_C_40000000, A_GPR(0), &pc);
1530
1531	/* Headphones[l/r] = GPR[0/1] */
1532	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_L),
1533			A_C_00000000, A_C_00000000, A_GPR(0), &pc);
1534	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_R),
1535			A_C_00000000, A_C_00000000, A_GPR(1), &pc);
1536
1537	/* Analog Front[l/r] = GPR[0/1] */
1538	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_L), A_C_00000000,
1539			A_C_00000000, A_GPR(0), &pc);
1540	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_R), A_C_00000000,
1541			A_C_00000000, A_GPR(1), &pc);
1542
1543	/* Digital Front[l/r] = GPR[0/1] */
1544	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L), A_C_00000000,
1545			A_C_00000000, A_GPR(0), &pc);
1546	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_R), A_C_00000000,
1547			A_C_00000000, A_GPR(1), &pc);
1548
1549	/* Center and Subwoofer configuration */
1550	/* Analog Center = GPR[0] + GPR[2] */
1551	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ACENTER), A_C_00000000,
1552			A_GPR(0), A_GPR(2), &pc);
1553	/* Analog Sub = GPR[1] + GPR[2] */
1554	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ALFE), A_C_00000000,
1555			A_GPR(1), A_GPR(2), &pc);
1556
1557	/* Digital Center = GPR[0] + GPR[2] */
1558	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_CENTER), A_C_00000000,
1559			A_GPR(0), A_GPR(2), &pc);
1560	/* Digital Sub = GPR[1] + GPR[2] */
1561	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_LFE), A_C_00000000,
1562			A_GPR(1), A_GPR(2), &pc);
1563
1564#if 0
1565	/* Analog Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
1566	/*   RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
1567	audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
1568			A_GPR(16), A_GPR(0), &pc);
1569	audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
1570			A_GPR(17), A_GPR(1), &pc);
1571
1572	/* Digital Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
1573	/*   RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
1574	audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
1575			A_GPR(16), A_GPR(0), &pc);
1576	audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
1577			A_GPR(17), A_GPR(1), &pc);
1578#else
1579	/* XXX This is just a copy to the channel, since we do not have
1580	 *     a patch manager, it is useful for have another output enabled.
1581	 */
1582
1583	/* Analog Rear[l/r] = GPR[0/1] */
1584	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
1585			A_C_00000000, A_GPR(0), &pc);
1586	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
1587			A_C_00000000, A_GPR(1), &pc);
1588
1589	/* Digital Rear[l/r] = GPR[0/1] */
1590	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
1591			A_C_00000000, A_GPR(0), &pc);
1592	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
1593			A_C_00000000, A_GPR(1), &pc);
1594#endif
1595
1596	/* ADC Recording buffer[l/r] = AC97Input[l/r] */
1597	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_L), A_C_00000000,
1598			A_C_00000000, A_EXTIN(A_EXTIN_AC97_L), &pc);
1599	audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_R), A_C_00000000,
1600			A_C_00000000, A_EXTIN(A_EXTIN_AC97_R), &pc);
1601
1602	/* resume normal operations */
1603	emu_wrptr(sc, 0, EMU_A_DBG, 0);
1604}
1605
1606static void
1607emu_initefx(struct sc_info *sc)
1608{
1609	int i;
1610	u_int32_t pc = 16;
1611
1612	/* acc3 0,0,0,0 - NOPs */
1613	for (i = 0; i < 512; i++) {
1614		emu_wrefx(sc, i * 2, 0x10040);
1615		emu_wrefx(sc, i * 2 + 1, 0x610040);
1616	}
1617
1618	for (i = 0; i < 256; i++)
1619		emu_wrptr(sc, 0, EMU_FXGPREGBASE + i, 0);
1620
1621	/* FX-8010 DSP Registers:
1622	   FX Bus
1623	     0x000-0x00f : 16 registers
1624	   Input
1625	     0x010/0x011 : AC97 Codec (l/r)
1626	     0x012/0x013 : ADC, S/PDIF (l/r)
1627	     0x014/0x015 : Mic(left), Zoom (l/r)
1628	     0x016/0x017 : TOS link in (l/r)
1629	     0x018/0x019 : Line/Mic 1 (l/r)
1630	     0x01a/0x01b : COAX S/PDIF (l/r)
1631	     0x01c/0x01d : Line/Mic 2 (l/r)
1632	   Output
1633	     0x020/0x021 : AC97 Output (l/r)
1634	     0x022/0x023 : TOS link out (l/r)
1635	     0x024/0x025 : Center/LFE
1636	     0x026/0x027 : LiveDrive Headphone (l/r)
1637	     0x028/0x029 : Rear Channel (l/r)
1638	     0x02a/0x02b : ADC Recording Buffer (l/r)
1639	     0x02c       : Mic Recording Buffer
1640	     0x031/0x032 : Analog Center/LFE
1641	   Constants
1642	     0x040 - 0x044 = 0 - 4
1643	     0x045 = 0x8, 0x046 = 0x10, 0x047 = 0x20
1644	     0x048 = 0x100, 0x049 = 0x10000, 0x04a = 0x80000
1645	     0x04b = 0x10000000, 0x04c = 0x20000000, 0x04d = 0x40000000
1646	     0x04e = 0x80000000, 0x04f = 0x7fffffff, 0x050 = 0xffffffff
1647	     0x051 = 0xfffffffe, 0x052 = 0xc0000000, 0x053 = 0x41fbbcdc
1648	     0x054 = 0x5a7ef9db, 0x055 = 0x00100000
1649	   Temporary Values
1650	     0x056 : Accumulator
1651	     0x057 : Condition Register
1652	     0x058 : Noise source
1653	     0x059 : Noise source
1654	     0x05a : IRQ Register
1655	     0x05b : TRAM Delay Base Address Count
1656	   General Purpose Registers
1657	     0x100 - 0x1ff
1658	   Tank Memory Data Registers
1659	     0x200 - 0x2ff
1660	   Tank Memory Address Registers
1661	     0x300 - 0x3ff
1662	     */
1663
1664	/* Routing - this will be configurable in later version */
1665
1666	/* GPR[0/1] = FX * 4 + SPDIF-in */
1667	emu_addefxop(sc, iMACINT0, GPR(0), EXTIN(EXTIN_SPDIF_CD_L),
1668			FXBUS(FXBUS_PCM_LEFT), C_00000004, &pc);
1669	emu_addefxop(sc, iMACINT0, GPR(1), EXTIN(EXTIN_SPDIF_CD_R),
1670			FXBUS(FXBUS_PCM_RIGHT), C_00000004, &pc);
1671
1672	/* GPR[0/1] += APS-input */
1673	emu_addefxop(sc, iACC3, GPR(0), GPR(0), C_00000000,
1674			sc->APS ? EXTIN(EXTIN_TOSLINK_L) : C_00000000, &pc);
1675	emu_addefxop(sc, iACC3, GPR(1), GPR(1), C_00000000,
1676			sc->APS ? EXTIN(EXTIN_TOSLINK_R) : C_00000000, &pc);
1677
1678	/* FrontOut (AC97) = GPR[0/1] */
1679	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_L), C_00000000,
1680			C_00000000, GPR(0), &pc);
1681	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_R), C_00000000,
1682			C_00000001, GPR(1), &pc);
1683
1684	/* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
1685	emu_addefxop(sc, iINTERP, GPR(2), GPR(1), C_40000000, GPR(0), &pc);
1686
1687#if 0
1688	/* RearOut = (GPR[0/1] * RearVolume) >> 31 */
1689	/*   RearVolume = GPR[0x10/0x11] */
1690	emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_L), C_00000000,
1691			GPR(16), GPR(0), &pc);
1692	emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_R), C_00000000,
1693			GPR(17), GPR(1), &pc);
1694#else
1695	/* XXX This is just a copy to the channel, since we do not have
1696	 *     a patch manager, it is useful for have another output enabled.
1697	 */
1698
1699	/* Rear[l/r] = GPR[0/1] */
1700	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_L), C_00000000,
1701			C_00000000, GPR(0), &pc);
1702	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_R), C_00000000,
1703			C_00000000, GPR(1), &pc);
1704#endif
1705
1706	/* TOS out[l/r] = GPR[0/1] */
1707	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_L), C_00000000,
1708			C_00000000, GPR(0), &pc);
1709	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_R), C_00000000,
1710			C_00000000, GPR(1), &pc);
1711
1712	/* Center and Subwoofer configuration */
1713	/* Analog Center = GPR[0] + GPR[2] */
1714	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ACENTER), C_00000000,
1715			GPR(0), GPR(2), &pc);
1716	/* Analog Sub = GPR[1] + GPR[2] */
1717	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ALFE), C_00000000,
1718			GPR(1), GPR(2), &pc);
1719	/* Digital Center = GPR[0] + GPR[2] */
1720	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_CENTER), C_00000000,
1721			GPR(0), GPR(2), &pc);
1722	/* Digital Sub = GPR[1] + GPR[2] */
1723	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_LFE), C_00000000,
1724			GPR(1), GPR(2), &pc);
1725
1726	/* Headphones[l/r] = GPR[0/1] */
1727	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_L), C_00000000,
1728			C_00000000, GPR(0), &pc);
1729	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_R), C_00000000,
1730			C_00000000, GPR(1), &pc);
1731
1732	/* ADC Recording buffer[l/r] = AC97Input[l/r] */
1733	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_L), C_00000000,
1734			C_00000000, EXTIN(EXTIN_AC97_L), &pc);
1735	emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_R), C_00000000,
1736			C_00000000, EXTIN(EXTIN_AC97_R), &pc);
1737
1738	/* resume normal operations */
1739	emu_wrptr(sc, 0, EMU_DBG, 0);
1740}
1741
1742/* Probe and attach the card */
1743static int
1744emu_init(struct sc_info *sc)
1745{
1746	u_int32_t spcs, ch, tmp, i;
1747
1748	if (sc->audigy) {
1749		/* enable additional AC97 slots */
1750		emu_wrptr(sc, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE);
1751	}
1752
1753	/* disable audio and lock cache */
1754	emu_wr(sc, EMU_HCFG,
1755	    EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE,
1756	    4);
1757
1758	/* reset recording buffers */
1759	emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
1760	emu_wrptr(sc, 0, EMU_MICBA, 0);
1761	emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
1762	emu_wrptr(sc, 0, EMU_FXBA, 0);
1763	emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
1764	emu_wrptr(sc, 0, EMU_ADCBA, 0);
1765
1766	/* disable channel interrupt */
1767	emu_wr(sc, EMU_INTE,
1768	    EMU_INTE_INTERTIMERENB | EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE,
1769	    4);
1770	emu_wrptr(sc, 0, EMU_CLIEL, 0);
1771	emu_wrptr(sc, 0, EMU_CLIEH, 0);
1772	emu_wrptr(sc, 0, EMU_SOLEL, 0);
1773	emu_wrptr(sc, 0, EMU_SOLEH, 0);
1774
1775	/* wonder what these do... */
1776	if (sc->audigy) {
1777		emu_wrptr(sc, 0, EMU_SPBYPASS, 0xf00);
1778		emu_wrptr(sc, 0, EMU_AC97SLOT, 0x3);
1779	}
1780
1781	/* init envelope engine */
1782	for (ch = 0; ch < NUM_G; ch++) {
1783		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, ENV_OFF);
1784		emu_wrptr(sc, ch, EMU_CHAN_IP, 0);
1785		emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0xffff);
1786		emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0xffff);
1787		emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
1788		emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
1789		emu_wrptr(sc, ch, EMU_CHAN_CCR, 0);
1790
1791		emu_wrptr(sc, ch, EMU_CHAN_PSST, 0);
1792		emu_wrptr(sc, ch, EMU_CHAN_DSL, 0x10);
1793		emu_wrptr(sc, ch, EMU_CHAN_CCCA, 0);
1794		emu_wrptr(sc, ch, EMU_CHAN_Z1, 0);
1795		emu_wrptr(sc, ch, EMU_CHAN_Z2, 0);
1796		emu_wrptr(sc, ch, EMU_CHAN_FXRT, 0xd01c0000);
1797
1798		emu_wrptr(sc, ch, EMU_CHAN_ATKHLDM, 0);
1799		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSM, 0);
1800		emu_wrptr(sc, ch, EMU_CHAN_IFATN, 0xffff);
1801		emu_wrptr(sc, ch, EMU_CHAN_PEFE, 0);
1802		emu_wrptr(sc, ch, EMU_CHAN_FMMOD, 0);
1803		emu_wrptr(sc, ch, EMU_CHAN_TREMFRQ, 24);	/* 1 Hz */
1804		emu_wrptr(sc, ch, EMU_CHAN_FM2FRQ2, 24);	/* 1 Hz */
1805		emu_wrptr(sc, ch, EMU_CHAN_TEMPENV, 0);
1806
1807		/*** these are last so OFF prevents writing ***/
1808		emu_wrptr(sc, ch, EMU_CHAN_LFOVAL2, 0);
1809		emu_wrptr(sc, ch, EMU_CHAN_LFOVAL1, 0);
1810		emu_wrptr(sc, ch, EMU_CHAN_ATKHLDV, 0);
1811		emu_wrptr(sc, ch, EMU_CHAN_ENVVOL, 0);
1812		emu_wrptr(sc, ch, EMU_CHAN_ENVVAL, 0);
1813
1814		if (sc->audigy) {
1815			/* audigy cards need this to initialize correctly */
1816			emu_wrptr(sc, ch, 0x4c, 0);
1817			emu_wrptr(sc, ch, 0x4d, 0);
1818			emu_wrptr(sc, ch, 0x4e, 0);
1819			emu_wrptr(sc, ch, 0x4f, 0);
1820			/* set default routing */
1821			emu_wrptr(sc, ch, EMU_A_CHAN_FXRT1, 0x03020100);
1822			emu_wrptr(sc, ch, EMU_A_CHAN_FXRT2, 0x3f3f3f3f);
1823			emu_wrptr(sc, ch, EMU_A_CHAN_SENDAMOUNTS, 0);
1824		}
1825
1826		sc->voice[ch].vnum = ch;
1827		sc->voice[ch].slave = NULL;
1828		sc->voice[ch].busy = 0;
1829		sc->voice[ch].ismaster = 0;
1830		sc->voice[ch].running = 0;
1831		sc->voice[ch].b16 = 0;
1832		sc->voice[ch].stereo = 0;
1833		sc->voice[ch].speed = 0;
1834		sc->voice[ch].start = 0;
1835		sc->voice[ch].end = 0;
1836		sc->voice[ch].channel = NULL;
1837	}
1838	sc->pnum = sc->rnum = 0;
1839
1840	/*
1841	 *  Init to 0x02109204 :
1842	 *  Clock accuracy    = 0     (1000ppm)
1843	 *  Sample Rate       = 2     (48kHz)
1844	 *  Audio Channel     = 1     (Left of 2)
1845	 *  Source Number     = 0     (Unspecified)
1846	 *  Generation Status = 1     (Original for Cat Code 12)
1847	 *  Cat Code          = 12    (Digital Signal Mixer)
1848	 *  Mode              = 0     (Mode 0)
1849	 *  Emphasis          = 0     (None)
1850	 *  CP                = 1     (Copyright unasserted)
1851	 *  AN                = 0     (Audio data)
1852	 *  P                 = 0     (Consumer)
1853	 */
1854	spcs = EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
1855	    EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
1856	    EMU_SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 |
1857	    EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT;
1858	emu_wrptr(sc, 0, EMU_SPCS0, spcs);
1859	emu_wrptr(sc, 0, EMU_SPCS1, spcs);
1860	emu_wrptr(sc, 0, EMU_SPCS2, spcs);
1861
1862	if (!sc->audigy)
1863		emu_initefx(sc);
1864	else if (sc->audigy2) {	/* Audigy 2 */
1865		/* from ALSA initialization code: */
1866
1867		/* Hack for Alice3 to work independent of haP16V driver */
1868		u_int32_t tmp;
1869
1870		/* Setup SRCMulti_I2S SamplingRate */
1871		tmp = emu_rdptr(sc, 0, EMU_A_SPDIF_SAMPLERATE) & 0xfffff1ff;
1872		emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, tmp | 0x400);
1873
1874		/* Setup SRCSel (Enable SPDIF, I2S SRCMulti) */
1875		emu_wr(sc, 0x20, 0x00600000, 4);
1876		emu_wr(sc, 0x24, 0x00000014, 4);
1877
1878		/* Setup SRCMulti Input Audio Enable */
1879		emu_wr(sc, 0x20, 0x006e0000, 4);
1880		emu_wr(sc, 0x24, 0xff00ff00, 4);
1881	}
1882
1883	SLIST_INIT(&sc->mem.blocks);
1884	sc->mem.ptb_pages = emu_malloc(sc, EMUMAXPAGES * sizeof(u_int32_t),
1885	    &sc->mem.ptb_pages_addr);
1886	if (sc->mem.ptb_pages == NULL)
1887		return -1;
1888
1889	sc->mem.silent_page = emu_malloc(sc, EMUPAGESIZE,
1890	    &sc->mem.silent_page_addr);
1891	if (sc->mem.silent_page == NULL) {
1892		emu_free(sc, sc->mem.ptb_pages);
1893		return -1;
1894	}
1895	/* Clear page with silence & setup all pointers to this page */
1896	bzero(sc->mem.silent_page, EMUPAGESIZE);
1897	tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1;
1898	for (i = 0; i < EMUMAXPAGES; i++)
1899		sc->mem.ptb_pages[i] = tmp | i;
1900
1901	emu_wrptr(sc, 0, EMU_PTB, (sc->mem.ptb_pages_addr));
1902	emu_wrptr(sc, 0, EMU_TCB, 0);	/* taken from original driver */
1903	emu_wrptr(sc, 0, EMU_TCBS, 0);	/* taken from original driver */
1904
1905	for (ch = 0; ch < NUM_G; ch++) {
1906		emu_wrptr(sc, ch, EMU_CHAN_MAPA, tmp | EMU_CHAN_MAP_PTI_MASK);
1907		emu_wrptr(sc, ch, EMU_CHAN_MAPB, tmp | EMU_CHAN_MAP_PTI_MASK);
1908	}
1909
1910	/* emu_memalloc(sc, EMUPAGESIZE); */
1911	/*
1912	 *  Hokay, now enable the AUD bit
1913	 *
1914	 *  Audigy
1915	 *   Enable Audio = 0 (enabled after fx processor initialization)
1916	 *   Mute Disable Audio = 0
1917	 *   Joystick = 1
1918	 *
1919	 *  Audigy 2
1920	 *   Enable Audio = 1
1921	 *   Mute Disable Audio = 0
1922	 *   Joystick = 1
1923	 *   GP S/PDIF AC3 Enable = 1
1924	 *   CD S/PDIF AC3 Enable = 1
1925	 *
1926	 *  EMU10K1
1927	 *   Enable Audio = 1
1928	 *   Mute Disable Audio = 0
1929	 *   Lock Tank Memory = 1
1930	 *   Lock Sound Memory = 0
1931	 *   Auto Mute = 1
1932	 */
1933
1934	if (sc->audigy) {
1935		tmp = EMU_HCFG_AUTOMUTE | EMU_HCFG_JOYENABLE;
1936		if (sc->audigy2)	/* Audigy 2 */
1937			tmp = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AC3ENABLE_CDSPDIF |
1938			    EMU_HCFG_AC3ENABLE_GPSPDIF;
1939		emu_wr(sc, EMU_HCFG, tmp, 4);
1940
1941		audigy_initefx(sc);
1942
1943		/* from ALSA initialization code: */
1944
1945		/* enable audio and disable both audio/digital outputs */
1946		emu_wr(sc, EMU_HCFG, emu_rd(sc, EMU_HCFG, 4) | EMU_HCFG_AUDIOENABLE, 4);
1947		emu_wr(sc, EMU_A_IOCFG, emu_rd(sc, EMU_A_IOCFG, 4) & ~EMU_A_IOCFG_GPOUT_AD,
1948		    4);
1949		if (sc->audigy2) {	/* Audigy 2 */
1950			/* Unmute Analog.
1951			 * Set GPO6 to 1 for Apollo. This has to be done after
1952			 * init Alice3 I2SOut beyond 48kHz.
1953			 * So, sequence is important.
1954			 */
1955			emu_wr(sc, EMU_A_IOCFG,
1956			    emu_rd(sc, EMU_A_IOCFG, 4) | EMU_A_IOCFG_GPOUT_A, 4);
1957		}
1958	} else {
1959		/* EMU10K1 initialization code */
1960		tmp = EMU_HCFG_AUDIOENABLE | EMU_HCFG_LOCKTANKCACHE_MASK
1961		    | EMU_HCFG_AUTOMUTE;
1962		if (sc->rev >= 6)
1963			tmp |= EMU_HCFG_JOYENABLE;
1964
1965		emu_wr(sc, EMU_HCFG, tmp, 4);
1966
1967		/* TOSLink detection */
1968		sc->tos_link = 0;
1969		tmp = emu_rd(sc, EMU_HCFG, 4);
1970		if (tmp & (EMU_HCFG_GPINPUT0 | EMU_HCFG_GPINPUT1)) {
1971			emu_wr(sc, EMU_HCFG, tmp | EMU_HCFG_GPOUT1, 4);
1972			DELAY(50);
1973			if (tmp != (emu_rd(sc, EMU_HCFG, 4) & ~EMU_HCFG_GPOUT1)) {
1974				sc->tos_link = 1;
1975				emu_wr(sc, EMU_HCFG, tmp, 4);
1976			}
1977		}
1978	}
1979
1980	return 0;
1981}
1982
1983static int
1984emu_uninit(struct sc_info *sc)
1985{
1986	u_int32_t ch;
1987
1988	emu_wr(sc, EMU_INTE, 0, 4);
1989	for (ch = 0; ch < NUM_G; ch++)
1990		emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, ENV_OFF);
1991	for (ch = 0; ch < NUM_G; ch++) {
1992		emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0);
1993		emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0);
1994		emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
1995		emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
1996	}
1997
1998	if (sc->audigy) {	/* stop fx processor */
1999		emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
2000	}
2001
2002	/* disable audio and lock cache */
2003	emu_wr(sc, EMU_HCFG,
2004	    EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE,
2005	    4);
2006
2007	emu_wrptr(sc, 0, EMU_PTB, 0);
2008	/* reset recording buffers */
2009	emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
2010	emu_wrptr(sc, 0, EMU_MICBA, 0);
2011	emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
2012	emu_wrptr(sc, 0, EMU_FXBA, 0);
2013	emu_wrptr(sc, 0, EMU_FXWC, 0);
2014	emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
2015	emu_wrptr(sc, 0, EMU_ADCBA, 0);
2016	emu_wrptr(sc, 0, EMU_TCB, 0);
2017	emu_wrptr(sc, 0, EMU_TCBS, 0);
2018
2019	/* disable channel interrupt */
2020	emu_wrptr(sc, 0, EMU_CLIEL, 0);
2021	emu_wrptr(sc, 0, EMU_CLIEH, 0);
2022	emu_wrptr(sc, 0, EMU_SOLEL, 0);
2023	emu_wrptr(sc, 0, EMU_SOLEH, 0);
2024
2025	/* init envelope engine */
2026	if (!SLIST_EMPTY(&sc->mem.blocks))
2027		device_printf(sc->dev, "warning: memblock list not empty\n");
2028	emu_free(sc, sc->mem.ptb_pages);
2029	emu_free(sc, sc->mem.silent_page);
2030
2031	if(sc->mpu)
2032	    mpu401_uninit(sc->mpu);
2033	return 0;
2034}
2035
2036static int
2037emu_pci_probe(device_t dev)
2038{
2039	char *s = NULL;
2040
2041	switch (pci_get_devid(dev)) {
2042	case EMU10K1_PCI_ID:
2043		s = "Creative EMU10K1";
2044		break;
2045
2046	case EMU10K2_PCI_ID:
2047		if (pci_get_revid(dev) == 0x04)
2048			s = "Creative Audigy 2 (EMU10K2)";
2049		else
2050			s = "Creative Audigy (EMU10K2)";
2051		break;
2052
2053	case EMU10K3_PCI_ID:
2054		s = "Creative Audigy 2 (EMU10K3)";
2055		break;
2056
2057	default:
2058		return ENXIO;
2059	}
2060
2061	device_set_desc(dev, s);
2062	return BUS_PROBE_LOW_PRIORITY;
2063}
2064
2065static int
2066emu_pci_attach(device_t dev)
2067{
2068	struct ac97_info *codec = NULL;
2069	struct sc_info *sc;
2070	int i, gotmic;
2071	char status[SND_STATUSLEN];
2072
2073	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
2074	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_emu10k1 softc");
2075	sc->dev = dev;
2076	sc->type = pci_get_devid(dev);
2077	sc->rev = pci_get_revid(dev);
2078	sc->audigy = sc->type == EMU10K2_PCI_ID || sc->type == EMU10K3_PCI_ID;
2079	sc->audigy2 = (sc->audigy && sc->rev == 0x04);
2080	sc->nchans = sc->audigy ? 8 : 4;
2081	sc->addrmask = sc->audigy ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK;
2082
2083	pci_enable_busmaster(dev);
2084
2085	i = PCIR_BAR(0);
2086	sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE);
2087	if (sc->reg == NULL) {
2088		device_printf(dev, "unable to map register space\n");
2089		goto bad;
2090	}
2091	sc->st = rman_get_bustag(sc->reg);
2092	sc->sh = rman_get_bushandle(sc->reg);
2093
2094	sc->bufsz = pcm_getbuffersize(dev, 4096, EMU_DEFAULT_BUFSZ, 65536);
2095
2096	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
2097		/*boundary*/0,
2098		/*lowaddr*/(1U << 31) - 1, /* can only access 0-2gb */
2099		/*highaddr*/BUS_SPACE_MAXADDR,
2100		/*filter*/NULL, /*filterarg*/NULL,
2101		/*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
2102		/*flags*/0, /*lockfunc*/busdma_lock_mutex,
2103		/*lockarg*/&Giant, &sc->parent_dmat) != 0) {
2104		device_printf(dev, "unable to create dma tag\n");
2105		goto bad;
2106	}
2107
2108	if (emu_init(sc) == -1) {
2109		device_printf(dev, "unable to initialize the card\n");
2110		goto bad;
2111	}
2112
2113	codec = AC97_CREATE(dev, sc, emu_ac97);
2114	if (codec == NULL) goto bad;
2115	gotmic = (ac97_getcaps(codec) & AC97_CAP_MICCHANNEL) ? 1 : 0;
2116	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
2117
2118	emu_midiattach(sc);
2119
2120	i = 0;
2121	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
2122	    RF_ACTIVE | RF_SHAREABLE);
2123	if (!sc->irq ||
2124	    snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) {
2125		device_printf(dev, "unable to map interrupt\n");
2126		goto bad;
2127	}
2128
2129	snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
2130	    rman_get_start(sc->reg), rman_get_start(sc->irq),
2131	    PCM_KLDSTRING(snd_emu10k1));
2132
2133	if (pcm_register(dev, sc, sc->nchans, gotmic ? 3 : 2)) goto bad;
2134	for (i = 0; i < sc->nchans; i++)
2135		pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc);
2136	for (i = 0; i < (gotmic ? 3 : 2); i++)
2137		pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc);
2138
2139	pcm_setstatus(dev, status);
2140
2141	return 0;
2142
2143bad:
2144	if (codec) ac97_destroy(codec);
2145	if (sc->reg) bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
2146	if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih);
2147	if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
2148	if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat);
2149	if (sc->lock) snd_mtxfree(sc->lock);
2150	free(sc, M_DEVBUF);
2151	return ENXIO;
2152}
2153
2154static int
2155emu_pci_detach(device_t dev)
2156{
2157	int r;
2158	struct sc_info *sc;
2159
2160	r = pcm_unregister(dev);
2161	if (r)
2162		return r;
2163
2164	sc = pcm_getdevinfo(dev);
2165	/* shutdown chip */
2166	emu_uninit(sc);
2167
2168	bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
2169	bus_teardown_intr(dev, sc->irq, sc->ih);
2170	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
2171	bus_dma_tag_destroy(sc->parent_dmat);
2172	snd_mtxfree(sc->lock);
2173	free(sc, M_DEVBUF);
2174
2175	return 0;
2176}
2177
2178/* add suspend, resume */
2179static device_method_t emu_methods[] = {
2180	/* Device interface */
2181	DEVMETHOD(device_probe,		emu_pci_probe),
2182	DEVMETHOD(device_attach,	emu_pci_attach),
2183	DEVMETHOD(device_detach,	emu_pci_detach),
2184
2185	DEVMETHOD_END
2186};
2187
2188static driver_t emu_driver = {
2189	"pcm",
2190	emu_methods,
2191	PCM_SOFTC_SIZE,
2192};
2193
2194DRIVER_MODULE(snd_emu10k1, pci, emu_driver, pcm_devclass, NULL, NULL);
2195MODULE_DEPEND(snd_emu10k1, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2196MODULE_VERSION(snd_emu10k1, 1);
2197MODULE_DEPEND(snd_emu10k1, midi, 1, 1, 1);
2198
2199/* dummy driver to silence the joystick device */
2200static int
2201emujoy_pci_probe(device_t dev)
2202{
2203	char *s = NULL;
2204
2205	switch (pci_get_devid(dev)) {
2206	case 0x70021102:
2207		s = "Creative EMU10K1 Joystick";
2208		device_quiet(dev);
2209		break;
2210	case 0x70031102:
2211		s = "Creative EMU10K2 Joystick";
2212		device_quiet(dev);
2213		break;
2214	}
2215
2216	if (s) device_set_desc(dev, s);
2217	return s ? -1000 : ENXIO;
2218}
2219
2220static int
2221emujoy_pci_attach(device_t dev)
2222{
2223
2224	return 0;
2225}
2226
2227static int
2228emujoy_pci_detach(device_t dev)
2229{
2230
2231	return 0;
2232}
2233
2234static device_method_t emujoy_methods[] = {
2235	DEVMETHOD(device_probe,		emujoy_pci_probe),
2236	DEVMETHOD(device_attach,	emujoy_pci_attach),
2237	DEVMETHOD(device_detach,	emujoy_pci_detach),
2238
2239	DEVMETHOD_END
2240};
2241
2242static driver_t emujoy_driver = {
2243	"emujoy",
2244	emujoy_methods,
2245	1	/* no softc */
2246};
2247
2248static devclass_t emujoy_devclass;
2249
2250DRIVER_MODULE(emujoy, pci, emujoy_driver, emujoy_devclass, NULL, NULL);
2251