1098ca2bdSWarner Losh /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
42511c244SDavid E. O'Brien * Copyright (c) 2004 David O'Brien <obrien@FreeBSD.org>
521f1e37cSDavid E. O'Brien * Copyright (c) 2003 Orlando Bassotto <orlando.bassotto@ieo-research.it>
63f225978SCameron Grant * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
7c067afaaSCameron Grant * All rights reserved.
8c067afaaSCameron Grant *
9c067afaaSCameron Grant * Redistribution and use in source and binary forms, with or without
10c067afaaSCameron Grant * modification, are permitted provided that the following conditions
11c067afaaSCameron Grant * are met:
12c067afaaSCameron Grant * 1. Redistributions of source code must retain the above copyright
13c067afaaSCameron Grant * notice, this list of conditions and the following disclaimer.
14c067afaaSCameron Grant * 2. Redistributions in binary form must reproduce the above copyright
15c067afaaSCameron Grant * notice, this list of conditions and the following disclaimer in the
16c067afaaSCameron Grant * documentation and/or other materials provided with the distribution.
17c067afaaSCameron Grant *
18c067afaaSCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19c067afaaSCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20c067afaaSCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21c067afaaSCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22c067afaaSCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23c067afaaSCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24c067afaaSCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25c067afaaSCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
26c067afaaSCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27c067afaaSCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28c067afaaSCameron Grant * SUCH DAMAGE.
29c067afaaSCameron Grant */
30c067afaaSCameron Grant
3190da2b28SAriff Abdullah #ifdef HAVE_KERNEL_OPTION_HEADERS
3290da2b28SAriff Abdullah #include "opt_snd.h"
3390da2b28SAriff Abdullah #endif
3490da2b28SAriff Abdullah
35c067afaaSCameron Grant #include <dev/sound/pcm/sound.h>
36c067afaaSCameron Grant #include <dev/sound/pcm/ac97.h>
37c7e0c9dbSPedro F. Giffuni #include <dev/sound/pci/emuxkireg.h>
38c067afaaSCameron Grant
3990cf0136SWarner Losh #include <dev/pci/pcireg.h>
4090cf0136SWarner Losh #include <dev/pci/pcivar.h>
41c067afaaSCameron Grant #include <sys/queue.h>
42c067afaaSCameron Grant
43f510d240SAlexander Leidinger #include <dev/sound/midi/mpu401.h>
44f510d240SAlexander Leidinger #include "mpufoi_if.h"
45f510d240SAlexander Leidinger
46c067afaaSCameron Grant /* -------------------------------------------------------------------- */
47c067afaaSCameron Grant
482511c244SDavid E. O'Brien #define NUM_G 64 /* use all channels */
492511c244SDavid E. O'Brien #define WAVEOUT_MAXBUFSIZE 32768
502511c244SDavid E. O'Brien #define EMUPAGESIZE 4096 /* don't change */
5121f1e37cSDavid E. O'Brien #define EMUMAXPAGES (WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE)
5221f1e37cSDavid E. O'Brien #define EMU10K1_PCI_ID 0x00021102 /* 1102 => Creative Labs Vendor ID */
53a791cfeeSCameron Grant #define EMU10K2_PCI_ID 0x00041102
54d2b677bbSWarner Losh #define EMU10K3_PCI_ID 0x00081102
55a791cfeeSCameron Grant #define EMU_DEFAULT_BUFSZ 4096
5621f1e37cSDavid E. O'Brien #define EMU_MAX_CHANS 8
5770776a9cSCameron Grant #define EMU_CHANS 4
5821f1e37cSDavid E. O'Brien
5921f1e37cSDavid E. O'Brien #define MAXREQVOICES 8
6021f1e37cSDavid E. O'Brien #define RESERVED 0
6121f1e37cSDavid E. O'Brien #define NUM_MIDI 16
6221f1e37cSDavid E. O'Brien #define NUM_FXSENDS 4
6321f1e37cSDavid E. O'Brien
6421f1e37cSDavid E. O'Brien #define TMEMSIZE 256*1024
6521f1e37cSDavid E. O'Brien #define TMEMSIZEREG 4
6621f1e37cSDavid E. O'Brien
6721f1e37cSDavid E. O'Brien #define ENABLE 0xffffffff
6821f1e37cSDavid E. O'Brien #define DISABLE 0x00000000
69c7e0c9dbSPedro F. Giffuni #define ENV_ON EMU_CHAN_DCYSUSV_CHANNELENABLE_MASK
702511c244SDavid E. O'Brien #define ENV_OFF 0x00 /* XXX: should this be 1? */
71c067afaaSCameron Grant
72c7e0c9dbSPedro F. Giffuni #define EMU_A_IOCFG_GPOUT_A 0x40
73c7e0c9dbSPedro F. Giffuni #define EMU_A_IOCFG_GPOUT_D 0x04
74c7e0c9dbSPedro F. Giffuni #define EMU_A_IOCFG_GPOUT_AD (EMU_A_IOCFG_GPOUT_A|EMU_A_IOCFG_GPOUT_D) /* EMU_A_IOCFG_GPOUT0 */
75c7e0c9dbSPedro F. Giffuni
76c7e0c9dbSPedro F. Giffuni #define EMU_HCFG_GPOUT1 0x00000800
77c7e0c9dbSPedro F. Giffuni
78c7e0c9dbSPedro F. Giffuni /* instruction set */
79c7e0c9dbSPedro F. Giffuni #define iACC3 0x06
80c7e0c9dbSPedro F. Giffuni #define iMACINT0 0x04
81c7e0c9dbSPedro F. Giffuni #define iINTERP 0x0e
82c7e0c9dbSPedro F. Giffuni
83c7e0c9dbSPedro F. Giffuni #define C_00000000 0x40
84c7e0c9dbSPedro F. Giffuni #define C_00000001 0x41
85c7e0c9dbSPedro F. Giffuni #define C_00000004 0x44
86c7e0c9dbSPedro F. Giffuni #define C_40000000 0x4d
87c7e0c9dbSPedro F. Giffuni /* Audigy constants */
88c7e0c9dbSPedro F. Giffuni #define A_C_00000000 0xc0
89c7e0c9dbSPedro F. Giffuni #define A_C_40000000 0xcd
90c7e0c9dbSPedro F. Giffuni
91c7e0c9dbSPedro F. Giffuni /* GPRs */
92c7e0c9dbSPedro F. Giffuni #define FXBUS(x) (0x00 + (x))
93c7e0c9dbSPedro F. Giffuni #define EXTIN(x) (0x10 + (x))
94c7e0c9dbSPedro F. Giffuni #define EXTOUT(x) (0x20 + (x))
95c7e0c9dbSPedro F. Giffuni
96c7e0c9dbSPedro F. Giffuni #define GPR(x) (EMU_FXGPREGBASE + (x))
97c7e0c9dbSPedro F. Giffuni #define A_EXTIN(x) (0x40 + (x))
98c7e0c9dbSPedro F. Giffuni #define A_FXBUS(x) (0x00 + (x))
99c7e0c9dbSPedro F. Giffuni #define A_EXTOUT(x) (0x60 + (x))
100c7e0c9dbSPedro F. Giffuni #define A_GPR(x) (EMU_A_FXGPREGBASE + (x))
101c7e0c9dbSPedro F. Giffuni
102c7e0c9dbSPedro F. Giffuni /* FX buses */
103c7e0c9dbSPedro F. Giffuni #define FXBUS_PCM_LEFT 0x00
104c7e0c9dbSPedro F. Giffuni #define FXBUS_PCM_RIGHT 0x01
105c7e0c9dbSPedro F. Giffuni #define FXBUS_MIDI_LEFT 0x04
106c7e0c9dbSPedro F. Giffuni #define FXBUS_MIDI_RIGHT 0x05
107c7e0c9dbSPedro F. Giffuni #define FXBUS_MIDI_REVERB 0x0c
108c7e0c9dbSPedro F. Giffuni #define FXBUS_MIDI_CHORUS 0x0d
109c7e0c9dbSPedro F. Giffuni
110c7e0c9dbSPedro F. Giffuni /* Inputs */
111c7e0c9dbSPedro F. Giffuni #define EXTIN_AC97_L 0x00
112c7e0c9dbSPedro F. Giffuni #define EXTIN_AC97_R 0x01
113c7e0c9dbSPedro F. Giffuni #define EXTIN_SPDIF_CD_L 0x02
114c7e0c9dbSPedro F. Giffuni #define EXTIN_SPDIF_CD_R 0x03
115c7e0c9dbSPedro F. Giffuni #define EXTIN_TOSLINK_L 0x06
116c7e0c9dbSPedro F. Giffuni #define EXTIN_TOSLINK_R 0x07
117c7e0c9dbSPedro F. Giffuni #define EXTIN_COAX_SPDIF_L 0x0a
118c7e0c9dbSPedro F. Giffuni #define EXTIN_COAX_SPDIF_R 0x0b
119c7e0c9dbSPedro F. Giffuni /* Audigy Inputs */
120c7e0c9dbSPedro F. Giffuni #define A_EXTIN_AC97_L 0x00
121c7e0c9dbSPedro F. Giffuni #define A_EXTIN_AC97_R 0x01
122c7e0c9dbSPedro F. Giffuni
123c7e0c9dbSPedro F. Giffuni /* Outputs */
124c7e0c9dbSPedro F. Giffuni #define EXTOUT_AC97_L 0x00
125c7e0c9dbSPedro F. Giffuni #define EXTOUT_AC97_R 0x01
126c7e0c9dbSPedro F. Giffuni #define EXTOUT_TOSLINK_L 0x02
127c7e0c9dbSPedro F. Giffuni #define EXTOUT_TOSLINK_R 0x03
128c7e0c9dbSPedro F. Giffuni #define EXTOUT_AC97_CENTER 0x04
129c7e0c9dbSPedro F. Giffuni #define EXTOUT_AC97_LFE 0x05
130c7e0c9dbSPedro F. Giffuni #define EXTOUT_HEADPHONE_L 0x06
131c7e0c9dbSPedro F. Giffuni #define EXTOUT_HEADPHONE_R 0x07
132c7e0c9dbSPedro F. Giffuni #define EXTOUT_REAR_L 0x08
133c7e0c9dbSPedro F. Giffuni #define EXTOUT_REAR_R 0x09
134c7e0c9dbSPedro F. Giffuni #define EXTOUT_ADC_CAP_L 0x0a
135c7e0c9dbSPedro F. Giffuni #define EXTOUT_ADC_CAP_R 0x0b
136c7e0c9dbSPedro F. Giffuni #define EXTOUT_ACENTER 0x11
137c7e0c9dbSPedro F. Giffuni #define EXTOUT_ALFE 0x12
138c7e0c9dbSPedro F. Giffuni /* Audigy Outputs */
139c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_FRONT_L 0x00
140c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_FRONT_R 0x01
141c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_CENTER 0x02
142c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_LFE 0x03
143c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_HEADPHONE_L 0x04
144c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_HEADPHONE_R 0x05
145c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_REAR_L 0x06
146c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_REAR_R 0x07
147c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AFRONT_L 0x08
148c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AFRONT_R 0x09
149c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_ACENTER 0x0a
150c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_ALFE 0x0b
151c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AREAR_L 0x0e
152c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AREAR_R 0x0f
153c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AC97_L 0x10
154c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_AC97_R 0x11
155c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_ADC_CAP_L 0x16
156c7e0c9dbSPedro F. Giffuni #define A_EXTOUT_ADC_CAP_R 0x17
15721f1e37cSDavid E. O'Brien
158c067afaaSCameron Grant struct emu_memblk {
159e3975643SJake Burkholder SLIST_ENTRY(emu_memblk) link;
160c067afaaSCameron Grant void *buf;
16138cc9942SOlivier Houchard bus_addr_t buf_addr;
162c067afaaSCameron Grant u_int32_t pte_start, pte_size;
16386843ea8SJohn Baldwin bus_dmamap_t buf_map;
164c067afaaSCameron Grant };
165c067afaaSCameron Grant
166c067afaaSCameron Grant struct emu_mem {
16721f1e37cSDavid E. O'Brien u_int8_t bmap[EMUMAXPAGES / 8];
16897b3c9d8SCameron Grant u_int32_t *ptb_pages;
169c067afaaSCameron Grant void *silent_page;
17038cc9942SOlivier Houchard bus_addr_t silent_page_addr;
17138cc9942SOlivier Houchard bus_addr_t ptb_pages_addr;
17286843ea8SJohn Baldwin bus_dmamap_t ptb_map;
17386843ea8SJohn Baldwin bus_dmamap_t silent_map;
174e3975643SJake Burkholder SLIST_HEAD(, emu_memblk) blocks;
175c067afaaSCameron Grant };
176c067afaaSCameron Grant
177c067afaaSCameron Grant struct emu_voice {
178c067afaaSCameron Grant int vnum;
17979462204SAriff Abdullah unsigned int b16:1, stereo:1, busy:1, running:1, ismaster:1;
180c067afaaSCameron Grant int speed;
1812d3ce9d5SCameron Grant int start, end, vol;
18221f1e37cSDavid E. O'Brien int fxrt1; /* FX routing */
18321f1e37cSDavid E. O'Brien int fxrt2; /* FX routing (only for audigy) */
18497b3c9d8SCameron Grant u_int32_t buf;
1856c1146c0SCameron Grant struct emu_voice *slave;
18666ef8af5SCameron Grant struct pcm_channel *channel;
187c067afaaSCameron Grant };
188c067afaaSCameron Grant
189c067afaaSCameron Grant struct sc_info;
190c067afaaSCameron Grant
191c067afaaSCameron Grant /* channel registers */
19270776a9cSCameron Grant struct sc_pchinfo {
193350a5fafSCameron Grant int spd, fmt, blksz, run;
1946c1146c0SCameron Grant struct emu_voice *master, *slave;
19566ef8af5SCameron Grant struct snd_dbuf *buffer;
19666ef8af5SCameron Grant struct pcm_channel *channel;
197c067afaaSCameron Grant struct sc_info *parent;
198c067afaaSCameron Grant };
199c067afaaSCameron Grant
20070776a9cSCameron Grant struct sc_rchinfo {
201350a5fafSCameron Grant int spd, fmt, run, blksz, num;
20270776a9cSCameron Grant u_int32_t idxreg, basereg, sizereg, setupreg, irqmask;
20366ef8af5SCameron Grant struct snd_dbuf *buffer;
20466ef8af5SCameron Grant struct pcm_channel *channel;
20570776a9cSCameron Grant struct sc_info *parent;
20670776a9cSCameron Grant };
20770776a9cSCameron Grant
208c067afaaSCameron Grant /* device private data */
209c067afaaSCameron Grant struct sc_info {
210c067afaaSCameron Grant device_t dev;
211c067afaaSCameron Grant u_int32_t type, rev;
21221f1e37cSDavid E. O'Brien u_int32_t tos_link:1, APS:1, audigy:1, audigy2:1;
21321f1e37cSDavid E. O'Brien u_int32_t addrmask; /* wider if audigy */
214c067afaaSCameron Grant
215c067afaaSCameron Grant bus_space_tag_t st;
216c067afaaSCameron Grant bus_space_handle_t sh;
217c067afaaSCameron Grant bus_dma_tag_t parent_dmat;
218c067afaaSCameron Grant
219c067afaaSCameron Grant struct resource *reg, *irq;
220c067afaaSCameron Grant void *ih;
22100acb133SCameron Grant struct mtx *lock;
222c067afaaSCameron Grant
223a791cfeeSCameron Grant unsigned int bufsz;
224350a5fafSCameron Grant int timer, timerinterval;
22570776a9cSCameron Grant int pnum, rnum;
22621f1e37cSDavid E. O'Brien int nchans;
227c067afaaSCameron Grant struct emu_mem mem;
228c067afaaSCameron Grant struct emu_voice voice[64];
22921f1e37cSDavid E. O'Brien struct sc_pchinfo pch[EMU_MAX_CHANS];
2306c1146c0SCameron Grant struct sc_rchinfo rch[3];
231f510d240SAlexander Leidinger struct mpu401 *mpu;
232f510d240SAlexander Leidinger mpu401_intr_t *mpu_intr;
233f510d240SAlexander Leidinger int mputx;
234c067afaaSCameron Grant };
235c067afaaSCameron Grant
236c067afaaSCameron Grant /* -------------------------------------------------------------------- */
237c067afaaSCameron Grant
238c067afaaSCameron Grant /*
239c067afaaSCameron Grant * prototypes
240c067afaaSCameron Grant */
241c067afaaSCameron Grant
242c067afaaSCameron Grant /* stuff */
243c067afaaSCameron Grant static int emu_init(struct sc_info *);
244c067afaaSCameron Grant static void emu_intr(void *);
24586843ea8SJohn Baldwin static void *emu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr, bus_dmamap_t *map);
24638cc9942SOlivier Houchard static void *emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr);
247c067afaaSCameron Grant static int emu_memfree(struct sc_info *sc, void *buf);
248c067afaaSCameron Grant static int emu_memstart(struct sc_info *sc, void *buf);
2498046c763SCameron Grant #ifdef EMUDEBUG
2508046c763SCameron Grant static void emu_vdump(struct sc_info *sc, struct emu_voice *v);
2518046c763SCameron Grant #endif
252c067afaaSCameron Grant
253c067afaaSCameron Grant /* talk to the card */
254c067afaaSCameron Grant static u_int32_t emu_rd(struct sc_info *, int, int);
255c067afaaSCameron Grant static void emu_wr(struct sc_info *, int, u_int32_t, int);
256c067afaaSCameron Grant
257c067afaaSCameron Grant /* -------------------------------------------------------------------- */
258c067afaaSCameron Grant
259513693beSCameron Grant static u_int32_t emu_rfmt_ac97[] = {
26090da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 1, 0),
26190da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0),
262513693beSCameron Grant 0
263c067afaaSCameron Grant };
264c067afaaSCameron Grant
265513693beSCameron Grant static u_int32_t emu_rfmt_mic[] = {
26690da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 1, 0),
267513693beSCameron Grant 0
268c067afaaSCameron Grant };
269c067afaaSCameron Grant
270513693beSCameron Grant static u_int32_t emu_rfmt_efx[] = {
27190da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0),
272513693beSCameron Grant 0
273513693beSCameron Grant };
274513693beSCameron Grant
27566ef8af5SCameron Grant static struct pcmchan_caps emu_reccaps[3] = {
276513693beSCameron Grant {8000, 48000, emu_rfmt_ac97, 0},
277513693beSCameron Grant {8000, 8000, emu_rfmt_mic, 0},
278513693beSCameron Grant {48000, 48000, emu_rfmt_efx, 0},
279513693beSCameron Grant };
280513693beSCameron Grant
281513693beSCameron Grant static u_int32_t emu_pfmt[] = {
28290da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 1, 0),
28390da2b28SAriff Abdullah SND_FORMAT(AFMT_U8, 2, 0),
28490da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 1, 0),
28590da2b28SAriff Abdullah SND_FORMAT(AFMT_S16_LE, 2, 0),
286513693beSCameron Grant 0
287513693beSCameron Grant };
288513693beSCameron Grant
28966ef8af5SCameron Grant static struct pcmchan_caps emu_playcaps = {4000, 48000, emu_pfmt, 0};
29070776a9cSCameron Grant
29170776a9cSCameron Grant static int adcspeed[8] = {48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000};
29221f1e37cSDavid E. O'Brien /* audigy supports 12kHz. */
29321f1e37cSDavid E. O'Brien static int audigy_adcspeed[9] = {
29421f1e37cSDavid E. O'Brien 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000
29521f1e37cSDavid E. O'Brien };
29670776a9cSCameron Grant
297c067afaaSCameron Grant /* -------------------------------------------------------------------- */
298c067afaaSCameron Grant /* Hardware */
299c067afaaSCameron Grant static u_int32_t
emu_rd(struct sc_info * sc,int regno,int size)300c067afaaSCameron Grant emu_rd(struct sc_info *sc, int regno, int size)
301c067afaaSCameron Grant {
302c067afaaSCameron Grant switch (size) {
303c067afaaSCameron Grant case 1:
304c067afaaSCameron Grant return bus_space_read_1(sc->st, sc->sh, regno);
305c067afaaSCameron Grant case 2:
306c067afaaSCameron Grant return bus_space_read_2(sc->st, sc->sh, regno);
307c067afaaSCameron Grant case 4:
308c067afaaSCameron Grant return bus_space_read_4(sc->st, sc->sh, regno);
309c067afaaSCameron Grant default:
310c067afaaSCameron Grant return 0xffffffff;
311c067afaaSCameron Grant }
312c067afaaSCameron Grant }
313c067afaaSCameron Grant
314c067afaaSCameron Grant static void
emu_wr(struct sc_info * sc,int regno,u_int32_t data,int size)315c067afaaSCameron Grant emu_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
316c067afaaSCameron Grant {
317c067afaaSCameron Grant switch (size) {
318c067afaaSCameron Grant case 1:
319c067afaaSCameron Grant bus_space_write_1(sc->st, sc->sh, regno, data);
320c067afaaSCameron Grant break;
321c067afaaSCameron Grant case 2:
322c067afaaSCameron Grant bus_space_write_2(sc->st, sc->sh, regno, data);
323c067afaaSCameron Grant break;
324c067afaaSCameron Grant case 4:
325c067afaaSCameron Grant bus_space_write_4(sc->st, sc->sh, regno, data);
326c067afaaSCameron Grant break;
327c067afaaSCameron Grant }
328c067afaaSCameron Grant }
329c067afaaSCameron Grant
330c067afaaSCameron Grant static u_int32_t
emu_rdptr(struct sc_info * sc,int chn,int reg)331c067afaaSCameron Grant emu_rdptr(struct sc_info *sc, int chn, int reg)
332c067afaaSCameron Grant {
333c067afaaSCameron Grant u_int32_t ptr, val, mask, size, offset;
334c067afaaSCameron Grant
335c7e0c9dbSPedro F. Giffuni ptr = ((reg << 16) & sc->addrmask) | (chn & EMU_PTR_CHNO_MASK);
336c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_PTR, ptr, 4);
337c7e0c9dbSPedro F. Giffuni val = emu_rd(sc, EMU_DATA, 4);
338c067afaaSCameron Grant if (reg & 0xff000000) {
339c067afaaSCameron Grant size = (reg >> 24) & 0x3f;
340c067afaaSCameron Grant offset = (reg >> 16) & 0x1f;
341c067afaaSCameron Grant mask = ((1 << size) - 1) << offset;
342c067afaaSCameron Grant val &= mask;
343c067afaaSCameron Grant val >>= offset;
344c067afaaSCameron Grant }
345c067afaaSCameron Grant return val;
346c067afaaSCameron Grant }
347c067afaaSCameron Grant
348c067afaaSCameron Grant static void
emu_wrptr(struct sc_info * sc,int chn,int reg,u_int32_t data)349c067afaaSCameron Grant emu_wrptr(struct sc_info *sc, int chn, int reg, u_int32_t data)
350c067afaaSCameron Grant {
351c067afaaSCameron Grant u_int32_t ptr, mask, size, offset;
352c067afaaSCameron Grant
353c7e0c9dbSPedro F. Giffuni ptr = ((reg << 16) & sc->addrmask) | (chn & EMU_PTR_CHNO_MASK);
354c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_PTR, ptr, 4);
355c067afaaSCameron Grant if (reg & 0xff000000) {
356c067afaaSCameron Grant size = (reg >> 24) & 0x3f;
357c067afaaSCameron Grant offset = (reg >> 16) & 0x1f;
358c067afaaSCameron Grant mask = ((1 << size) - 1) << offset;
359c067afaaSCameron Grant data <<= offset;
360c067afaaSCameron Grant data &= mask;
361c7e0c9dbSPedro F. Giffuni data |= emu_rd(sc, EMU_DATA, 4) & ~mask;
362c067afaaSCameron Grant }
363c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_DATA, data, 4);
364c067afaaSCameron Grant }
365c067afaaSCameron Grant
366c067afaaSCameron Grant static void
emu_wrefx(struct sc_info * sc,unsigned int pc,unsigned int data)367c067afaaSCameron Grant emu_wrefx(struct sc_info *sc, unsigned int pc, unsigned int data)
368c067afaaSCameron Grant {
369c7e0c9dbSPedro F. Giffuni pc += sc->audigy ? EMU_A_MICROCODEBASE : EMU_MICROCODEBASE;
37021f1e37cSDavid E. O'Brien emu_wrptr(sc, 0, pc, data);
371c067afaaSCameron Grant }
372c067afaaSCameron Grant
3730f55ac6cSCameron Grant /* -------------------------------------------------------------------- */
3746c1146c0SCameron Grant /* ac97 codec */
37566ef8af5SCameron Grant /* no locking needed */
3760f55ac6cSCameron Grant
3770f55ac6cSCameron Grant static int
emu_rdcd(kobj_t obj,void * devinfo,int regno)3780f55ac6cSCameron Grant emu_rdcd(kobj_t obj, void *devinfo, int regno)
3796c1146c0SCameron Grant {
3806c1146c0SCameron Grant struct sc_info *sc = (struct sc_info *)devinfo;
3816c1146c0SCameron Grant
382c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_AC97ADDR, regno, 1);
383c7e0c9dbSPedro F. Giffuni return emu_rd(sc, EMU_AC97DATA, 2);
3846c1146c0SCameron Grant }
3856c1146c0SCameron Grant
3860f55ac6cSCameron Grant static int
emu_wrcd(kobj_t obj,void * devinfo,int regno,u_int32_t data)3870f55ac6cSCameron Grant emu_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
3886c1146c0SCameron Grant {
3896c1146c0SCameron Grant struct sc_info *sc = (struct sc_info *)devinfo;
3906c1146c0SCameron Grant
391c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_AC97ADDR, regno, 1);
392c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_AC97DATA, data, 2);
3930f55ac6cSCameron Grant return 0;
3946c1146c0SCameron Grant }
3956c1146c0SCameron Grant
3960f55ac6cSCameron Grant static kobj_method_t emu_ac97_methods[] = {
3970f55ac6cSCameron Grant KOBJMETHOD(ac97_read, emu_rdcd),
3980f55ac6cSCameron Grant KOBJMETHOD(ac97_write, emu_wrcd),
39990da2b28SAriff Abdullah KOBJMETHOD_END
4000f55ac6cSCameron Grant };
4010f55ac6cSCameron Grant AC97_DECLARE(emu_ac97);
4020f55ac6cSCameron Grant
4030f55ac6cSCameron Grant /* -------------------------------------------------------------------- */
4046c1146c0SCameron Grant /* stuff */
4056c1146c0SCameron Grant static int
emu_settimer(struct sc_info * sc)406350a5fafSCameron Grant emu_settimer(struct sc_info *sc)
407350a5fafSCameron Grant {
408350a5fafSCameron Grant struct sc_pchinfo *pch;
409350a5fafSCameron Grant struct sc_rchinfo *rch;
410350a5fafSCameron Grant int i, tmp, rate;
411350a5fafSCameron Grant
412350a5fafSCameron Grant rate = 0;
41321f1e37cSDavid E. O'Brien for (i = 0; i < sc->nchans; i++) {
414350a5fafSCameron Grant pch = &sc->pch[i];
415a791cfeeSCameron Grant if (pch->buffer) {
41690da2b28SAriff Abdullah tmp = (pch->spd * sndbuf_getalign(pch->buffer))
41721f1e37cSDavid E. O'Brien / pch->blksz;
418350a5fafSCameron Grant if (tmp > rate)
419350a5fafSCameron Grant rate = tmp;
420350a5fafSCameron Grant }
421a791cfeeSCameron Grant }
422350a5fafSCameron Grant
423350a5fafSCameron Grant for (i = 0; i < 3; i++) {
424350a5fafSCameron Grant rch = &sc->rch[i];
425a791cfeeSCameron Grant if (rch->buffer) {
42690da2b28SAriff Abdullah tmp = (rch->spd * sndbuf_getalign(rch->buffer))
42721f1e37cSDavid E. O'Brien / rch->blksz;
428350a5fafSCameron Grant if (tmp > rate)
429350a5fafSCameron Grant rate = tmp;
430350a5fafSCameron Grant }
431a791cfeeSCameron Grant }
432350a5fafSCameron Grant RANGE(rate, 48, 9600);
433350a5fafSCameron Grant sc->timerinterval = 48000 / rate;
434c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_TIMER, sc->timerinterval & 0x03ff, 2);
435350a5fafSCameron Grant
436350a5fafSCameron Grant return sc->timerinterval;
437350a5fafSCameron Grant }
438350a5fafSCameron Grant
439350a5fafSCameron Grant static int
emu_enatimer(struct sc_info * sc,int go)4406c1146c0SCameron Grant emu_enatimer(struct sc_info *sc, int go)
4416c1146c0SCameron Grant {
4426c1146c0SCameron Grant u_int32_t x;
4436c1146c0SCameron Grant if (go) {
4446c1146c0SCameron Grant if (sc->timer++ == 0) {
445c7e0c9dbSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4);
446c7e0c9dbSPedro F. Giffuni x |= EMU_INTE_INTERTIMERENB;
447c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4);
4486c1146c0SCameron Grant }
4496c1146c0SCameron Grant } else {
4506c1146c0SCameron Grant sc->timer = 0;
451c7e0c9dbSPedro F. Giffuni x = emu_rd(sc, EMU_INTE, 4);
452c7e0c9dbSPedro F. Giffuni x &= ~EMU_INTE_INTERTIMERENB;
453c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, x, 4);
4546c1146c0SCameron Grant }
4556c1146c0SCameron Grant return 0;
4566c1146c0SCameron Grant }
457c067afaaSCameron Grant
458c067afaaSCameron Grant static void
emu_enastop(struct sc_info * sc,char channel,int enable)459c067afaaSCameron Grant emu_enastop(struct sc_info *sc, char channel, int enable)
460c067afaaSCameron Grant {
461c7e0c9dbSPedro F. Giffuni int reg = (channel & 0x20) ? EMU_SOLEH : EMU_SOLEL;
462c067afaaSCameron Grant channel &= 0x1f;
463c067afaaSCameron Grant reg |= 1 << 24;
464c067afaaSCameron Grant reg |= channel << 16;
465c067afaaSCameron Grant emu_wrptr(sc, 0, reg, enable);
466c067afaaSCameron Grant }
467c067afaaSCameron Grant
46870776a9cSCameron Grant static int
emu_recval(int speed)46970776a9cSCameron Grant emu_recval(int speed) {
47070776a9cSCameron Grant int val;
47170776a9cSCameron Grant
47270776a9cSCameron Grant val = 0;
47370776a9cSCameron Grant while (val < 7 && speed < adcspeed[val])
47470776a9cSCameron Grant val++;
47570776a9cSCameron Grant return val;
47670776a9cSCameron Grant }
47770776a9cSCameron Grant
47821f1e37cSDavid E. O'Brien static int
audigy_recval(int speed)47921f1e37cSDavid E. O'Brien audigy_recval(int speed) {
48021f1e37cSDavid E. O'Brien int val;
48121f1e37cSDavid E. O'Brien
48221f1e37cSDavid E. O'Brien val = 0;
48321f1e37cSDavid E. O'Brien while (val < 8 && speed < audigy_adcspeed[val])
48421f1e37cSDavid E. O'Brien val++;
48521f1e37cSDavid E. O'Brien return val;
48621f1e37cSDavid E. O'Brien }
48721f1e37cSDavid E. O'Brien
488c067afaaSCameron Grant static u_int32_t
emu_rate_to_pitch(u_int32_t rate)489c067afaaSCameron Grant emu_rate_to_pitch(u_int32_t rate)
490c067afaaSCameron Grant {
491c067afaaSCameron Grant static u_int32_t logMagTable[128] = {
492c067afaaSCameron Grant 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
493c067afaaSCameron Grant 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
494c067afaaSCameron Grant 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
495c067afaaSCameron Grant 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
496c067afaaSCameron Grant 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
497c067afaaSCameron Grant 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
498c067afaaSCameron Grant 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
499c067afaaSCameron Grant 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
500c067afaaSCameron Grant 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
501c067afaaSCameron Grant 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
502c067afaaSCameron Grant 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
503c067afaaSCameron Grant 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
504c067afaaSCameron Grant 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
505c067afaaSCameron Grant 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
506c067afaaSCameron Grant 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
507c067afaaSCameron Grant 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
508c067afaaSCameron Grant };
509c067afaaSCameron Grant static char logSlopeTable[128] = {
510c067afaaSCameron Grant 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
511c067afaaSCameron Grant 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
512c067afaaSCameron Grant 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
513c067afaaSCameron Grant 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
514c067afaaSCameron Grant 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
515c067afaaSCameron Grant 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
516c067afaaSCameron Grant 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
517c067afaaSCameron Grant 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
518c067afaaSCameron Grant 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
519c067afaaSCameron Grant 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
520c067afaaSCameron Grant 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
521c067afaaSCameron Grant 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
522c067afaaSCameron Grant 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
523c067afaaSCameron Grant 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
524c067afaaSCameron Grant 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
525c067afaaSCameron Grant 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
526c067afaaSCameron Grant };
527c067afaaSCameron Grant int i;
528c067afaaSCameron Grant
529c067afaaSCameron Grant if (rate == 0)
530c067afaaSCameron Grant return 0; /* Bail out if no leading "1" */
531c067afaaSCameron Grant rate *= 11185; /* Scale 48000 to 0x20002380 */
532c067afaaSCameron Grant for (i = 31; i > 0; i--) {
533c067afaaSCameron Grant if (rate & 0x80000000) { /* Detect leading "1" */
534c067afaaSCameron Grant return (((u_int32_t) (i - 15) << 20) +
535c067afaaSCameron Grant logMagTable[0x7f & (rate >> 24)] +
536c067afaaSCameron Grant (0x7f & (rate >> 17)) *
537c067afaaSCameron Grant logSlopeTable[0x7f & (rate >> 24)]);
538c067afaaSCameron Grant }
539c067afaaSCameron Grant rate <<= 1;
540c067afaaSCameron Grant }
541c067afaaSCameron Grant
542c067afaaSCameron Grant return 0; /* Should never reach this point */
543c067afaaSCameron Grant }
544c067afaaSCameron Grant
5456c1146c0SCameron Grant static u_int32_t
emu_rate_to_linearpitch(u_int32_t rate)5466c1146c0SCameron Grant emu_rate_to_linearpitch(u_int32_t rate)
5476c1146c0SCameron Grant {
5486c1146c0SCameron Grant rate = (rate << 8) / 375;
5496c1146c0SCameron Grant return (rate >> 1) + (rate & 1);
5506c1146c0SCameron Grant }
5516c1146c0SCameron Grant
552c067afaaSCameron Grant static struct emu_voice *
emu_valloc(struct sc_info * sc)553c067afaaSCameron Grant emu_valloc(struct sc_info *sc)
554c067afaaSCameron Grant {
555c067afaaSCameron Grant struct emu_voice *v;
556c067afaaSCameron Grant int i;
557c067afaaSCameron Grant
558c067afaaSCameron Grant v = NULL;
559c067afaaSCameron Grant for (i = 0; i < 64 && sc->voice[i].busy; i++);
560c067afaaSCameron Grant if (i < 64) {
561c067afaaSCameron Grant v = &sc->voice[i];
562c067afaaSCameron Grant v->busy = 1;
563c067afaaSCameron Grant }
564c067afaaSCameron Grant return v;
565c067afaaSCameron Grant }
566c067afaaSCameron Grant
567c067afaaSCameron Grant static int
emu_vinit(struct sc_info * sc,struct emu_voice * m,struct emu_voice * s,u_int32_t sz,struct snd_dbuf * b)5686c1146c0SCameron Grant emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
56966ef8af5SCameron Grant u_int32_t sz, struct snd_dbuf *b)
570c067afaaSCameron Grant {
571c067afaaSCameron Grant void *buf;
57238cc9942SOlivier Houchard bus_addr_t tmp_addr;
573c067afaaSCameron Grant
57438cc9942SOlivier Houchard buf = emu_memalloc(sc, sz, &tmp_addr);
575c067afaaSCameron Grant if (buf == NULL)
576c067afaaSCameron Grant return -1;
57766ef8af5SCameron Grant if (b != NULL)
57866ef8af5SCameron Grant sndbuf_setup(b, buf, sz);
579c067afaaSCameron Grant m->start = emu_memstart(sc, buf) * EMUPAGESIZE;
58097b3c9d8SCameron Grant m->end = m->start + sz;
5812d3ce9d5SCameron Grant m->channel = NULL;
582c067afaaSCameron Grant m->speed = 0;
583c067afaaSCameron Grant m->b16 = 0;
584c067afaaSCameron Grant m->stereo = 0;
5856c1146c0SCameron Grant m->running = 0;
5862d3ce9d5SCameron Grant m->ismaster = 1;
5872d3ce9d5SCameron Grant m->vol = 0xff;
58838cc9942SOlivier Houchard m->buf = tmp_addr;
589c067afaaSCameron Grant m->slave = s;
59021f1e37cSDavid E. O'Brien if (sc->audigy) {
5919190333cSAlexander Leidinger m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 8 |
5929190333cSAlexander Leidinger FXBUS_PCM_LEFT << 16 | FXBUS_MIDI_REVERB << 24;
59321f1e37cSDavid E. O'Brien m->fxrt2 = 0x3f3f3f3f; /* No effects on second route */
59421f1e37cSDavid E. O'Brien } else {
5959190333cSAlexander Leidinger m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 4 |
5969190333cSAlexander Leidinger FXBUS_PCM_LEFT << 8 | FXBUS_MIDI_REVERB << 12;
59721f1e37cSDavid E. O'Brien m->fxrt2 = 0;
59821f1e37cSDavid E. O'Brien }
59921f1e37cSDavid E. O'Brien
600c067afaaSCameron Grant if (s != NULL) {
601c067afaaSCameron Grant s->start = m->start;
602c067afaaSCameron Grant s->end = m->end;
603c067afaaSCameron Grant s->channel = NULL;
604c067afaaSCameron Grant s->speed = 0;
605c067afaaSCameron Grant s->b16 = 0;
606c067afaaSCameron Grant s->stereo = 0;
6076c1146c0SCameron Grant s->running = 0;
6082d3ce9d5SCameron Grant s->ismaster = 0;
6092d3ce9d5SCameron Grant s->vol = m->vol;
61097b3c9d8SCameron Grant s->buf = m->buf;
61121f1e37cSDavid E. O'Brien s->fxrt1 = m->fxrt1;
61221f1e37cSDavid E. O'Brien s->fxrt2 = m->fxrt2;
613c067afaaSCameron Grant s->slave = NULL;
614c067afaaSCameron Grant }
615c067afaaSCameron Grant return 0;
616c067afaaSCameron Grant }
617c067afaaSCameron Grant
618c067afaaSCameron Grant static void
emu_vsetup(struct sc_pchinfo * ch)61970776a9cSCameron Grant emu_vsetup(struct sc_pchinfo *ch)
620c067afaaSCameron Grant {
621c067afaaSCameron Grant struct emu_voice *v = ch->master;
622c067afaaSCameron Grant
623c067afaaSCameron Grant if (ch->fmt) {
624c067afaaSCameron Grant v->b16 = (ch->fmt & AFMT_16BIT) ? 1 : 0;
62590da2b28SAriff Abdullah v->stereo = (AFMT_CHANNEL(ch->fmt) > 1) ? 1 : 0;
626c067afaaSCameron Grant if (v->slave != NULL) {
627c067afaaSCameron Grant v->slave->b16 = v->b16;
628c067afaaSCameron Grant v->slave->stereo = v->stereo;
629c067afaaSCameron Grant }
630c067afaaSCameron Grant }
631c067afaaSCameron Grant if (ch->spd) {
632c067afaaSCameron Grant v->speed = ch->spd;
633c067afaaSCameron Grant if (v->slave != NULL)
634c067afaaSCameron Grant v->slave->speed = v->speed;
635c067afaaSCameron Grant }
636c067afaaSCameron Grant }
637c067afaaSCameron Grant
638c067afaaSCameron Grant static void
emu_vwrite(struct sc_info * sc,struct emu_voice * v)639c067afaaSCameron Grant emu_vwrite(struct sc_info *sc, struct emu_voice *v)
640c067afaaSCameron Grant {
6416c1146c0SCameron Grant int s;
6426c1146c0SCameron Grant int l, r, x, y;
6436c1146c0SCameron Grant u_int32_t sa, ea, start, val, silent_page;
644c067afaaSCameron Grant
645c067afaaSCameron Grant s = (v->stereo ? 1 : 0) + (v->b16 ? 1 : 0);
6466c1146c0SCameron Grant
647c067afaaSCameron Grant sa = v->start >> s;
648c067afaaSCameron Grant ea = v->end >> s;
6496c1146c0SCameron Grant
6506c1146c0SCameron Grant l = r = x = y = v->vol;
651c067afaaSCameron Grant if (v->stereo) {
6522d3ce9d5SCameron Grant l = v->ismaster ? l : 0;
6532d3ce9d5SCameron Grant r = v->ismaster ? 0 : r;
654c067afaaSCameron Grant }
655c067afaaSCameron Grant
656c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF, v->stereo ? EMU_CHAN_CPF_STEREO_MASK : 0);
6576c1146c0SCameron Grant val = v->stereo ? 28 : 30;
6586c1146c0SCameron Grant val *= v->b16 ? 1 : 2;
6596c1146c0SCameron Grant start = sa + val;
6606c1146c0SCameron Grant
66121f1e37cSDavid E. O'Brien if (sc->audigy) {
662c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT1, v->fxrt1);
663c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_FXRT2, v->fxrt2);
664c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_A_CHAN_SENDAMOUNTS, 0);
66521f1e37cSDavid E. O'Brien }
66621f1e37cSDavid E. O'Brien else
667c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FXRT, v->fxrt1 << 16);
668c067afaaSCameron Grant
669c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX, (x << 8) | r);
670c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DSL, ea | (y << 24));
671c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PSST, sa | (l << 24));
672c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCCA, start | (v->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT));
673c067afaaSCameron Grant
674c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_Z1, 0);
675c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_Z2, 0);
676c067afaaSCameron Grant
67721f1e37cSDavid E. O'Brien silent_page = ((u_int32_t)(sc->mem.silent_page_addr) << 1)
678c7e0c9dbSPedro F. Giffuni | EMU_CHAN_MAP_PTI_MASK;
679c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_MAPA, silent_page);
680c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_MAPB, silent_page);
681c067afaaSCameron Grant
682c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, EMU_CHAN_CVCF_CURRFILTER_MASK);
683c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, EMU_CHAN_VTFT_FILTERTARGET_MASK);
684c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDM, 0);
685c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSM, EMU_CHAN_DCYSUSM_DECAYTIME_MASK);
686c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL1, 0x8000);
687c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_LFOVAL2, 0x8000);
688c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FMMOD, 0);
689c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_TREMFRQ, 0);
690c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_FM2FRQ2, 0);
691c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVAL, 0x8000);
6926c1146c0SCameron Grant
693c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ATKHLDV,
694c7e0c9dbSPedro F. Giffuni EMU_CHAN_ATKHLDV_HOLDTIME_MASK | EMU_CHAN_ATKHLDV_ATTACKTIME_MASK);
695c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_ENVVOL, 0x8000);
6966c1146c0SCameron Grant
697c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_FILTERAMOUNT, 0x7f);
698c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PEFE_PITCHAMOUNT, 0);
6992d3ce9d5SCameron Grant
7002d3ce9d5SCameron Grant if (v->slave != NULL)
7012d3ce9d5SCameron Grant emu_vwrite(sc, v->slave);
702c067afaaSCameron Grant }
703c067afaaSCameron Grant
704c067afaaSCameron Grant static void
emu_vtrigger(struct sc_info * sc,struct emu_voice * v,int go)705c067afaaSCameron Grant emu_vtrigger(struct sc_info *sc, struct emu_voice *v, int go)
706c067afaaSCameron Grant {
7076c1146c0SCameron Grant u_int32_t pitch_target, initial_pitch;
7086c1146c0SCameron Grant u_int32_t cra, cs, ccis;
7096c1146c0SCameron Grant u_int32_t sample, i;
7106c1146c0SCameron Grant
711c067afaaSCameron Grant if (go) {
7126c1146c0SCameron Grant cra = 64;
7136c1146c0SCameron Grant cs = v->stereo ? 4 : 2;
7146c1146c0SCameron Grant ccis = v->stereo ? 28 : 30;
7156c1146c0SCameron Grant ccis *= v->b16 ? 1 : 2;
7166c1146c0SCameron Grant sample = v->b16 ? 0x00000000 : 0x80808080;
7176c1146c0SCameron Grant
7186c1146c0SCameron Grant for (i = 0; i < cs; i++)
719c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CD0 + i, sample);
720c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
721c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_READADDRESS, cra);
722c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CCR_CACHEINVALIDSIZE, ccis);
7236c1146c0SCameron Grant
724c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xff00);
725c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0xffffffff);
726c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0xffffffff);
727c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_DCYSUSV, 0x00007f7f);
7286c1146c0SCameron Grant emu_enastop(sc, v->vnum, 0);
7296c1146c0SCameron Grant
7306c1146c0SCameron Grant pitch_target = emu_rate_to_linearpitch(v->speed);
7316c1146c0SCameron Grant initial_pitch = emu_rate_to_pitch(v->speed) >> 8;
732c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, pitch_target);
733c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, pitch_target);
734c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IP, initial_pitch);
735c067afaaSCameron Grant } else {
736c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_PTRX_PITCHTARGET, 0);
737c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CPF_PITCH, 0);
738c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IFATN, 0xffff);
739c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_VTFT, 0x0000ffff);
740c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_CVCF, 0x0000ffff);
741c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, v->vnum, EMU_CHAN_IP, 0);
7426c1146c0SCameron Grant emu_enastop(sc, v->vnum, 1);
743c067afaaSCameron Grant }
7442d3ce9d5SCameron Grant if (v->slave != NULL)
7452d3ce9d5SCameron Grant emu_vtrigger(sc, v->slave, go);
746c067afaaSCameron Grant }
747c067afaaSCameron Grant
748c067afaaSCameron Grant static int
emu_vpos(struct sc_info * sc,struct emu_voice * v)749c067afaaSCameron Grant emu_vpos(struct sc_info *sc, struct emu_voice *v)
750c067afaaSCameron Grant {
75170776a9cSCameron Grant int s, ptr;
75270776a9cSCameron Grant
753c067afaaSCameron Grant s = (v->b16 ? 1 : 0) + (v->stereo ? 1 : 0);
754c7e0c9dbSPedro F. Giffuni ptr = (emu_rdptr(sc, v->vnum, EMU_CHAN_CCCA_CURRADDR) - (v->start >> s)) << s;
7556c1146c0SCameron Grant return ptr & ~0x0000001f;
756c067afaaSCameron Grant }
757c067afaaSCameron Grant
758c067afaaSCameron Grant #ifdef EMUDEBUG
759c067afaaSCameron Grant static void
emu_vdump(struct sc_info * sc,struct emu_voice * v)760c067afaaSCameron Grant emu_vdump(struct sc_info *sc, struct emu_voice *v)
761c067afaaSCameron Grant {
76282d4d32dSDavid E. O'Brien char *regname[] = {
76382d4d32dSDavid E. O'Brien "cpf", "ptrx", "cvcf", "vtft", "z2", "z1", "psst", "dsl",
764c067afaaSCameron Grant "ccca", "ccr", "clp", "fxrt", "mapa", "mapb", NULL, NULL,
765c067afaaSCameron Grant "envvol", "atkhldv", "dcysusv", "lfoval1",
766c067afaaSCameron Grant "envval", "atkhldm", "dcysusm", "lfoval2",
767c067afaaSCameron Grant "ip", "ifatn", "pefe", "fmmod", "tremfrq", "fmfrq2",
76882d4d32dSDavid E. O'Brien "tempenv"
76982d4d32dSDavid E. O'Brien };
77021f1e37cSDavid E. O'Brien char *regname2[] = {
77121f1e37cSDavid E. O'Brien "mudata1", "mustat1", "mudata2", "mustat2",
77221f1e37cSDavid E. O'Brien "fxwc1", "fxwc2", "spdrate", NULL, NULL,
77321f1e37cSDavid E. O'Brien NULL, NULL, NULL, "fxrt2", "sndamnt", "fxrt1",
77421f1e37cSDavid E. O'Brien NULL, NULL
77521f1e37cSDavid E. O'Brien };
776c067afaaSCameron Grant int i, x;
777c067afaaSCameron Grant
778c067afaaSCameron Grant printf("voice number %d\n", v->vnum);
779c067afaaSCameron Grant for (i = 0, x = 0; i <= 0x1e; i++) {
780c067afaaSCameron Grant if (regname[i] == NULL)
781c067afaaSCameron Grant continue;
782c067afaaSCameron Grant printf("%s\t[%08x]", regname[i], emu_rdptr(sc, v->vnum, i));
783c067afaaSCameron Grant printf("%s", (x == 2) ? "\n" : "\t");
784c067afaaSCameron Grant x++;
785c067afaaSCameron Grant if (x > 2)
786c067afaaSCameron Grant x = 0;
787c067afaaSCameron Grant }
78821f1e37cSDavid E. O'Brien
78921f1e37cSDavid E. O'Brien /* Print out audigy extra registers */
79021f1e37cSDavid E. O'Brien if (sc->audigy) {
79121f1e37cSDavid E. O'Brien for (i = 0; i <= 0xe; i++) {
79221f1e37cSDavid E. O'Brien if (regname2[i] == NULL)
79321f1e37cSDavid E. O'Brien continue;
79421f1e37cSDavid E. O'Brien printf("%s\t[%08x]", regname2[i],
79521f1e37cSDavid E. O'Brien emu_rdptr(sc, v->vnum, i + 0x70));
79621f1e37cSDavid E. O'Brien printf("%s", (x == 2)? "\n" : "\t");
79721f1e37cSDavid E. O'Brien x++;
79821f1e37cSDavid E. O'Brien if (x > 2)
79921f1e37cSDavid E. O'Brien x = 0;
80021f1e37cSDavid E. O'Brien }
80121f1e37cSDavid E. O'Brien }
802c067afaaSCameron Grant printf("\n\n");
803c067afaaSCameron Grant }
804c067afaaSCameron Grant #endif
805c067afaaSCameron Grant
806c067afaaSCameron Grant /* channel interface */
8070f55ac6cSCameron Grant static void *
emupchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)80821f1e37cSDavid E. O'Brien emupchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
80921f1e37cSDavid E. O'Brien struct pcm_channel *c, int dir)
810c067afaaSCameron Grant {
811c067afaaSCameron Grant struct sc_info *sc = devinfo;
81270776a9cSCameron Grant struct sc_pchinfo *ch;
81366ef8af5SCameron Grant void *r;
814c067afaaSCameron Grant
81570776a9cSCameron Grant KASSERT(dir == PCMDIR_PLAY, ("emupchan_init: bad direction"));
81670776a9cSCameron Grant ch = &sc->pch[sc->pnum++];
817c067afaaSCameron Grant ch->buffer = b;
818c067afaaSCameron Grant ch->parent = sc;
819c067afaaSCameron Grant ch->channel = c;
820a791cfeeSCameron Grant ch->blksz = sc->bufsz / 2;
82190da2b28SAriff Abdullah ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
822350a5fafSCameron Grant ch->spd = 8000;
82366ef8af5SCameron Grant snd_mtxlock(sc->lock);
824c067afaaSCameron Grant ch->master = emu_valloc(sc);
825c067afaaSCameron Grant ch->slave = emu_valloc(sc);
82666ef8af5SCameron Grant snd_mtxunlock(sc->lock);
82721f1e37cSDavid E. O'Brien r = (emu_vinit(sc, ch->master, ch->slave, sc->bufsz, ch->buffer))
82821f1e37cSDavid E. O'Brien ? NULL : ch;
82966ef8af5SCameron Grant
83066ef8af5SCameron Grant return r;
831c067afaaSCameron Grant }
832c067afaaSCameron Grant
833c067afaaSCameron Grant static int
emupchan_free(kobj_t obj,void * data)8340f55ac6cSCameron Grant emupchan_free(kobj_t obj, void *data)
83533dbf14aSCameron Grant {
83633dbf14aSCameron Grant struct sc_pchinfo *ch = data;
83733dbf14aSCameron Grant struct sc_info *sc = ch->parent;
83866ef8af5SCameron Grant int r;
83933dbf14aSCameron Grant
84066ef8af5SCameron Grant snd_mtxlock(sc->lock);
84166ef8af5SCameron Grant r = emu_memfree(sc, sndbuf_getbuf(ch->buffer));
84266ef8af5SCameron Grant snd_mtxunlock(sc->lock);
84366ef8af5SCameron Grant
84466ef8af5SCameron Grant return r;
84533dbf14aSCameron Grant }
84633dbf14aSCameron Grant
84733dbf14aSCameron Grant static int
emupchan_setformat(kobj_t obj,void * data,u_int32_t format)8480f55ac6cSCameron Grant emupchan_setformat(kobj_t obj, void *data, u_int32_t format)
849c067afaaSCameron Grant {
85070776a9cSCameron Grant struct sc_pchinfo *ch = data;
851c067afaaSCameron Grant
852c067afaaSCameron Grant ch->fmt = format;
853c067afaaSCameron Grant return 0;
854c067afaaSCameron Grant }
855c067afaaSCameron Grant
85690da2b28SAriff Abdullah static u_int32_t
emupchan_setspeed(kobj_t obj,void * data,u_int32_t speed)8570f55ac6cSCameron Grant emupchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
858c067afaaSCameron Grant {
85970776a9cSCameron Grant struct sc_pchinfo *ch = data;
860c067afaaSCameron Grant
861c067afaaSCameron Grant ch->spd = speed;
862c067afaaSCameron Grant return ch->spd;
863c067afaaSCameron Grant }
864c067afaaSCameron Grant
86590da2b28SAriff Abdullah static u_int32_t
emupchan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)8660f55ac6cSCameron Grant emupchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
867c067afaaSCameron Grant {
868350a5fafSCameron Grant struct sc_pchinfo *ch = data;
869350a5fafSCameron Grant struct sc_info *sc = ch->parent;
870350a5fafSCameron Grant
871350a5fafSCameron Grant ch->blksz = blocksize;
87266ef8af5SCameron Grant snd_mtxlock(sc->lock);
873350a5fafSCameron Grant emu_settimer(sc);
87466ef8af5SCameron Grant snd_mtxunlock(sc->lock);
875c067afaaSCameron Grant return blocksize;
876c067afaaSCameron Grant }
877c067afaaSCameron Grant
878c067afaaSCameron Grant static int
emupchan_trigger(kobj_t obj,void * data,int go)8790f55ac6cSCameron Grant emupchan_trigger(kobj_t obj, void *data, int go)
880c067afaaSCameron Grant {
88170776a9cSCameron Grant struct sc_pchinfo *ch = data;
882c067afaaSCameron Grant struct sc_info *sc = ch->parent;
883c067afaaSCameron Grant
884bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go))
88535f9e4a1SCameron Grant return 0;
88635f9e4a1SCameron Grant
88766ef8af5SCameron Grant snd_mtxlock(sc->lock);
888c067afaaSCameron Grant if (go == PCMTRIG_START) {
889c067afaaSCameron Grant emu_vsetup(ch);
890c067afaaSCameron Grant emu_vwrite(sc, ch->master);
891350a5fafSCameron Grant emu_settimer(sc);
8926c1146c0SCameron Grant emu_enatimer(sc, 1);
893c067afaaSCameron Grant #ifdef EMUDEBUG
894c067afaaSCameron Grant printf("start [%d bit, %s, %d hz]\n",
895c067afaaSCameron Grant ch->master->b16 ? 16 : 8,
896c067afaaSCameron Grant ch->master->stereo ? "stereo" : "mono",
897c067afaaSCameron Grant ch->master->speed);
898c067afaaSCameron Grant emu_vdump(sc, ch->master);
899c067afaaSCameron Grant emu_vdump(sc, ch->slave);
900c067afaaSCameron Grant #endif
901c067afaaSCameron Grant }
90270776a9cSCameron Grant ch->run = (go == PCMTRIG_START) ? 1 : 0;
90370776a9cSCameron Grant emu_vtrigger(sc, ch->master, ch->run);
90466ef8af5SCameron Grant snd_mtxunlock(sc->lock);
905c067afaaSCameron Grant return 0;
906c067afaaSCameron Grant }
907c067afaaSCameron Grant
90890da2b28SAriff Abdullah static u_int32_t
emupchan_getptr(kobj_t obj,void * data)9090f55ac6cSCameron Grant emupchan_getptr(kobj_t obj, void *data)
910c067afaaSCameron Grant {
91170776a9cSCameron Grant struct sc_pchinfo *ch = data;
912c067afaaSCameron Grant struct sc_info *sc = ch->parent;
91366ef8af5SCameron Grant int r;
914c067afaaSCameron Grant
91566ef8af5SCameron Grant snd_mtxlock(sc->lock);
91666ef8af5SCameron Grant r = emu_vpos(sc, ch->master);
91766ef8af5SCameron Grant snd_mtxunlock(sc->lock);
91866ef8af5SCameron Grant
91966ef8af5SCameron Grant return r;
920c067afaaSCameron Grant }
921c067afaaSCameron Grant
92266ef8af5SCameron Grant static struct pcmchan_caps *
emupchan_getcaps(kobj_t obj,void * data)9230f55ac6cSCameron Grant emupchan_getcaps(kobj_t obj, void *data)
924c067afaaSCameron Grant {
92570776a9cSCameron Grant return &emu_playcaps;
92670776a9cSCameron Grant }
927c067afaaSCameron Grant
9280f55ac6cSCameron Grant static kobj_method_t emupchan_methods[] = {
9290f55ac6cSCameron Grant KOBJMETHOD(channel_init, emupchan_init),
9300f55ac6cSCameron Grant KOBJMETHOD(channel_free, emupchan_free),
9310f55ac6cSCameron Grant KOBJMETHOD(channel_setformat, emupchan_setformat),
9320f55ac6cSCameron Grant KOBJMETHOD(channel_setspeed, emupchan_setspeed),
9330f55ac6cSCameron Grant KOBJMETHOD(channel_setblocksize, emupchan_setblocksize),
9340f55ac6cSCameron Grant KOBJMETHOD(channel_trigger, emupchan_trigger),
9350f55ac6cSCameron Grant KOBJMETHOD(channel_getptr, emupchan_getptr),
9360f55ac6cSCameron Grant KOBJMETHOD(channel_getcaps, emupchan_getcaps),
93790da2b28SAriff Abdullah KOBJMETHOD_END
9380f55ac6cSCameron Grant };
9390f55ac6cSCameron Grant CHANNEL_DECLARE(emupchan);
9400f55ac6cSCameron Grant
94170776a9cSCameron Grant /* channel interface */
94270776a9cSCameron Grant static void *
emurchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)94321f1e37cSDavid E. O'Brien emurchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
94421f1e37cSDavid E. O'Brien struct pcm_channel *c, int dir)
94570776a9cSCameron Grant {
94670776a9cSCameron Grant struct sc_info *sc = devinfo;
94770776a9cSCameron Grant struct sc_rchinfo *ch;
94870776a9cSCameron Grant
9496c1146c0SCameron Grant KASSERT(dir == PCMDIR_REC, ("emurchan_init: bad direction"));
95070776a9cSCameron Grant ch = &sc->rch[sc->rnum];
95170776a9cSCameron Grant ch->buffer = b;
95270776a9cSCameron Grant ch->parent = sc;
95370776a9cSCameron Grant ch->channel = c;
954a791cfeeSCameron Grant ch->blksz = sc->bufsz / 2;
95590da2b28SAriff Abdullah ch->fmt = SND_FORMAT(AFMT_U8, 1, 0);
95670776a9cSCameron Grant ch->spd = 8000;
95770776a9cSCameron Grant ch->num = sc->rnum;
95870776a9cSCameron Grant switch(sc->rnum) {
95970776a9cSCameron Grant case 0:
960c7e0c9dbSPedro F. Giffuni ch->idxreg = sc->audigy ? EMU_A_ADCIDX : EMU_ADCIDX;
961c7e0c9dbSPedro F. Giffuni ch->basereg = EMU_ADCBA;
962c7e0c9dbSPedro F. Giffuni ch->sizereg = EMU_ADCBS;
963c7e0c9dbSPedro F. Giffuni ch->setupreg = EMU_ADCCR;
964c7e0c9dbSPedro F. Giffuni ch->irqmask = EMU_INTE_ADCBUFENABLE;
96570776a9cSCameron Grant break;
96670776a9cSCameron Grant
96770776a9cSCameron Grant case 1:
968c7e0c9dbSPedro F. Giffuni ch->idxreg = EMU_FXIDX;
969c7e0c9dbSPedro F. Giffuni ch->basereg = EMU_FXBA;
970c7e0c9dbSPedro F. Giffuni ch->sizereg = EMU_FXBS;
971c7e0c9dbSPedro F. Giffuni ch->setupreg = EMU_FXWC;
972c7e0c9dbSPedro F. Giffuni ch->irqmask = EMU_INTE_EFXBUFENABLE;
97370776a9cSCameron Grant break;
974a791cfeeSCameron Grant
975a791cfeeSCameron Grant case 2:
976c7e0c9dbSPedro F. Giffuni ch->idxreg = EMU_MICIDX;
977c7e0c9dbSPedro F. Giffuni ch->basereg = EMU_MICBA;
978c7e0c9dbSPedro F. Giffuni ch->sizereg = EMU_MICBS;
979a791cfeeSCameron Grant ch->setupreg = 0;
980c7e0c9dbSPedro F. Giffuni ch->irqmask = EMU_INTE_MICBUFENABLE;
981a791cfeeSCameron Grant break;
98270776a9cSCameron Grant }
98370776a9cSCameron Grant sc->rnum++;
9842e334adfSAriff Abdullah if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0)
98570776a9cSCameron Grant return NULL;
98670776a9cSCameron Grant else {
98766ef8af5SCameron Grant snd_mtxlock(sc->lock);
98838cc9942SOlivier Houchard emu_wrptr(sc, 0, ch->basereg, sndbuf_getbufaddr(ch->buffer));
98970776a9cSCameron Grant emu_wrptr(sc, 0, ch->sizereg, 0); /* off */
99066ef8af5SCameron Grant snd_mtxunlock(sc->lock);
99170776a9cSCameron Grant return ch;
99270776a9cSCameron Grant }
99370776a9cSCameron Grant }
99470776a9cSCameron Grant
99570776a9cSCameron Grant static int
emurchan_setformat(kobj_t obj,void * data,u_int32_t format)9960f55ac6cSCameron Grant emurchan_setformat(kobj_t obj, void *data, u_int32_t format)
99770776a9cSCameron Grant {
99870776a9cSCameron Grant struct sc_rchinfo *ch = data;
99970776a9cSCameron Grant
100070776a9cSCameron Grant ch->fmt = format;
100170776a9cSCameron Grant return 0;
100270776a9cSCameron Grant }
100370776a9cSCameron Grant
100490da2b28SAriff Abdullah static u_int32_t
emurchan_setspeed(kobj_t obj,void * data,u_int32_t speed)10050f55ac6cSCameron Grant emurchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
100670776a9cSCameron Grant {
100770776a9cSCameron Grant struct sc_rchinfo *ch = data;
100870776a9cSCameron Grant
100921f1e37cSDavid E. O'Brien if (ch->num == 0) {
101021f1e37cSDavid E. O'Brien if (ch->parent->audigy)
101121f1e37cSDavid E. O'Brien speed = audigy_adcspeed[audigy_recval(speed)];
101221f1e37cSDavid E. O'Brien else
101370776a9cSCameron Grant speed = adcspeed[emu_recval(speed)];
101421f1e37cSDavid E. O'Brien }
101570776a9cSCameron Grant if (ch->num == 1)
101670776a9cSCameron Grant speed = 48000;
1017a791cfeeSCameron Grant if (ch->num == 2)
1018a791cfeeSCameron Grant speed = 8000;
101970776a9cSCameron Grant ch->spd = speed;
102070776a9cSCameron Grant return ch->spd;
102170776a9cSCameron Grant }
102270776a9cSCameron Grant
102390da2b28SAriff Abdullah static u_int32_t
emurchan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)10240f55ac6cSCameron Grant emurchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
102570776a9cSCameron Grant {
1026350a5fafSCameron Grant struct sc_rchinfo *ch = data;
1027350a5fafSCameron Grant struct sc_info *sc = ch->parent;
1028350a5fafSCameron Grant
1029350a5fafSCameron Grant ch->blksz = blocksize;
103066ef8af5SCameron Grant snd_mtxlock(sc->lock);
1031350a5fafSCameron Grant emu_settimer(sc);
103266ef8af5SCameron Grant snd_mtxunlock(sc->lock);
103370776a9cSCameron Grant return blocksize;
103470776a9cSCameron Grant }
103570776a9cSCameron Grant
103670776a9cSCameron Grant /* semantic note: must start at beginning of buffer */
103770776a9cSCameron Grant static int
emurchan_trigger(kobj_t obj,void * data,int go)10380f55ac6cSCameron Grant emurchan_trigger(kobj_t obj, void *data, int go)
103970776a9cSCameron Grant {
104070776a9cSCameron Grant struct sc_rchinfo *ch = data;
104170776a9cSCameron Grant struct sc_info *sc = ch->parent;
1042a791cfeeSCameron Grant u_int32_t val, sz;
1043a791cfeeSCameron Grant
1044bdfbdcecSAriff Abdullah if (!PCMTRIG_COMMON(go))
1045bdfbdcecSAriff Abdullah return 0;
1046bdfbdcecSAriff Abdullah
1047a791cfeeSCameron Grant switch(sc->bufsz) {
1048a791cfeeSCameron Grant case 4096:
1049c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_4096;
1050a791cfeeSCameron Grant break;
1051a791cfeeSCameron Grant
1052a791cfeeSCameron Grant case 8192:
1053c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_8192;
1054a791cfeeSCameron Grant break;
1055a791cfeeSCameron Grant
1056a791cfeeSCameron Grant case 16384:
1057c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_16384;
1058a791cfeeSCameron Grant break;
1059a791cfeeSCameron Grant
1060a791cfeeSCameron Grant case 32768:
1061c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_32768;
1062a791cfeeSCameron Grant break;
1063a791cfeeSCameron Grant
1064a791cfeeSCameron Grant case 65536:
1065c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_65536;
1066a791cfeeSCameron Grant break;
1067a791cfeeSCameron Grant
1068a791cfeeSCameron Grant default:
1069c7e0c9dbSPedro F. Giffuni sz = EMU_RECBS_BUFSIZE_4096;
1070a791cfeeSCameron Grant }
107170776a9cSCameron Grant
107266ef8af5SCameron Grant snd_mtxlock(sc->lock);
107370776a9cSCameron Grant switch(go) {
107470776a9cSCameron Grant case PCMTRIG_START:
107570776a9cSCameron Grant ch->run = 1;
1076a791cfeeSCameron Grant emu_wrptr(sc, 0, ch->sizereg, sz);
107770776a9cSCameron Grant if (ch->num == 0) {
107821f1e37cSDavid E. O'Brien if (sc->audigy) {
10797523592fSPedro F. Giffuni val = EMU_A_ADCCR_LCHANENABLE;
108090da2b28SAriff Abdullah if (AFMT_CHANNEL(ch->fmt) > 1)
10817523592fSPedro F. Giffuni val |= EMU_A_ADCCR_RCHANENABLE;
108221f1e37cSDavid E. O'Brien val |= audigy_recval(ch->spd);
108321f1e37cSDavid E. O'Brien } else {
1084c7e0c9dbSPedro F. Giffuni val = EMU_ADCCR_LCHANENABLE;
108590da2b28SAriff Abdullah if (AFMT_CHANNEL(ch->fmt) > 1)
1086c7e0c9dbSPedro F. Giffuni val |= EMU_ADCCR_RCHANENABLE;
108770776a9cSCameron Grant val |= emu_recval(ch->spd);
108821f1e37cSDavid E. O'Brien }
108921f1e37cSDavid E. O'Brien
1090a791cfeeSCameron Grant emu_wrptr(sc, 0, ch->setupreg, 0);
109170776a9cSCameron Grant emu_wrptr(sc, 0, ch->setupreg, val);
109270776a9cSCameron Grant }
1093c7e0c9dbSPedro F. Giffuni val = emu_rd(sc, EMU_INTE, 4);
109470776a9cSCameron Grant val |= ch->irqmask;
1095c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, val, 4);
109670776a9cSCameron Grant break;
109770776a9cSCameron Grant
109870776a9cSCameron Grant case PCMTRIG_STOP:
109970776a9cSCameron Grant case PCMTRIG_ABORT:
110070776a9cSCameron Grant ch->run = 0;
110170776a9cSCameron Grant emu_wrptr(sc, 0, ch->sizereg, 0);
110270776a9cSCameron Grant if (ch->setupreg)
110370776a9cSCameron Grant emu_wrptr(sc, 0, ch->setupreg, 0);
1104c7e0c9dbSPedro F. Giffuni val = emu_rd(sc, EMU_INTE, 4);
110570776a9cSCameron Grant val &= ~ch->irqmask;
1106c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, val, 4);
110770776a9cSCameron Grant break;
110870776a9cSCameron Grant
110970776a9cSCameron Grant case PCMTRIG_EMLDMAWR:
111070776a9cSCameron Grant case PCMTRIG_EMLDMARD:
111170776a9cSCameron Grant default:
111270776a9cSCameron Grant break;
111370776a9cSCameron Grant }
111466ef8af5SCameron Grant snd_mtxunlock(sc->lock);
111570776a9cSCameron Grant
111670776a9cSCameron Grant return 0;
111770776a9cSCameron Grant }
111870776a9cSCameron Grant
111990da2b28SAriff Abdullah static u_int32_t
emurchan_getptr(kobj_t obj,void * data)11200f55ac6cSCameron Grant emurchan_getptr(kobj_t obj, void *data)
112170776a9cSCameron Grant {
112270776a9cSCameron Grant struct sc_rchinfo *ch = data;
112370776a9cSCameron Grant struct sc_info *sc = ch->parent;
112466ef8af5SCameron Grant int r;
112570776a9cSCameron Grant
112666ef8af5SCameron Grant snd_mtxlock(sc->lock);
112766ef8af5SCameron Grant r = emu_rdptr(sc, 0, ch->idxreg) & 0x0000ffff;
112866ef8af5SCameron Grant snd_mtxunlock(sc->lock);
112966ef8af5SCameron Grant
113066ef8af5SCameron Grant return r;
113170776a9cSCameron Grant }
113270776a9cSCameron Grant
113366ef8af5SCameron Grant static struct pcmchan_caps *
emurchan_getcaps(kobj_t obj,void * data)11340f55ac6cSCameron Grant emurchan_getcaps(kobj_t obj, void *data)
113570776a9cSCameron Grant {
113670776a9cSCameron Grant struct sc_rchinfo *ch = data;
113770776a9cSCameron Grant
113870776a9cSCameron Grant return &emu_reccaps[ch->num];
1139c067afaaSCameron Grant }
1140c067afaaSCameron Grant
1141a791cfeeSCameron Grant static kobj_method_t emurchan_methods[] = {
1142a791cfeeSCameron Grant KOBJMETHOD(channel_init, emurchan_init),
1143a791cfeeSCameron Grant KOBJMETHOD(channel_setformat, emurchan_setformat),
1144a791cfeeSCameron Grant KOBJMETHOD(channel_setspeed, emurchan_setspeed),
1145a791cfeeSCameron Grant KOBJMETHOD(channel_setblocksize, emurchan_setblocksize),
1146a791cfeeSCameron Grant KOBJMETHOD(channel_trigger, emurchan_trigger),
1147a791cfeeSCameron Grant KOBJMETHOD(channel_getptr, emurchan_getptr),
1148a791cfeeSCameron Grant KOBJMETHOD(channel_getcaps, emurchan_getcaps),
114990da2b28SAriff Abdullah KOBJMETHOD_END
1150a791cfeeSCameron Grant };
1151a791cfeeSCameron Grant CHANNEL_DECLARE(emurchan);
1152a791cfeeSCameron Grant
1153f510d240SAlexander Leidinger static unsigned char
emu_mread(struct mpu401 * arg,void * sc,int reg)115490da2b28SAriff Abdullah emu_mread(struct mpu401 *arg, void *sc, int reg)
1155f510d240SAlexander Leidinger {
1156f510d240SAlexander Leidinger unsigned int d;
1157f510d240SAlexander Leidinger
115890da2b28SAriff Abdullah d = emu_rd((struct sc_info *)sc, 0x18 + reg, 1);
1159f510d240SAlexander Leidinger return d;
1160f510d240SAlexander Leidinger }
1161f510d240SAlexander Leidinger
1162f510d240SAlexander Leidinger static void
emu_mwrite(struct mpu401 * arg,void * sc,int reg,unsigned char b)116390da2b28SAriff Abdullah emu_mwrite(struct mpu401 *arg, void *sc, int reg, unsigned char b)
1164f510d240SAlexander Leidinger {
1165f510d240SAlexander Leidinger
116690da2b28SAriff Abdullah emu_wr((struct sc_info *)sc, 0x18 + reg, b, 1);
1167f510d240SAlexander Leidinger }
1168f510d240SAlexander Leidinger
1169f510d240SAlexander Leidinger static int
emu_muninit(struct mpu401 * arg,void * cookie)117090da2b28SAriff Abdullah emu_muninit(struct mpu401 *arg, void *cookie)
1171f510d240SAlexander Leidinger {
117290da2b28SAriff Abdullah struct sc_info *sc = cookie;
1173f510d240SAlexander Leidinger
1174f510d240SAlexander Leidinger snd_mtxlock(sc->lock);
117587d8fcc8SPedro F. Giffuni sc->mpu_intr = NULL;
1176f510d240SAlexander Leidinger snd_mtxunlock(sc->lock);
1177f510d240SAlexander Leidinger
1178f510d240SAlexander Leidinger return 0;
1179f510d240SAlexander Leidinger }
1180f510d240SAlexander Leidinger
1181f510d240SAlexander Leidinger static kobj_method_t emu_mpu_methods[] = {
1182f510d240SAlexander Leidinger KOBJMETHOD(mpufoi_read, emu_mread),
1183f510d240SAlexander Leidinger KOBJMETHOD(mpufoi_write, emu_mwrite),
1184f510d240SAlexander Leidinger KOBJMETHOD(mpufoi_uninit, emu_muninit),
118590da2b28SAriff Abdullah KOBJMETHOD_END
1186f510d240SAlexander Leidinger };
1187f510d240SAlexander Leidinger
118875d7240eSAlexander Leidinger static DEFINE_CLASS(emu_mpu, emu_mpu_methods, 0);
1189f510d240SAlexander Leidinger
1190f510d240SAlexander Leidinger static void
emu_intr2(void * p)1191f510d240SAlexander Leidinger emu_intr2(void *p)
1192f510d240SAlexander Leidinger {
1193f510d240SAlexander Leidinger struct sc_info *sc = (struct sc_info *)p;
1194f510d240SAlexander Leidinger
1195f510d240SAlexander Leidinger if (sc->mpu_intr)
1196f510d240SAlexander Leidinger (sc->mpu_intr)(sc->mpu);
1197f510d240SAlexander Leidinger }
1198f510d240SAlexander Leidinger
1199f510d240SAlexander Leidinger static void
emu_midiattach(struct sc_info * sc)1200f510d240SAlexander Leidinger emu_midiattach(struct sc_info *sc)
1201f510d240SAlexander Leidinger {
1202f510d240SAlexander Leidinger int i;
1203f510d240SAlexander Leidinger
1204c7e0c9dbSPedro F. Giffuni i = emu_rd(sc, EMU_INTE, 4);
1205c7e0c9dbSPedro F. Giffuni i |= EMU_INTE_MIDIRXENABLE;
1206c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, i, 4);
1207f510d240SAlexander Leidinger
1208f510d240SAlexander Leidinger sc->mpu = mpu401_init(&emu_mpu_class, sc, emu_intr2, &sc->mpu_intr);
1209f510d240SAlexander Leidinger }
1210a791cfeeSCameron Grant /* -------------------------------------------------------------------- */
1211c067afaaSCameron Grant /* The interrupt handler */
1212f510d240SAlexander Leidinger
1213c067afaaSCameron Grant static void
emu_intr(void * data)121405478063SMaxime Henrion emu_intr(void *data)
1215c067afaaSCameron Grant {
121605478063SMaxime Henrion struct sc_info *sc = data;
12176c1146c0SCameron Grant u_int32_t stat, ack, i, x;
1218c067afaaSCameron Grant
121905478063SMaxime Henrion snd_mtxlock(sc->lock);
122070776a9cSCameron Grant while (1) {
1221c7e0c9dbSPedro F. Giffuni stat = emu_rd(sc, EMU_IPR, 4);
122270776a9cSCameron Grant if (stat == 0)
122370776a9cSCameron Grant break;
122470776a9cSCameron Grant ack = 0;
1225c067afaaSCameron Grant
1226c067afaaSCameron Grant /* process irq */
1227c7e0c9dbSPedro F. Giffuni if (stat & EMU_IPR_INTERVALTIMER)
1228c7e0c9dbSPedro F. Giffuni ack |= EMU_IPR_INTERVALTIMER;
122970776a9cSCameron Grant
1230c7e0c9dbSPedro F. Giffuni if (stat & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL))
1231c7e0c9dbSPedro F. Giffuni ack |= stat & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL);
123205478063SMaxime Henrion
1233c7e0c9dbSPedro F. Giffuni if (stat & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL))
1234c7e0c9dbSPedro F. Giffuni ack |= stat & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL);
123505478063SMaxime Henrion
1236c7e0c9dbSPedro F. Giffuni if (stat & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL))
1237c7e0c9dbSPedro F. Giffuni ack |= stat & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL);
123805478063SMaxime Henrion
1239c7e0c9dbSPedro F. Giffuni if (stat & EMU_PCIERROR) {
1240c7e0c9dbSPedro F. Giffuni ack |= EMU_PCIERROR;
124170776a9cSCameron Grant device_printf(sc->dev, "pci error\n");
12426c1146c0SCameron Grant /* we still get an nmi with ecc ram even if we ack this */
12436c1146c0SCameron Grant }
1244c7e0c9dbSPedro F. Giffuni if (stat & EMU_IPR_RATETRCHANGE) {
1245c7e0c9dbSPedro F. Giffuni ack |= EMU_IPR_RATETRCHANGE;
124621f1e37cSDavid E. O'Brien #ifdef EMUDEBUG
124721f1e37cSDavid E. O'Brien device_printf(sc->dev,
124821f1e37cSDavid E. O'Brien "sample rate tracker lock status change\n");
124921f1e37cSDavid E. O'Brien #endif
125070776a9cSCameron Grant }
125170776a9cSCameron Grant
1252c73222d0SJohn Baldwin if (stat & EMU_IPR_MIDIRECVBUFE) {
1253f510d240SAlexander Leidinger if (sc->mpu_intr) {
1254f510d240SAlexander Leidinger (sc->mpu_intr)(sc->mpu);
1255c7e0c9dbSPedro F. Giffuni ack |= EMU_IPR_MIDIRECVBUFE | EMU_IPR_MIDITRANSBUFE;
1256f510d240SAlexander Leidinger }
1257c73222d0SJohn Baldwin }
125870776a9cSCameron Grant if (stat & ~ack)
125905478063SMaxime Henrion device_printf(sc->dev, "dodgy irq: %x (harmless)\n",
126005478063SMaxime Henrion stat & ~ack);
1261c067afaaSCameron Grant
1262c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_IPR, stat, 4);
126305478063SMaxime Henrion
126405478063SMaxime Henrion if (ack) {
126505478063SMaxime Henrion snd_mtxunlock(sc->lock);
126605478063SMaxime Henrion
1267c7e0c9dbSPedro F. Giffuni if (ack & EMU_IPR_INTERVALTIMER) {
126805478063SMaxime Henrion x = 0;
126905478063SMaxime Henrion for (i = 0; i < sc->nchans; i++) {
127005478063SMaxime Henrion if (sc->pch[i].run) {
127105478063SMaxime Henrion x = 1;
127205478063SMaxime Henrion chn_intr(sc->pch[i].channel);
127370776a9cSCameron Grant }
1274c067afaaSCameron Grant }
127505478063SMaxime Henrion if (x == 0)
127605478063SMaxime Henrion emu_enatimer(sc, 0);
127705478063SMaxime Henrion }
127805478063SMaxime Henrion
1279c7e0c9dbSPedro F. Giffuni if (ack & (EMU_IPR_ADCBUFFULL | EMU_IPR_ADCBUFHALFFULL)) {
128005478063SMaxime Henrion if (sc->rch[0].channel)
128105478063SMaxime Henrion chn_intr(sc->rch[0].channel);
128205478063SMaxime Henrion }
1283c7e0c9dbSPedro F. Giffuni if (ack & (EMU_IPR_EFXBUFFULL | EMU_IPR_EFXBUFHALFFULL)) {
128405478063SMaxime Henrion if (sc->rch[1].channel)
128505478063SMaxime Henrion chn_intr(sc->rch[1].channel);
128605478063SMaxime Henrion }
1287c7e0c9dbSPedro F. Giffuni if (ack & (EMU_IPR_MICBUFFULL | EMU_IPR_MICBUFHALFFULL)) {
128805478063SMaxime Henrion if (sc->rch[2].channel)
128905478063SMaxime Henrion chn_intr(sc->rch[2].channel);
129005478063SMaxime Henrion }
129105478063SMaxime Henrion
129205478063SMaxime Henrion snd_mtxlock(sc->lock);
129305478063SMaxime Henrion }
129405478063SMaxime Henrion }
129505478063SMaxime Henrion snd_mtxunlock(sc->lock);
129605478063SMaxime Henrion }
1297c067afaaSCameron Grant
1298c067afaaSCameron Grant /* -------------------------------------------------------------------- */
1299c067afaaSCameron Grant
130070776a9cSCameron Grant static void
emu_setmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)130170776a9cSCameron Grant emu_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
130270776a9cSCameron Grant {
130333673595SOlivier Houchard bus_addr_t *phys = arg;
130470776a9cSCameron Grant
130533673595SOlivier Houchard *phys = error ? 0 : (bus_addr_t)segs->ds_addr;
130670776a9cSCameron Grant
130770776a9cSCameron Grant if (bootverbose) {
130870776a9cSCameron Grant printf("emu: setmap (%lx, %lx), nseg=%d, error=%d\n",
130970776a9cSCameron Grant (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len,
131070776a9cSCameron Grant nseg, error);
131170776a9cSCameron Grant }
131270776a9cSCameron Grant }
131370776a9cSCameron Grant
1314c067afaaSCameron Grant static void *
emu_malloc(struct sc_info * sc,u_int32_t sz,bus_addr_t * addr,bus_dmamap_t * map)131586843ea8SJohn Baldwin emu_malloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr,
131686843ea8SJohn Baldwin bus_dmamap_t *map)
1317c067afaaSCameron Grant {
131838cc9942SOlivier Houchard void *buf;
1319c067afaaSCameron Grant
132038cc9942SOlivier Houchard *addr = 0;
132186843ea8SJohn Baldwin if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, map))
1322c067afaaSCameron Grant return NULL;
13231f7a6325SAlexander Motin if (bus_dmamap_load(sc->parent_dmat, *map, buf, sz, emu_setmap, addr,
13241f7a6325SAlexander Motin BUS_DMA_NOWAIT) || !*addr) {
132586843ea8SJohn Baldwin bus_dmamem_free(sc->parent_dmat, buf, *map);
132670776a9cSCameron Grant return NULL;
132786843ea8SJohn Baldwin }
1328c067afaaSCameron Grant return buf;
1329c067afaaSCameron Grant }
1330c067afaaSCameron Grant
1331c067afaaSCameron Grant static void
emu_free(struct sc_info * sc,void * buf,bus_dmamap_t map)133286843ea8SJohn Baldwin emu_free(struct sc_info *sc, void *buf, bus_dmamap_t map)
1333c067afaaSCameron Grant {
133486843ea8SJohn Baldwin bus_dmamap_unload(sc->parent_dmat, map);
133586843ea8SJohn Baldwin bus_dmamem_free(sc->parent_dmat, buf, map);
1336c067afaaSCameron Grant }
1337c067afaaSCameron Grant
1338c067afaaSCameron Grant static void *
emu_memalloc(struct sc_info * sc,u_int32_t sz,bus_addr_t * addr)133938cc9942SOlivier Houchard emu_memalloc(struct sc_info *sc, u_int32_t sz, bus_addr_t *addr)
1340c067afaaSCameron Grant {
1341c067afaaSCameron Grant u_int32_t blksz, start, idx, ofs, tmp, found;
1342c067afaaSCameron Grant struct emu_mem *mem = &sc->mem;
1343c067afaaSCameron Grant struct emu_memblk *blk;
1344c067afaaSCameron Grant void *buf;
1345c067afaaSCameron Grant
1346c067afaaSCameron Grant blksz = sz / EMUPAGESIZE;
1347c067afaaSCameron Grant if (sz > (blksz * EMUPAGESIZE))
1348c067afaaSCameron Grant blksz++;
1349c067afaaSCameron Grant /* find a free block in the bitmap */
1350c067afaaSCameron Grant found = 0;
13516c1146c0SCameron Grant start = 1;
135221f1e37cSDavid E. O'Brien while (!found && start + blksz < EMUMAXPAGES) {
1353c067afaaSCameron Grant found = 1;
1354c067afaaSCameron Grant for (idx = start; idx < start + blksz; idx++)
1355c067afaaSCameron Grant if (mem->bmap[idx >> 3] & (1 << (idx & 7)))
1356c067afaaSCameron Grant found = 0;
1357c067afaaSCameron Grant if (!found)
1358c067afaaSCameron Grant start++;
1359c067afaaSCameron Grant }
1360c067afaaSCameron Grant if (!found)
1361c067afaaSCameron Grant return NULL;
1362c067afaaSCameron Grant blk = malloc(sizeof(*blk), M_DEVBUF, M_NOWAIT);
1363c067afaaSCameron Grant if (blk == NULL)
1364c067afaaSCameron Grant return NULL;
136586843ea8SJohn Baldwin buf = emu_malloc(sc, sz, &blk->buf_addr, &blk->buf_map);
136638cc9942SOlivier Houchard *addr = blk->buf_addr;
1367c067afaaSCameron Grant if (buf == NULL) {
1368c067afaaSCameron Grant free(blk, M_DEVBUF);
1369c067afaaSCameron Grant return NULL;
1370c067afaaSCameron Grant }
1371c067afaaSCameron Grant blk->buf = buf;
1372c067afaaSCameron Grant blk->pte_start = start;
1373c067afaaSCameron Grant blk->pte_size = blksz;
137421f1e37cSDavid E. O'Brien #ifdef EMUDEBUG
137521f1e37cSDavid E. O'Brien printf("buf %p, pte_start %d, pte_size %d\n", blk->buf,
137621f1e37cSDavid E. O'Brien blk->pte_start, blk->pte_size);
137721f1e37cSDavid E. O'Brien #endif
1378c067afaaSCameron Grant ofs = 0;
1379c067afaaSCameron Grant for (idx = start; idx < start + blksz; idx++) {
1380c067afaaSCameron Grant mem->bmap[idx >> 3] |= 1 << (idx & 7);
1381bdec45e2SMarius Strobl tmp = (uint32_t)(blk->buf_addr + ofs);
138221f1e37cSDavid E. O'Brien #ifdef EMUDEBUG
138321f1e37cSDavid E. O'Brien printf("pte[%d] -> %x phys, %x virt\n", idx, tmp,
138421f1e37cSDavid E. O'Brien ((u_int32_t)buf) + ofs);
138521f1e37cSDavid E. O'Brien #endif
138619b6ac09SCameron Grant mem->ptb_pages[idx] = (tmp << 1) | idx;
1387c067afaaSCameron Grant ofs += EMUPAGESIZE;
1388c067afaaSCameron Grant }
1389c067afaaSCameron Grant SLIST_INSERT_HEAD(&mem->blocks, blk, link);
1390c067afaaSCameron Grant return buf;
1391c067afaaSCameron Grant }
1392c067afaaSCameron Grant
1393c067afaaSCameron Grant static int
emu_memfree(struct sc_info * sc,void * buf)1394c067afaaSCameron Grant emu_memfree(struct sc_info *sc, void *buf)
1395c067afaaSCameron Grant {
1396c067afaaSCameron Grant u_int32_t idx, tmp;
1397c067afaaSCameron Grant struct emu_mem *mem = &sc->mem;
1398c067afaaSCameron Grant struct emu_memblk *blk, *i;
1399c067afaaSCameron Grant
1400c067afaaSCameron Grant blk = NULL;
1401c067afaaSCameron Grant SLIST_FOREACH(i, &mem->blocks, link) {
1402c067afaaSCameron Grant if (i->buf == buf)
1403c067afaaSCameron Grant blk = i;
1404c067afaaSCameron Grant }
1405c067afaaSCameron Grant if (blk == NULL)
1406c067afaaSCameron Grant return EINVAL;
1407c067afaaSCameron Grant SLIST_REMOVE(&mem->blocks, blk, emu_memblk, link);
140886843ea8SJohn Baldwin emu_free(sc, buf, blk->buf_map);
140938cc9942SOlivier Houchard tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1;
1410c067afaaSCameron Grant for (idx = blk->pte_start; idx < blk->pte_start + blk->pte_size; idx++) {
1411c067afaaSCameron Grant mem->bmap[idx >> 3] &= ~(1 << (idx & 7));
1412c067afaaSCameron Grant mem->ptb_pages[idx] = tmp | idx;
1413c067afaaSCameron Grant }
1414c067afaaSCameron Grant free(blk, M_DEVBUF);
1415c067afaaSCameron Grant return 0;
1416c067afaaSCameron Grant }
1417c067afaaSCameron Grant
1418c067afaaSCameron Grant static int
emu_memstart(struct sc_info * sc,void * buf)1419c067afaaSCameron Grant emu_memstart(struct sc_info *sc, void *buf)
1420c067afaaSCameron Grant {
1421c067afaaSCameron Grant struct emu_mem *mem = &sc->mem;
1422c067afaaSCameron Grant struct emu_memblk *blk, *i;
1423c067afaaSCameron Grant
1424c067afaaSCameron Grant blk = NULL;
1425c067afaaSCameron Grant SLIST_FOREACH(i, &mem->blocks, link) {
1426c067afaaSCameron Grant if (i->buf == buf)
1427c067afaaSCameron Grant blk = i;
1428c067afaaSCameron Grant }
1429c067afaaSCameron Grant if (blk == NULL)
1430c067afaaSCameron Grant return -EINVAL;
1431c067afaaSCameron Grant return blk->pte_start;
1432c067afaaSCameron Grant }
1433c067afaaSCameron Grant
1434c067afaaSCameron Grant static void
emu_addefxop(struct sc_info * sc,int op,int z,int w,int x,int y,u_int32_t * pc)143521f1e37cSDavid E. O'Brien emu_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
143621f1e37cSDavid E. O'Brien u_int32_t *pc)
1437c067afaaSCameron Grant {
1438c067afaaSCameron Grant emu_wrefx(sc, (*pc) * 2, (x << 10) | y);
1439c067afaaSCameron Grant emu_wrefx(sc, (*pc) * 2 + 1, (op << 20) | (z << 10) | w);
1440c067afaaSCameron Grant (*pc)++;
1441c067afaaSCameron Grant }
1442c067afaaSCameron Grant
1443c067afaaSCameron Grant static void
audigy_addefxop(struct sc_info * sc,int op,int z,int w,int x,int y,u_int32_t * pc)144421f1e37cSDavid E. O'Brien audigy_addefxop(struct sc_info *sc, int op, int z, int w, int x, int y,
144521f1e37cSDavid E. O'Brien u_int32_t *pc)
144621f1e37cSDavid E. O'Brien {
144721f1e37cSDavid E. O'Brien emu_wrefx(sc, (*pc) * 2, (x << 12) | y);
144821f1e37cSDavid E. O'Brien emu_wrefx(sc, (*pc) * 2 + 1, (op << 24) | (z << 12) | w);
144921f1e37cSDavid E. O'Brien (*pc)++;
145021f1e37cSDavid E. O'Brien }
145121f1e37cSDavid E. O'Brien
145221f1e37cSDavid E. O'Brien static void
audigy_initefx(struct sc_info * sc)145321f1e37cSDavid E. O'Brien audigy_initefx(struct sc_info *sc)
145421f1e37cSDavid E. O'Brien {
145521f1e37cSDavid E. O'Brien int i;
145621f1e37cSDavid E. O'Brien u_int32_t pc = 0;
145721f1e37cSDavid E. O'Brien
145821f1e37cSDavid E. O'Brien /* skip 0, 0, -1, 0 - NOPs */
145921f1e37cSDavid E. O'Brien for (i = 0; i < 512; i++)
146021f1e37cSDavid E. O'Brien audigy_addefxop(sc, 0x0f, 0x0c0, 0x0c0, 0x0cf, 0x0c0, &pc);
146121f1e37cSDavid E. O'Brien
146221f1e37cSDavid E. O'Brien for (i = 0; i < 512; i++)
1463c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_FXGPREGBASE + i, 0x0);
146421f1e37cSDavid E. O'Brien
146521f1e37cSDavid E. O'Brien pc = 16;
146621f1e37cSDavid E. O'Brien
146721f1e37cSDavid E. O'Brien /* stop fx processor */
1468c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
146921f1e37cSDavid E. O'Brien
147021f1e37cSDavid E. O'Brien /* Audigy 2 (EMU10K2) DSP Registers:
147121f1e37cSDavid E. O'Brien FX Bus
147230baa78dSAlexander Leidinger 0x000-0x00f : 16 registers (?)
147321f1e37cSDavid E. O'Brien Input
147421f1e37cSDavid E. O'Brien 0x040/0x041 : AC97 Codec (l/r)
147521f1e37cSDavid E. O'Brien 0x042/0x043 : ADC, S/PDIF (l/r)
147621f1e37cSDavid E. O'Brien 0x044/0x045 : Optical S/PDIF in (l/r)
147730baa78dSAlexander Leidinger 0x046/0x047 : ?
147821f1e37cSDavid E. O'Brien 0x048/0x049 : Line/Mic 2 (l/r)
147921f1e37cSDavid E. O'Brien 0x04a/0x04b : RCA S/PDIF (l/r)
148021f1e37cSDavid E. O'Brien 0x04c/0x04d : Aux 2 (l/r)
148121f1e37cSDavid E. O'Brien Output
148221f1e37cSDavid E. O'Brien 0x060/0x061 : Digital Front (l/r)
148321f1e37cSDavid E. O'Brien 0x062/0x063 : Digital Center/LFE
148421f1e37cSDavid E. O'Brien 0x064/0x065 : AudigyDrive Heaphone (l/r)
148521f1e37cSDavid E. O'Brien 0x066/0x067 : Digital Rear (l/r)
148621f1e37cSDavid E. O'Brien 0x068/0x069 : Analog Front (l/r)
148721f1e37cSDavid E. O'Brien 0x06a/0x06b : Analog Center/LFE
148830baa78dSAlexander Leidinger 0x06c/0x06d : ?
148921f1e37cSDavid E. O'Brien 0x06e/0x06f : Analog Rear (l/r)
149021f1e37cSDavid E. O'Brien 0x070/0x071 : AC97 Output (l/r)
149130baa78dSAlexander Leidinger 0x072/0x073 : ?
149230baa78dSAlexander Leidinger 0x074/0x075 : ?
149321f1e37cSDavid E. O'Brien 0x076/0x077 : ADC Recording Buffer (l/r)
149421f1e37cSDavid E. O'Brien Constants
149521f1e37cSDavid E. O'Brien 0x0c0 - 0x0c4 = 0 - 4
149621f1e37cSDavid E. O'Brien 0x0c5 = 0x8, 0x0c6 = 0x10, 0x0c7 = 0x20
149721f1e37cSDavid E. O'Brien 0x0c8 = 0x100, 0x0c9 = 0x10000, 0x0ca = 0x80000
149821f1e37cSDavid E. O'Brien 0x0cb = 0x10000000, 0x0cc = 0x20000000, 0x0cd = 0x40000000
149921f1e37cSDavid E. O'Brien 0x0ce = 0x80000000, 0x0cf = 0x7fffffff, 0x0d0 = 0xffffffff
150021f1e37cSDavid E. O'Brien 0x0d1 = 0xfffffffe, 0x0d2 = 0xc0000000, 0x0d3 = 0x41fbbcdc
150130baa78dSAlexander Leidinger 0x0d4 = 0x5a7ef9db, 0x0d5 = 0x00100000, 0x0dc = 0x00000001 (?)
150221f1e37cSDavid E. O'Brien Temporary Values
150330baa78dSAlexander Leidinger 0x0d6 : Accumulator (?)
150421f1e37cSDavid E. O'Brien 0x0d7 : Condition Register
150521f1e37cSDavid E. O'Brien 0x0d8 : Noise source
150621f1e37cSDavid E. O'Brien 0x0d9 : Noise source
150721f1e37cSDavid E. O'Brien Tank Memory Data Registers
150821f1e37cSDavid E. O'Brien 0x200 - 0x2ff
150921f1e37cSDavid E. O'Brien Tank Memory Address Registers
151021f1e37cSDavid E. O'Brien 0x300 - 0x3ff
151121f1e37cSDavid E. O'Brien General Purpose Registers
151221f1e37cSDavid E. O'Brien 0x400 - 0x5ff
151321f1e37cSDavid E. O'Brien */
151421f1e37cSDavid E. O'Brien
151521f1e37cSDavid E. O'Brien /* AC97Output[l/r] = FXBus PCM[l/r] */
151621f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_L), A_C_00000000,
151721f1e37cSDavid E. O'Brien A_C_00000000, A_FXBUS(FXBUS_PCM_LEFT), &pc);
151821f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AC97_R), A_C_00000000,
151921f1e37cSDavid E. O'Brien A_C_00000000, A_FXBUS(FXBUS_PCM_RIGHT), &pc);
152021f1e37cSDavid E. O'Brien
152121f1e37cSDavid E. O'Brien /* GPR[0/1] = RCA S/PDIF[l/r] -- Master volume */
152221f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_GPR(0), A_C_00000000,
152321f1e37cSDavid E. O'Brien A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_L), &pc);
152421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_GPR(1), A_C_00000000,
152521f1e37cSDavid E. O'Brien A_C_00000000, A_EXTIN(EXTIN_COAX_SPDIF_R), &pc);
152621f1e37cSDavid E. O'Brien
152721f1e37cSDavid E. O'Brien /* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
152821f1e37cSDavid E. O'Brien audigy_addefxop(sc, iINTERP, A_GPR(2), A_GPR(1),
152921f1e37cSDavid E. O'Brien A_C_40000000, A_GPR(0), &pc);
153021f1e37cSDavid E. O'Brien
153121f1e37cSDavid E. O'Brien /* Headphones[l/r] = GPR[0/1] */
153221f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_L),
153321f1e37cSDavid E. O'Brien A_C_00000000, A_C_00000000, A_GPR(0), &pc);
153421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_HEADPHONE_R),
153521f1e37cSDavid E. O'Brien A_C_00000000, A_C_00000000, A_GPR(1), &pc);
153621f1e37cSDavid E. O'Brien
153721f1e37cSDavid E. O'Brien /* Analog Front[l/r] = GPR[0/1] */
153821f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_L), A_C_00000000,
153921f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(0), &pc);
154021f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AFRONT_R), A_C_00000000,
154121f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(1), &pc);
154221f1e37cSDavid E. O'Brien
154321f1e37cSDavid E. O'Brien /* Digital Front[l/r] = GPR[0/1] */
154421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L), A_C_00000000,
154521f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(0), &pc);
154621f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_FRONT_R), A_C_00000000,
154721f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(1), &pc);
154821f1e37cSDavid E. O'Brien
154921f1e37cSDavid E. O'Brien /* Center and Subwoofer configuration */
155021f1e37cSDavid E. O'Brien /* Analog Center = GPR[0] + GPR[2] */
155121f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ACENTER), A_C_00000000,
155221f1e37cSDavid E. O'Brien A_GPR(0), A_GPR(2), &pc);
155321f1e37cSDavid E. O'Brien /* Analog Sub = GPR[1] + GPR[2] */
155421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ALFE), A_C_00000000,
155521f1e37cSDavid E. O'Brien A_GPR(1), A_GPR(2), &pc);
155621f1e37cSDavid E. O'Brien
155721f1e37cSDavid E. O'Brien /* Digital Center = GPR[0] + GPR[2] */
155821f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_CENTER), A_C_00000000,
155921f1e37cSDavid E. O'Brien A_GPR(0), A_GPR(2), &pc);
156021f1e37cSDavid E. O'Brien /* Digital Sub = GPR[1] + GPR[2] */
156121f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_LFE), A_C_00000000,
156221f1e37cSDavid E. O'Brien A_GPR(1), A_GPR(2), &pc);
156321f1e37cSDavid E. O'Brien
156421f1e37cSDavid E. O'Brien #if 0
156521f1e37cSDavid E. O'Brien /* Analog Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
156621f1e37cSDavid E. O'Brien /* RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
156721f1e37cSDavid E. O'Brien audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
156821f1e37cSDavid E. O'Brien A_GPR(16), A_GPR(0), &pc);
156921f1e37cSDavid E. O'Brien audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
157021f1e37cSDavid E. O'Brien A_GPR(17), A_GPR(1), &pc);
157121f1e37cSDavid E. O'Brien
157221f1e37cSDavid E. O'Brien /* Digital Rear[l/r] = (GPR[0/1] * RearVolume[l/r]) >> 31 */
157321f1e37cSDavid E. O'Brien /* RearVolume = GPR[0x10/0x11] (Will this ever be implemented?) */
157421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
157521f1e37cSDavid E. O'Brien A_GPR(16), A_GPR(0), &pc);
157621f1e37cSDavid E. O'Brien audigy_addefxop(sc, iMAC0, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
157721f1e37cSDavid E. O'Brien A_GPR(17), A_GPR(1), &pc);
157821f1e37cSDavid E. O'Brien #else
157921f1e37cSDavid E. O'Brien /* XXX This is just a copy to the channel, since we do not have
158021f1e37cSDavid E. O'Brien * a patch manager, it is useful for have another output enabled.
158121f1e37cSDavid E. O'Brien */
158221f1e37cSDavid E. O'Brien
158321f1e37cSDavid E. O'Brien /* Analog Rear[l/r] = GPR[0/1] */
158421f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_L), A_C_00000000,
158521f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(0), &pc);
158621f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_AREAR_R), A_C_00000000,
158721f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(1), &pc);
158821f1e37cSDavid E. O'Brien
158921f1e37cSDavid E. O'Brien /* Digital Rear[l/r] = GPR[0/1] */
159021f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_L), A_C_00000000,
159121f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(0), &pc);
159221f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_REAR_R), A_C_00000000,
159321f1e37cSDavid E. O'Brien A_C_00000000, A_GPR(1), &pc);
159421f1e37cSDavid E. O'Brien #endif
159521f1e37cSDavid E. O'Brien
159621f1e37cSDavid E. O'Brien /* ADC Recording buffer[l/r] = AC97Input[l/r] */
159721f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_L), A_C_00000000,
159821f1e37cSDavid E. O'Brien A_C_00000000, A_EXTIN(A_EXTIN_AC97_L), &pc);
159921f1e37cSDavid E. O'Brien audigy_addefxop(sc, iACC3, A_EXTOUT(A_EXTOUT_ADC_CAP_R), A_C_00000000,
160021f1e37cSDavid E. O'Brien A_C_00000000, A_EXTIN(A_EXTIN_AC97_R), &pc);
160121f1e37cSDavid E. O'Brien
160221f1e37cSDavid E. O'Brien /* resume normal operations */
1603c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_DBG, 0);
160421f1e37cSDavid E. O'Brien }
160521f1e37cSDavid E. O'Brien
160621f1e37cSDavid E. O'Brien static void
emu_initefx(struct sc_info * sc)1607c067afaaSCameron Grant emu_initefx(struct sc_info *sc)
1608c067afaaSCameron Grant {
1609c067afaaSCameron Grant int i;
1610c067afaaSCameron Grant u_int32_t pc = 16;
1611c067afaaSCameron Grant
161221f1e37cSDavid E. O'Brien /* acc3 0,0,0,0 - NOPs */
1613c067afaaSCameron Grant for (i = 0; i < 512; i++) {
1614c067afaaSCameron Grant emu_wrefx(sc, i * 2, 0x10040);
1615c067afaaSCameron Grant emu_wrefx(sc, i * 2 + 1, 0x610040);
1616c067afaaSCameron Grant }
1617c067afaaSCameron Grant
1618c067afaaSCameron Grant for (i = 0; i < 256; i++)
1619c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXGPREGBASE + i, 0);
1620c067afaaSCameron Grant
1621c067afaaSCameron Grant /* FX-8010 DSP Registers:
1622c067afaaSCameron Grant FX Bus
1623c067afaaSCameron Grant 0x000-0x00f : 16 registers
1624c067afaaSCameron Grant Input
1625c067afaaSCameron Grant 0x010/0x011 : AC97 Codec (l/r)
1626c067afaaSCameron Grant 0x012/0x013 : ADC, S/PDIF (l/r)
1627c067afaaSCameron Grant 0x014/0x015 : Mic(left), Zoom (l/r)
162821f1e37cSDavid E. O'Brien 0x016/0x017 : TOS link in (l/r)
162921f1e37cSDavid E. O'Brien 0x018/0x019 : Line/Mic 1 (l/r)
163021f1e37cSDavid E. O'Brien 0x01a/0x01b : COAX S/PDIF (l/r)
163121f1e37cSDavid E. O'Brien 0x01c/0x01d : Line/Mic 2 (l/r)
1632c067afaaSCameron Grant Output
1633c067afaaSCameron Grant 0x020/0x021 : AC97 Output (l/r)
1634c067afaaSCameron Grant 0x022/0x023 : TOS link out (l/r)
163521f1e37cSDavid E. O'Brien 0x024/0x025 : Center/LFE
1636c067afaaSCameron Grant 0x026/0x027 : LiveDrive Headphone (l/r)
1637c067afaaSCameron Grant 0x028/0x029 : Rear Channel (l/r)
1638c067afaaSCameron Grant 0x02a/0x02b : ADC Recording Buffer (l/r)
163921f1e37cSDavid E. O'Brien 0x02c : Mic Recording Buffer
164021f1e37cSDavid E. O'Brien 0x031/0x032 : Analog Center/LFE
1641c067afaaSCameron Grant Constants
1642c067afaaSCameron Grant 0x040 - 0x044 = 0 - 4
1643c067afaaSCameron Grant 0x045 = 0x8, 0x046 = 0x10, 0x047 = 0x20
1644c067afaaSCameron Grant 0x048 = 0x100, 0x049 = 0x10000, 0x04a = 0x80000
1645c067afaaSCameron Grant 0x04b = 0x10000000, 0x04c = 0x20000000, 0x04d = 0x40000000
164621f1e37cSDavid E. O'Brien 0x04e = 0x80000000, 0x04f = 0x7fffffff, 0x050 = 0xffffffff
164721f1e37cSDavid E. O'Brien 0x051 = 0xfffffffe, 0x052 = 0xc0000000, 0x053 = 0x41fbbcdc
164821f1e37cSDavid E. O'Brien 0x054 = 0x5a7ef9db, 0x055 = 0x00100000
1649c067afaaSCameron Grant Temporary Values
1650c067afaaSCameron Grant 0x056 : Accumulator
165121f1e37cSDavid E. O'Brien 0x057 : Condition Register
165221f1e37cSDavid E. O'Brien 0x058 : Noise source
165321f1e37cSDavid E. O'Brien 0x059 : Noise source
165421f1e37cSDavid E. O'Brien 0x05a : IRQ Register
165521f1e37cSDavid E. O'Brien 0x05b : TRAM Delay Base Address Count
1656c067afaaSCameron Grant General Purpose Registers
1657c067afaaSCameron Grant 0x100 - 0x1ff
1658c067afaaSCameron Grant Tank Memory Data Registers
1659c067afaaSCameron Grant 0x200 - 0x2ff
1660c067afaaSCameron Grant Tank Memory Address Registers
1661c067afaaSCameron Grant 0x300 - 0x3ff
1662c067afaaSCameron Grant */
1663c067afaaSCameron Grant
1664c067afaaSCameron Grant /* Routing - this will be configurable in later version */
1665c067afaaSCameron Grant
1666c067afaaSCameron Grant /* GPR[0/1] = FX * 4 + SPDIF-in */
166721f1e37cSDavid E. O'Brien emu_addefxop(sc, iMACINT0, GPR(0), EXTIN(EXTIN_SPDIF_CD_L),
166821f1e37cSDavid E. O'Brien FXBUS(FXBUS_PCM_LEFT), C_00000004, &pc);
166921f1e37cSDavid E. O'Brien emu_addefxop(sc, iMACINT0, GPR(1), EXTIN(EXTIN_SPDIF_CD_R),
167021f1e37cSDavid E. O'Brien FXBUS(FXBUS_PCM_RIGHT), C_00000004, &pc);
1671c067afaaSCameron Grant
167221f1e37cSDavid E. O'Brien /* GPR[0/1] += APS-input */
167321f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, GPR(0), GPR(0), C_00000000,
167421f1e37cSDavid E. O'Brien sc->APS ? EXTIN(EXTIN_TOSLINK_L) : C_00000000, &pc);
167521f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, GPR(1), GPR(1), C_00000000,
167621f1e37cSDavid E. O'Brien sc->APS ? EXTIN(EXTIN_TOSLINK_R) : C_00000000, &pc);
167721f1e37cSDavid E. O'Brien
167821f1e37cSDavid E. O'Brien /* FrontOut (AC97) = GPR[0/1] */
167921f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_L), C_00000000,
168021f1e37cSDavid E. O'Brien C_00000000, GPR(0), &pc);
168121f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_R), C_00000000,
168221f1e37cSDavid E. O'Brien C_00000001, GPR(1), &pc);
168321f1e37cSDavid E. O'Brien
168421f1e37cSDavid E. O'Brien /* GPR[2] = GPR[0] (Left) / 2 + GPR[1] (Right) / 2 -- Central volume */
168521f1e37cSDavid E. O'Brien emu_addefxop(sc, iINTERP, GPR(2), GPR(1), C_40000000, GPR(0), &pc);
168621f1e37cSDavid E. O'Brien
168721f1e37cSDavid E. O'Brien #if 0
168821f1e37cSDavid E. O'Brien /* RearOut = (GPR[0/1] * RearVolume) >> 31 */
168921f1e37cSDavid E. O'Brien /* RearVolume = GPR[0x10/0x11] */
169021f1e37cSDavid E. O'Brien emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_L), C_00000000,
169121f1e37cSDavid E. O'Brien GPR(16), GPR(0), &pc);
169221f1e37cSDavid E. O'Brien emu_addefxop(sc, iMAC0, EXTOUT(EXTOUT_REAR_R), C_00000000,
169321f1e37cSDavid E. O'Brien GPR(17), GPR(1), &pc);
169421f1e37cSDavid E. O'Brien #else
169521f1e37cSDavid E. O'Brien /* XXX This is just a copy to the channel, since we do not have
169621f1e37cSDavid E. O'Brien * a patch manager, it is useful for have another output enabled.
169721f1e37cSDavid E. O'Brien */
169821f1e37cSDavid E. O'Brien
169921f1e37cSDavid E. O'Brien /* Rear[l/r] = GPR[0/1] */
170021f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_L), C_00000000,
170121f1e37cSDavid E. O'Brien C_00000000, GPR(0), &pc);
170221f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_REAR_R), C_00000000,
170321f1e37cSDavid E. O'Brien C_00000000, GPR(1), &pc);
170421f1e37cSDavid E. O'Brien #endif
170521f1e37cSDavid E. O'Brien
170621f1e37cSDavid E. O'Brien /* TOS out[l/r] = GPR[0/1] */
170721f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_L), C_00000000,
170821f1e37cSDavid E. O'Brien C_00000000, GPR(0), &pc);
170921f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_TOSLINK_R), C_00000000,
171021f1e37cSDavid E. O'Brien C_00000000, GPR(1), &pc);
171121f1e37cSDavid E. O'Brien
171221f1e37cSDavid E. O'Brien /* Center and Subwoofer configuration */
171321f1e37cSDavid E. O'Brien /* Analog Center = GPR[0] + GPR[2] */
171421f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ACENTER), C_00000000,
171521f1e37cSDavid E. O'Brien GPR(0), GPR(2), &pc);
171621f1e37cSDavid E. O'Brien /* Analog Sub = GPR[1] + GPR[2] */
171721f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ALFE), C_00000000,
171821f1e37cSDavid E. O'Brien GPR(1), GPR(2), &pc);
171921f1e37cSDavid E. O'Brien /* Digital Center = GPR[0] + GPR[2] */
172053f4fb11SAlexander Leidinger emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_CENTER), C_00000000,
172121f1e37cSDavid E. O'Brien GPR(0), GPR(2), &pc);
172221f1e37cSDavid E. O'Brien /* Digital Sub = GPR[1] + GPR[2] */
172353f4fb11SAlexander Leidinger emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_AC97_LFE), C_00000000,
172421f1e37cSDavid E. O'Brien GPR(1), GPR(2), &pc);
172521f1e37cSDavid E. O'Brien
172621f1e37cSDavid E. O'Brien /* Headphones[l/r] = GPR[0/1] */
172721f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_L), C_00000000,
172821f1e37cSDavid E. O'Brien C_00000000, GPR(0), &pc);
172921f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_HEADPHONE_R), C_00000000,
173021f1e37cSDavid E. O'Brien C_00000000, GPR(1), &pc);
173121f1e37cSDavid E. O'Brien
173221f1e37cSDavid E. O'Brien /* ADC Recording buffer[l/r] = AC97Input[l/r] */
173321f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_L), C_00000000,
173421f1e37cSDavid E. O'Brien C_00000000, EXTIN(EXTIN_AC97_L), &pc);
173521f1e37cSDavid E. O'Brien emu_addefxop(sc, iACC3, EXTOUT(EXTOUT_ADC_CAP_R), C_00000000,
173621f1e37cSDavid E. O'Brien C_00000000, EXTIN(EXTIN_AC97_R), &pc);
173721f1e37cSDavid E. O'Brien
173821f1e37cSDavid E. O'Brien /* resume normal operations */
1739c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_DBG, 0);
1740c067afaaSCameron Grant }
1741c067afaaSCameron Grant
1742c067afaaSCameron Grant /* Probe and attach the card */
1743c067afaaSCameron Grant static int
emu_init(struct sc_info * sc)1744c067afaaSCameron Grant emu_init(struct sc_info *sc)
1745c067afaaSCameron Grant {
1746c067afaaSCameron Grant u_int32_t spcs, ch, tmp, i;
1747c067afaaSCameron Grant
174821f1e37cSDavid E. O'Brien if (sc->audigy) {
174921f1e37cSDavid E. O'Brien /* enable additional AC97 slots */
1750c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE);
175121f1e37cSDavid E. O'Brien }
175221f1e37cSDavid E. O'Brien
1753c067afaaSCameron Grant /* disable audio and lock cache */
1754c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG,
1755c7e0c9dbSPedro F. Giffuni EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE,
175621f1e37cSDavid E. O'Brien 4);
1757c067afaaSCameron Grant
1758c067afaaSCameron Grant /* reset recording buffers */
1759c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
1760c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBA, 0);
1761c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
1762c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBA, 0);
1763c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
1764c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBA, 0);
1765c067afaaSCameron Grant
1766c067afaaSCameron Grant /* disable channel interrupt */
1767c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE,
1768c7e0c9dbSPedro F. Giffuni EMU_INTE_INTERTIMERENB | EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE,
176921f1e37cSDavid E. O'Brien 4);
1770c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEL, 0);
1771c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEH, 0);
1772c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEL, 0);
1773c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEH, 0);
1774c067afaaSCameron Grant
177521f1e37cSDavid E. O'Brien /* wonder what these do... */
177621f1e37cSDavid E. O'Brien if (sc->audigy) {
1777c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPBYPASS, 0xf00);
1778c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_AC97SLOT, 0x3);
177921f1e37cSDavid E. O'Brien }
178021f1e37cSDavid E. O'Brien
1781c067afaaSCameron Grant /* init envelope engine */
1782c067afaaSCameron Grant for (ch = 0; ch < NUM_G; ch++) {
1783c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, ENV_OFF);
1784c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_IP, 0);
1785c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0xffff);
1786c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0xffff);
1787c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
1788c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
1789c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CCR, 0);
1790c067afaaSCameron Grant
1791c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PSST, 0);
1792c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DSL, 0x10);
1793c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CCCA, 0);
1794c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_Z1, 0);
1795c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_Z2, 0);
1796c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FXRT, 0xd01c0000);
1797c067afaaSCameron Grant
1798c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ATKHLDM, 0);
1799c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSM, 0);
1800c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_IFATN, 0xffff);
1801c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PEFE, 0);
1802c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FMMOD, 0);
1803c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_TREMFRQ, 24); /* 1 Hz */
1804c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_FM2FRQ2, 24); /* 1 Hz */
1805c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_TEMPENV, 0);
1806c067afaaSCameron Grant
1807c067afaaSCameron Grant /*** these are last so OFF prevents writing ***/
1808c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_LFOVAL2, 0);
1809c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_LFOVAL1, 0);
1810c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ATKHLDV, 0);
1811c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ENVVOL, 0);
1812c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_ENVVAL, 0);
1813c067afaaSCameron Grant
181421f1e37cSDavid E. O'Brien if (sc->audigy) {
181521f1e37cSDavid E. O'Brien /* audigy cards need this to initialize correctly */
181621f1e37cSDavid E. O'Brien emu_wrptr(sc, ch, 0x4c, 0);
181721f1e37cSDavid E. O'Brien emu_wrptr(sc, ch, 0x4d, 0);
181821f1e37cSDavid E. O'Brien emu_wrptr(sc, ch, 0x4e, 0);
181921f1e37cSDavid E. O'Brien emu_wrptr(sc, ch, 0x4f, 0);
182021f1e37cSDavid E. O'Brien /* set default routing */
1821c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_FXRT1, 0x03020100);
1822c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_FXRT2, 0x3f3f3f3f);
1823c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_A_CHAN_SENDAMOUNTS, 0);
182421f1e37cSDavid E. O'Brien }
182521f1e37cSDavid E. O'Brien
1826c067afaaSCameron Grant sc->voice[ch].vnum = ch;
1827c067afaaSCameron Grant sc->voice[ch].slave = NULL;
1828c067afaaSCameron Grant sc->voice[ch].busy = 0;
182970776a9cSCameron Grant sc->voice[ch].ismaster = 0;
18306c1146c0SCameron Grant sc->voice[ch].running = 0;
1831c067afaaSCameron Grant sc->voice[ch].b16 = 0;
1832c067afaaSCameron Grant sc->voice[ch].stereo = 0;
1833c067afaaSCameron Grant sc->voice[ch].speed = 0;
1834c067afaaSCameron Grant sc->voice[ch].start = 0;
1835c067afaaSCameron Grant sc->voice[ch].end = 0;
1836c067afaaSCameron Grant sc->voice[ch].channel = NULL;
1837c067afaaSCameron Grant }
183870776a9cSCameron Grant sc->pnum = sc->rnum = 0;
1839c067afaaSCameron Grant
1840c067afaaSCameron Grant /*
1841c067afaaSCameron Grant * Init to 0x02109204 :
1842c067afaaSCameron Grant * Clock accuracy = 0 (1000ppm)
1843c067afaaSCameron Grant * Sample Rate = 2 (48kHz)
1844c067afaaSCameron Grant * Audio Channel = 1 (Left of 2)
1845c067afaaSCameron Grant * Source Number = 0 (Unspecified)
1846c067afaaSCameron Grant * Generation Status = 1 (Original for Cat Code 12)
1847c067afaaSCameron Grant * Cat Code = 12 (Digital Signal Mixer)
1848c067afaaSCameron Grant * Mode = 0 (Mode 0)
1849c067afaaSCameron Grant * Emphasis = 0 (None)
1850c067afaaSCameron Grant * CP = 1 (Copyright unasserted)
1851c067afaaSCameron Grant * AN = 0 (Audio data)
1852c067afaaSCameron Grant * P = 0 (Consumer)
1853c067afaaSCameron Grant */
1854c7e0c9dbSPedro F. Giffuni spcs = EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
1855c7e0c9dbSPedro F. Giffuni EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
1856c7e0c9dbSPedro F. Giffuni EMU_SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 |
1857c7e0c9dbSPedro F. Giffuni EMU_SPCS_EMPHASIS_NONE | EMU_SPCS_COPYRIGHT;
1858c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS0, spcs);
1859c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS1, spcs);
1860c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SPCS2, spcs);
1861c067afaaSCameron Grant
186221f1e37cSDavid E. O'Brien if (!sc->audigy)
1863c067afaaSCameron Grant emu_initefx(sc);
186421f1e37cSDavid E. O'Brien else if (sc->audigy2) { /* Audigy 2 */
186521f1e37cSDavid E. O'Brien /* from ALSA initialization code: */
186621f1e37cSDavid E. O'Brien
186721f1e37cSDavid E. O'Brien /* Hack for Alice3 to work independent of haP16V driver */
186821f1e37cSDavid E. O'Brien u_int32_t tmp;
186921f1e37cSDavid E. O'Brien
187021f1e37cSDavid E. O'Brien /* Setup SRCMulti_I2S SamplingRate */
1871c7e0c9dbSPedro F. Giffuni tmp = emu_rdptr(sc, 0, EMU_A_SPDIF_SAMPLERATE) & 0xfffff1ff;
1872c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_SPDIF_SAMPLERATE, tmp | 0x400);
187321f1e37cSDavid E. O'Brien
187421f1e37cSDavid E. O'Brien /* Setup SRCSel (Enable SPDIF, I2S SRCMulti) */
187521f1e37cSDavid E. O'Brien emu_wr(sc, 0x20, 0x00600000, 4);
187621f1e37cSDavid E. O'Brien emu_wr(sc, 0x24, 0x00000014, 4);
187721f1e37cSDavid E. O'Brien
187821f1e37cSDavid E. O'Brien /* Setup SRCMulti Input Audio Enable */
187921f1e37cSDavid E. O'Brien emu_wr(sc, 0x20, 0x006e0000, 4);
188021f1e37cSDavid E. O'Brien emu_wr(sc, 0x24, 0xff00ff00, 4);
188121f1e37cSDavid E. O'Brien }
1882c067afaaSCameron Grant
188397b3c9d8SCameron Grant SLIST_INIT(&sc->mem.blocks);
188421f1e37cSDavid E. O'Brien sc->mem.ptb_pages = emu_malloc(sc, EMUMAXPAGES * sizeof(u_int32_t),
188586843ea8SJohn Baldwin &sc->mem.ptb_pages_addr, &sc->mem.ptb_map);
1886c067afaaSCameron Grant if (sc->mem.ptb_pages == NULL)
1887c067afaaSCameron Grant return -1;
188897b3c9d8SCameron Grant
188921f1e37cSDavid E. O'Brien sc->mem.silent_page = emu_malloc(sc, EMUPAGESIZE,
189086843ea8SJohn Baldwin &sc->mem.silent_page_addr, &sc->mem.silent_map);
189197b3c9d8SCameron Grant if (sc->mem.silent_page == NULL) {
189286843ea8SJohn Baldwin emu_free(sc, sc->mem.ptb_pages, sc->mem.ptb_map);
189397b3c9d8SCameron Grant return -1;
189497b3c9d8SCameron Grant }
189597b3c9d8SCameron Grant /* Clear page with silence & setup all pointers to this page */
189697b3c9d8SCameron Grant bzero(sc->mem.silent_page, EMUPAGESIZE);
189738cc9942SOlivier Houchard tmp = (u_int32_t)(sc->mem.silent_page_addr) << 1;
189821f1e37cSDavid E. O'Brien for (i = 0; i < EMUMAXPAGES; i++)
189919b6ac09SCameron Grant sc->mem.ptb_pages[i] = tmp | i;
190097b3c9d8SCameron Grant
1901c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_PTB, (sc->mem.ptb_pages_addr));
1902c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCB, 0); /* taken from original driver */
1903c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCBS, 0); /* taken from original driver */
1904c067afaaSCameron Grant
1905c067afaaSCameron Grant for (ch = 0; ch < NUM_G; ch++) {
1906c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_MAPA, tmp | EMU_CHAN_MAP_PTI_MASK);
1907c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_MAPB, tmp | EMU_CHAN_MAP_PTI_MASK);
1908c067afaaSCameron Grant }
1909c067afaaSCameron Grant
1910c067afaaSCameron Grant /* emu_memalloc(sc, EMUPAGESIZE); */
1911c067afaaSCameron Grant /*
1912c067afaaSCameron Grant * Hokay, now enable the AUD bit
191321f1e37cSDavid E. O'Brien *
191421f1e37cSDavid E. O'Brien * Audigy
191521f1e37cSDavid E. O'Brien * Enable Audio = 0 (enabled after fx processor initialization)
191621f1e37cSDavid E. O'Brien * Mute Disable Audio = 0
191721f1e37cSDavid E. O'Brien * Joystick = 1
191821f1e37cSDavid E. O'Brien *
191921f1e37cSDavid E. O'Brien * Audigy 2
192021f1e37cSDavid E. O'Brien * Enable Audio = 1
192121f1e37cSDavid E. O'Brien * Mute Disable Audio = 0
192221f1e37cSDavid E. O'Brien * Joystick = 1
192321f1e37cSDavid E. O'Brien * GP S/PDIF AC3 Enable = 1
192421f1e37cSDavid E. O'Brien * CD S/PDIF AC3 Enable = 1
192521f1e37cSDavid E. O'Brien *
192621f1e37cSDavid E. O'Brien * EMU10K1
1927c067afaaSCameron Grant * Enable Audio = 1
1928c067afaaSCameron Grant * Mute Disable Audio = 0
1929c067afaaSCameron Grant * Lock Tank Memory = 1
1930c067afaaSCameron Grant * Lock Sound Memory = 0
1931c067afaaSCameron Grant * Auto Mute = 1
1932c067afaaSCameron Grant */
193321f1e37cSDavid E. O'Brien
193421f1e37cSDavid E. O'Brien if (sc->audigy) {
1935c7e0c9dbSPedro F. Giffuni tmp = EMU_HCFG_AUTOMUTE | EMU_HCFG_JOYENABLE;
193621f1e37cSDavid E. O'Brien if (sc->audigy2) /* Audigy 2 */
1937c7e0c9dbSPedro F. Giffuni tmp = EMU_HCFG_AUDIOENABLE | EMU_HCFG_AC3ENABLE_CDSPDIF |
1938c7e0c9dbSPedro F. Giffuni EMU_HCFG_AC3ENABLE_GPSPDIF;
1939c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG, tmp, 4);
194021f1e37cSDavid E. O'Brien
194121f1e37cSDavid E. O'Brien audigy_initefx(sc);
194221f1e37cSDavid E. O'Brien
194321f1e37cSDavid E. O'Brien /* from ALSA initialization code: */
194421f1e37cSDavid E. O'Brien
194521f1e37cSDavid E. O'Brien /* enable audio and disable both audio/digital outputs */
1946c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG, emu_rd(sc, EMU_HCFG, 4) | EMU_HCFG_AUDIOENABLE, 4);
1947c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_A_IOCFG, emu_rd(sc, EMU_A_IOCFG, 4) & ~EMU_A_IOCFG_GPOUT_AD,
194821f1e37cSDavid E. O'Brien 4);
194921f1e37cSDavid E. O'Brien if (sc->audigy2) { /* Audigy 2 */
195021f1e37cSDavid E. O'Brien /* Unmute Analog.
195121f1e37cSDavid E. O'Brien * Set GPO6 to 1 for Apollo. This has to be done after
195221f1e37cSDavid E. O'Brien * init Alice3 I2SOut beyond 48kHz.
195321f1e37cSDavid E. O'Brien * So, sequence is important.
195421f1e37cSDavid E. O'Brien */
1955c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_A_IOCFG,
1956c7e0c9dbSPedro F. Giffuni emu_rd(sc, EMU_A_IOCFG, 4) | EMU_A_IOCFG_GPOUT_A, 4);
195721f1e37cSDavid E. O'Brien }
195821f1e37cSDavid E. O'Brien } else {
195921f1e37cSDavid E. O'Brien /* EMU10K1 initialization code */
1960c7e0c9dbSPedro F. Giffuni tmp = EMU_HCFG_AUDIOENABLE | EMU_HCFG_LOCKTANKCACHE_MASK
1961c7e0c9dbSPedro F. Giffuni | EMU_HCFG_AUTOMUTE;
1962c067afaaSCameron Grant if (sc->rev >= 6)
1963c7e0c9dbSPedro F. Giffuni tmp |= EMU_HCFG_JOYENABLE;
196421f1e37cSDavid E. O'Brien
1965c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG, tmp, 4);
1966c067afaaSCameron Grant
1967c067afaaSCameron Grant /* TOSLink detection */
1968c067afaaSCameron Grant sc->tos_link = 0;
1969c7e0c9dbSPedro F. Giffuni tmp = emu_rd(sc, EMU_HCFG, 4);
1970c7e0c9dbSPedro F. Giffuni if (tmp & (EMU_HCFG_GPINPUT0 | EMU_HCFG_GPINPUT1)) {
1971c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG, tmp | EMU_HCFG_GPOUT1, 4);
1972c067afaaSCameron Grant DELAY(50);
1973c7e0c9dbSPedro F. Giffuni if (tmp != (emu_rd(sc, EMU_HCFG, 4) & ~EMU_HCFG_GPOUT1)) {
1974c067afaaSCameron Grant sc->tos_link = 1;
1975c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG, tmp, 4);
1976c067afaaSCameron Grant }
1977c067afaaSCameron Grant }
197821f1e37cSDavid E. O'Brien }
1979c067afaaSCameron Grant
1980c067afaaSCameron Grant return 0;
1981c067afaaSCameron Grant }
1982c067afaaSCameron Grant
1983c067afaaSCameron Grant static int
emu_uninit(struct sc_info * sc)1984c02f3f7aSCameron Grant emu_uninit(struct sc_info *sc)
1985c02f3f7aSCameron Grant {
1986c02f3f7aSCameron Grant u_int32_t ch;
1987c02f3f7aSCameron Grant
1988c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_INTE, 0, 4);
1989c02f3f7aSCameron Grant for (ch = 0; ch < NUM_G; ch++)
1990c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_DCYSUSV, ENV_OFF);
1991c02f3f7aSCameron Grant for (ch = 0; ch < NUM_G; ch++) {
1992c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_VTFT, 0);
1993c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CVCF, 0);
1994c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_PTRX, 0);
1995c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, ch, EMU_CHAN_CPF, 0);
1996c02f3f7aSCameron Grant }
1997c02f3f7aSCameron Grant
199821f1e37cSDavid E. O'Brien if (sc->audigy) { /* stop fx processor */
1999c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_A_DBG, EMU_A_DBG_SINGLE_STEP);
200021f1e37cSDavid E. O'Brien }
200121f1e37cSDavid E. O'Brien
2002c02f3f7aSCameron Grant /* disable audio and lock cache */
2003c7e0c9dbSPedro F. Giffuni emu_wr(sc, EMU_HCFG,
2004c7e0c9dbSPedro F. Giffuni EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_MUTEBUTTONENABLE,
200521f1e37cSDavid E. O'Brien 4);
2006c02f3f7aSCameron Grant
2007c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_PTB, 0);
2008c02f3f7aSCameron Grant /* reset recording buffers */
2009c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
2010c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_MICBA, 0);
2011c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
2012c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXBA, 0);
2013c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_FXWC, 0);
2014c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
2015c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_ADCBA, 0);
2016c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCB, 0);
2017c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_TCBS, 0);
2018c02f3f7aSCameron Grant
2019c02f3f7aSCameron Grant /* disable channel interrupt */
2020c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEL, 0);
2021c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_CLIEH, 0);
2022c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEL, 0);
2023c7e0c9dbSPedro F. Giffuni emu_wrptr(sc, 0, EMU_SOLEH, 0);
2024c02f3f7aSCameron Grant
2025c02f3f7aSCameron Grant /* init envelope engine */
2026c02f3f7aSCameron Grant if (!SLIST_EMPTY(&sc->mem.blocks))
2027c02f3f7aSCameron Grant device_printf(sc->dev, "warning: memblock list not empty\n");
202886843ea8SJohn Baldwin emu_free(sc, sc->mem.ptb_pages, sc->mem.ptb_map);
202986843ea8SJohn Baldwin emu_free(sc, sc->mem.silent_page, sc->mem.silent_map);
2030c02f3f7aSCameron Grant
2031f510d240SAlexander Leidinger if(sc->mpu)
2032f510d240SAlexander Leidinger mpu401_uninit(sc->mpu);
2033c02f3f7aSCameron Grant return 0;
2034c02f3f7aSCameron Grant }
2035c02f3f7aSCameron Grant
2036c02f3f7aSCameron Grant static int
emu_pci_probe(device_t dev)2037c067afaaSCameron Grant emu_pci_probe(device_t dev)
2038c067afaaSCameron Grant {
2039c067afaaSCameron Grant char *s = NULL;
2040c067afaaSCameron Grant
2041c067afaaSCameron Grant switch (pci_get_devid(dev)) {
2042c067afaaSCameron Grant case EMU10K1_PCI_ID:
2043c067afaaSCameron Grant s = "Creative EMU10K1";
2044c067afaaSCameron Grant break;
204521f1e37cSDavid E. O'Brien
2046a791cfeeSCameron Grant case EMU10K2_PCI_ID:
204721f1e37cSDavid E. O'Brien if (pci_get_revid(dev) == 0x04)
204821f1e37cSDavid E. O'Brien s = "Creative Audigy 2 (EMU10K2)";
204921f1e37cSDavid E. O'Brien else
205021f1e37cSDavid E. O'Brien s = "Creative Audigy (EMU10K2)";
2051a791cfeeSCameron Grant break;
205221f1e37cSDavid E. O'Brien
2053d2b677bbSWarner Losh case EMU10K3_PCI_ID:
2054d2b677bbSWarner Losh s = "Creative Audigy 2 (EMU10K3)";
2055d2b677bbSWarner Losh break;
2056d2b677bbSWarner Losh
2057a791cfeeSCameron Grant default:
2058a791cfeeSCameron Grant return ENXIO;
2059c067afaaSCameron Grant }
2060c067afaaSCameron Grant
2061a791cfeeSCameron Grant device_set_desc(dev, s);
206204d895e8SAlexander Leidinger return BUS_PROBE_LOW_PRIORITY;
2063c067afaaSCameron Grant }
2064c067afaaSCameron Grant
2065c067afaaSCameron Grant static int
emu_pci_attach(device_t dev)2066c067afaaSCameron Grant emu_pci_attach(device_t dev)
2067c067afaaSCameron Grant {
2068306f91b6SCameron Grant struct ac97_info *codec = NULL;
2069a791cfeeSCameron Grant struct sc_info *sc;
2070a791cfeeSCameron Grant int i, gotmic;
2071c067afaaSCameron Grant char status[SND_STATUSLEN];
2072c067afaaSCameron Grant
2073082f6383SAriff Abdullah sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
20744582b3a1SAriff Abdullah sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_emu10k1 softc");
207570776a9cSCameron Grant sc->dev = dev;
2076c067afaaSCameron Grant sc->type = pci_get_devid(dev);
2077c067afaaSCameron Grant sc->rev = pci_get_revid(dev);
2078d2b677bbSWarner Losh sc->audigy = sc->type == EMU10K2_PCI_ID || sc->type == EMU10K3_PCI_ID;
207921f1e37cSDavid E. O'Brien sc->audigy2 = (sc->audigy && sc->rev == 0x04);
208021f1e37cSDavid E. O'Brien sc->nchans = sc->audigy ? 8 : 4;
2081c7e0c9dbSPedro F. Giffuni sc->addrmask = sc->audigy ? EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK;
2082c067afaaSCameron Grant
2083c68534f1SScott Long pci_enable_busmaster(dev);
2084c067afaaSCameron Grant
2085e27951b2SJohn Baldwin i = PCIR_BAR(0);
20865f96beb9SNate Lawson sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE);
2087a791cfeeSCameron Grant if (sc->reg == NULL) {
2088c067afaaSCameron Grant device_printf(dev, "unable to map register space\n");
2089c067afaaSCameron Grant goto bad;
2090c067afaaSCameron Grant }
2091a791cfeeSCameron Grant sc->st = rman_get_bustag(sc->reg);
2092a791cfeeSCameron Grant sc->sh = rman_get_bushandle(sc->reg);
2093a791cfeeSCameron Grant
2094a791cfeeSCameron Grant sc->bufsz = pcm_getbuffersize(dev, 4096, EMU_DEFAULT_BUFSZ, 65536);
2095c067afaaSCameron Grant
20960b989078SAlexander Leidinger if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
20970b989078SAlexander Leidinger /*boundary*/0,
20981115e138SMarius Strobl /*lowaddr*/(1U << 31) - 1, /* can only access 0-2gb */
2099c067afaaSCameron Grant /*highaddr*/BUS_SPACE_MAXADDR,
2100c067afaaSCameron Grant /*filter*/NULL, /*filterarg*/NULL,
2101a791cfeeSCameron Grant /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
21021f7a6325SAlexander Motin /*flags*/0, /*lockfunc*/NULL, /*lockarg*/NULL,
21031f7a6325SAlexander Motin &sc->parent_dmat) != 0) {
2104c067afaaSCameron Grant device_printf(dev, "unable to create dma tag\n");
2105c067afaaSCameron Grant goto bad;
2106c067afaaSCameron Grant }
2107c067afaaSCameron Grant
2108c067afaaSCameron Grant if (emu_init(sc) == -1) {
2109c067afaaSCameron Grant device_printf(dev, "unable to initialize the card\n");
2110c067afaaSCameron Grant goto bad;
2111c067afaaSCameron Grant }
2112c067afaaSCameron Grant
21130f55ac6cSCameron Grant codec = AC97_CREATE(dev, sc, emu_ac97);
2114c067afaaSCameron Grant if (codec == NULL) goto bad;
2115a791cfeeSCameron Grant gotmic = (ac97_getcaps(codec) & AC97_CAP_MICCHANNEL) ? 1 : 0;
21160f55ac6cSCameron Grant if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
2117c067afaaSCameron Grant
2118f510d240SAlexander Leidinger emu_midiattach(sc);
2119f510d240SAlexander Leidinger
2120a791cfeeSCameron Grant i = 0;
21215f96beb9SNate Lawson sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
212221f1e37cSDavid E. O'Brien RF_ACTIVE | RF_SHAREABLE);
212321f1e37cSDavid E. O'Brien if (!sc->irq ||
212405478063SMaxime Henrion snd_setup_intr(dev, sc->irq, INTR_MPSAFE, emu_intr, sc, &sc->ih)) {
2125c067afaaSCameron Grant device_printf(dev, "unable to map interrupt\n");
2126c067afaaSCameron Grant goto bad;
2127c067afaaSCameron Grant }
2128c067afaaSCameron Grant
2129837cd192SChristos Margiolis snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
21300d8ed52eSMathew Kanner rman_get_start(sc->reg), rman_get_start(sc->irq),
2131837cd192SChristos Margiolis device_get_nameunit(device_get_parent(dev)));
2132c067afaaSCameron Grant
2133*516a9c02SChristos Margiolis pcm_init(dev, sc);
213421f1e37cSDavid E. O'Brien for (i = 0; i < sc->nchans; i++)
21350f55ac6cSCameron Grant pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc);
2136a791cfeeSCameron Grant for (i = 0; i < (gotmic ? 3 : 2); i++)
21370f55ac6cSCameron Grant pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc);
2138c067afaaSCameron Grant
2139*516a9c02SChristos Margiolis if (pcm_register(dev, status))
2140*516a9c02SChristos Margiolis goto bad;
2141c067afaaSCameron Grant
2142c067afaaSCameron Grant return 0;
2143c067afaaSCameron Grant
2144c067afaaSCameron Grant bad:
2145306f91b6SCameron Grant if (codec) ac97_destroy(codec);
2146e27951b2SJohn Baldwin if (sc->reg) bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
2147c067afaaSCameron Grant if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih);
2148a791cfeeSCameron Grant if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
2149306f91b6SCameron Grant if (sc->parent_dmat) bus_dma_tag_destroy(sc->parent_dmat);
215066ef8af5SCameron Grant if (sc->lock) snd_mtxfree(sc->lock);
2151c067afaaSCameron Grant free(sc, M_DEVBUF);
2152c067afaaSCameron Grant return ENXIO;
2153c067afaaSCameron Grant }
2154c067afaaSCameron Grant
2155c02f3f7aSCameron Grant static int
emu_pci_detach(device_t dev)2156c02f3f7aSCameron Grant emu_pci_detach(device_t dev)
2157c02f3f7aSCameron Grant {
2158c02f3f7aSCameron Grant int r;
2159c02f3f7aSCameron Grant struct sc_info *sc;
2160c02f3f7aSCameron Grant
2161c02f3f7aSCameron Grant r = pcm_unregister(dev);
2162c02f3f7aSCameron Grant if (r)
2163c02f3f7aSCameron Grant return r;
2164c02f3f7aSCameron Grant
2165c02f3f7aSCameron Grant sc = pcm_getdevinfo(dev);
2166c02f3f7aSCameron Grant /* shutdown chip */
2167c02f3f7aSCameron Grant emu_uninit(sc);
2168c02f3f7aSCameron Grant
2169e27951b2SJohn Baldwin bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->reg);
2170c02f3f7aSCameron Grant bus_teardown_intr(dev, sc->irq, sc->ih);
2171a791cfeeSCameron Grant bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
2172306f91b6SCameron Grant bus_dma_tag_destroy(sc->parent_dmat);
217366ef8af5SCameron Grant snd_mtxfree(sc->lock);
2174c02f3f7aSCameron Grant free(sc, M_DEVBUF);
2175c02f3f7aSCameron Grant
2176c02f3f7aSCameron Grant return 0;
2177c02f3f7aSCameron Grant }
2178c02f3f7aSCameron Grant
2179c02f3f7aSCameron Grant /* add suspend, resume */
2180c067afaaSCameron Grant static device_method_t emu_methods[] = {
2181c067afaaSCameron Grant /* Device interface */
2182c067afaaSCameron Grant DEVMETHOD(device_probe, emu_pci_probe),
2183c067afaaSCameron Grant DEVMETHOD(device_attach, emu_pci_attach),
2184c02f3f7aSCameron Grant DEVMETHOD(device_detach, emu_pci_detach),
2185c067afaaSCameron Grant
21863ac12483SMarius Strobl DEVMETHOD_END
2187c067afaaSCameron Grant };
2188c067afaaSCameron Grant
2189c067afaaSCameron Grant static driver_t emu_driver = {
2190c067afaaSCameron Grant "pcm",
2191c067afaaSCameron Grant emu_methods,
219267b1dce3SCameron Grant PCM_SOFTC_SIZE,
2193c067afaaSCameron Grant };
2194c067afaaSCameron Grant
21952287364eSJohn Baldwin DRIVER_MODULE(snd_emu10k1, pci, emu_driver, NULL, NULL);
21960739ea1dSSeigo Tanimura MODULE_DEPEND(snd_emu10k1, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2197f314f3daSCameron Grant MODULE_VERSION(snd_emu10k1, 1);
2198f510d240SAlexander Leidinger MODULE_DEPEND(snd_emu10k1, midi, 1, 1, 1);
219970776a9cSCameron Grant
22006c1146c0SCameron Grant /* dummy driver to silence the joystick device */
220170776a9cSCameron Grant static int
emujoy_pci_probe(device_t dev)220270776a9cSCameron Grant emujoy_pci_probe(device_t dev)
220370776a9cSCameron Grant {
220470776a9cSCameron Grant char *s = NULL;
220570776a9cSCameron Grant
220670776a9cSCameron Grant switch (pci_get_devid(dev)) {
220770776a9cSCameron Grant case 0x70021102:
220870776a9cSCameron Grant s = "Creative EMU10K1 Joystick";
220970776a9cSCameron Grant device_quiet(dev);
221070776a9cSCameron Grant break;
2211a791cfeeSCameron Grant case 0x70031102:
2212a791cfeeSCameron Grant s = "Creative EMU10K2 Joystick";
2213a791cfeeSCameron Grant device_quiet(dev);
2214a791cfeeSCameron Grant break;
221570776a9cSCameron Grant }
221670776a9cSCameron Grant
221770776a9cSCameron Grant if (s) device_set_desc(dev, s);
2218a791cfeeSCameron Grant return s ? -1000 : ENXIO;
221970776a9cSCameron Grant }
222070776a9cSCameron Grant
222170776a9cSCameron Grant static int
emujoy_pci_attach(device_t dev)222270776a9cSCameron Grant emujoy_pci_attach(device_t dev)
222370776a9cSCameron Grant {
22243ac12483SMarius Strobl
222570776a9cSCameron Grant return 0;
222670776a9cSCameron Grant }
222770776a9cSCameron Grant
2228c02f3f7aSCameron Grant static int
emujoy_pci_detach(device_t dev)2229c02f3f7aSCameron Grant emujoy_pci_detach(device_t dev)
2230c02f3f7aSCameron Grant {
22313ac12483SMarius Strobl
2232c02f3f7aSCameron Grant return 0;
2233c02f3f7aSCameron Grant }
2234c02f3f7aSCameron Grant
223570776a9cSCameron Grant static device_method_t emujoy_methods[] = {
223670776a9cSCameron Grant DEVMETHOD(device_probe, emujoy_pci_probe),
223770776a9cSCameron Grant DEVMETHOD(device_attach, emujoy_pci_attach),
2238c02f3f7aSCameron Grant DEVMETHOD(device_detach, emujoy_pci_detach),
223970776a9cSCameron Grant
22403ac12483SMarius Strobl DEVMETHOD_END
224170776a9cSCameron Grant };
224270776a9cSCameron Grant
224370776a9cSCameron Grant static driver_t emujoy_driver = {
224470776a9cSCameron Grant "emujoy",
224570776a9cSCameron Grant emujoy_methods,
22463ac12483SMarius Strobl 1 /* no softc */
224770776a9cSCameron Grant };
224870776a9cSCameron Grant
22493390adfeSJohn Baldwin DRIVER_MODULE(emujoy, pci, emujoy_driver, NULL, NULL);
2250