envy24.c revision 168883
1159687Snetchild/*
2159687Snetchild * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3159687Snetchild * All rights reserved.
4159687Snetchild *
5159687Snetchild * Redistribution and use in source and binary forms, with or without
6159687Snetchild * modification, are permitted provided that the following conditions
7159687Snetchild * are met:
8159687Snetchild * 1. Redistributions of source code must retain the above copyright
9159687Snetchild *    notice, this list of conditions and the following disclaimer.
10159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright
11159687Snetchild *    notice, this list of conditions and the following disclaimer in the
12159687Snetchild *    documentation and/or other materials provided with the distribution.
13159687Snetchild *
14159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15159687Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16159687Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17159687Snetchild * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18159687Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19159687Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20159687Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22159687Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23159687Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24159687Snetchild * SUCH DAMAGE.
25159687Snetchild *
26159687Snetchild */
27159687Snetchild
28159687Snetchild#include <dev/sound/pcm/sound.h>
29159687Snetchild#include <dev/sound/pcm/ac97.h>
30162876Snetchild#include <dev/sound/pci/spicds.h>
31159687Snetchild#include <dev/sound/pci/envy24.h>
32159687Snetchild
33159689Snetchild#include <dev/pci/pcireg.h>
34159689Snetchild#include <dev/pci/pcivar.h>
35159687Snetchild
36159687Snetchild#include "mixer_if.h"
37159687Snetchild
38165306SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24.c 168883 2007-04-20 01:28:51Z ariff $");
39165306Sariff
40159687SnetchildMALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
41159687Snetchild
42159687Snetchild/* -------------------------------------------------------------------- */
43159687Snetchild
44159687Snetchildstruct sc_info;
45159687Snetchild
46159687Snetchild#define ENVY24_PLAY_CHNUM 10
47159687Snetchild#define ENVY24_REC_CHNUM 12
48159687Snetchild#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
49159687Snetchild#define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
50159687Snetchild#define ENVY24_SAMPLE_NUM   4096
51159687Snetchild
52159687Snetchild#define ENVY24_TIMEOUT 1000
53159687Snetchild
54159687Snetchild#define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
55159687Snetchild
56159687Snetchild#define ENVY24_NAMELEN 32
57159687Snetchild
58159689Snetchildstruct envy24_sample {
59159689Snetchild        volatile u_int32_t buffer;
60159689Snetchild};
61159687Snetchild
62159689Snetchildtypedef struct envy24_sample sample32_t;
63159689Snetchild
64159687Snetchild/* channel registers */
65159687Snetchildstruct sc_chinfo {
66159687Snetchild	struct snd_dbuf		*buffer;
67159687Snetchild	struct pcm_channel	*channel;
68159687Snetchild	struct sc_info		*parent;
69159687Snetchild	int			dir;
70159687Snetchild	unsigned		num; /* hw channel number */
71159687Snetchild
72159687Snetchild	/* channel information */
73159687Snetchild	u_int32_t		format;
74159687Snetchild	u_int32_t		speed;
75159687Snetchild	u_int32_t		blk; /* hw block size(dword) */
76159687Snetchild
77159687Snetchild	/* format conversion structure */
78159687Snetchild	u_int8_t		*data;
79159687Snetchild	unsigned int		size; /* data buffer size(byte) */
80159687Snetchild	int			unit; /* sample size(byte) */
81159687Snetchild	unsigned int		offset; /* samples number offset */
82159687Snetchild	void			(*emldma)(struct sc_chinfo *);
83159687Snetchild
84159687Snetchild	/* flags */
85159687Snetchild	int			run;
86159687Snetchild};
87159687Snetchild
88159687Snetchild/* codec interface entrys */
89159687Snetchildstruct codec_entry {
90159687Snetchild	void *(*create)(device_t dev, void *devinfo, int dir, int num);
91159687Snetchild	void (*destroy)(void *codec);
92159687Snetchild	void (*init)(void *codec);
93159687Snetchild	void (*reinit)(void *codec);
94159687Snetchild	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
95159687Snetchild	void (*setrate)(void *codec, int which, int rate);
96159687Snetchild};
97159687Snetchild
98159687Snetchild/* system configuration information */
99159687Snetchildstruct cfg_info {
100159687Snetchild	char *name;
101159687Snetchild	u_int16_t subvendor, subdevice;
102159687Snetchild	u_int8_t scfg, acl, i2s, spdif;
103159687Snetchild	u_int8_t gpiomask, gpiostate, gpiodir;
104159689Snetchild	u_int8_t cdti, cclk, cs, cif, type;
105159687Snetchild	u_int8_t free;
106159687Snetchild	struct codec_entry *codec;
107159687Snetchild};
108159687Snetchild
109159687Snetchild/* device private data */
110159687Snetchildstruct sc_info {
111159687Snetchild	device_t	dev;
112166713Sariff	struct mtx	*lock;
113159687Snetchild
114159687Snetchild	/* Control/Status registor */
115159687Snetchild	struct resource *cs;
116159687Snetchild	int		csid;
117159687Snetchild	bus_space_tag_t cst;
118159687Snetchild	bus_space_handle_t csh;
119159687Snetchild	/* DDMA registor */
120159687Snetchild	struct resource *ddma;
121159687Snetchild	int		ddmaid;
122159687Snetchild	bus_space_tag_t ddmat;
123159687Snetchild	bus_space_handle_t ddmah;
124159687Snetchild	/* Consumer Section DMA Channel Registers */
125159687Snetchild	struct resource *ds;
126159687Snetchild	int		dsid;
127159687Snetchild	bus_space_tag_t dst;
128159687Snetchild	bus_space_handle_t dsh;
129159687Snetchild	/* MultiTrack registor */
130159687Snetchild	struct resource *mt;
131159687Snetchild	int		mtid;
132159687Snetchild	bus_space_tag_t mtt;
133159687Snetchild	bus_space_handle_t mth;
134159687Snetchild	/* DMA tag */
135159687Snetchild	bus_dma_tag_t dmat;
136159687Snetchild	/* IRQ resource */
137159687Snetchild	struct resource *irq;
138159687Snetchild	int		irqid;
139159687Snetchild	void		*ih;
140159687Snetchild
141159687Snetchild	/* system configuration data */
142159687Snetchild	struct cfg_info *cfg;
143159687Snetchild
144159687Snetchild	/* ADC/DAC number and info */
145159687Snetchild	int		adcn, dacn;
146159687Snetchild	void		*adc[4], *dac[4];
147159687Snetchild
148159687Snetchild	/* mixer control data */
149159687Snetchild	u_int32_t	src;
150159687Snetchild	u_int8_t	left[ENVY24_CHAN_NUM];
151159687Snetchild	u_int8_t	right[ENVY24_CHAN_NUM];
152159687Snetchild
153159687Snetchild	/* Play/Record DMA fifo */
154159687Snetchild	sample32_t	*pbuf;
155159687Snetchild	sample32_t	*rbuf;
156159687Snetchild	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
157159687Snetchild	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
158159687Snetchild	bus_dmamap_t	pmap, rmap;
159159687Snetchild
160159687Snetchild	/* current status */
161159687Snetchild	u_int32_t	speed;
162159687Snetchild	int		run[2];
163159687Snetchild	u_int16_t	intr[2];
164159687Snetchild	struct pcmchan_caps	caps[2];
165159687Snetchild
166159687Snetchild	/* channel info table */
167159687Snetchild	unsigned	chnum;
168159687Snetchild	struct sc_chinfo chan[11];
169159687Snetchild};
170159687Snetchild
171159687Snetchild/* -------------------------------------------------------------------- */
172159687Snetchild
173159687Snetchild/*
174159687Snetchild * prototypes
175159687Snetchild */
176159687Snetchild
177159687Snetchild/* DMA emulator */
178159687Snetchildstatic void envy24_p8u(struct sc_chinfo *);
179159687Snetchildstatic void envy24_p16sl(struct sc_chinfo *);
180159687Snetchildstatic void envy24_p32sl(struct sc_chinfo *);
181159687Snetchildstatic void envy24_r16sl(struct sc_chinfo *);
182159687Snetchildstatic void envy24_r32sl(struct sc_chinfo *);
183159687Snetchild
184159687Snetchild/* channel interface */
185159687Snetchildstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
186159687Snetchildstatic int envy24chan_setformat(kobj_t, void *, u_int32_t);
187159687Snetchildstatic int envy24chan_setspeed(kobj_t, void *, u_int32_t);
188159687Snetchildstatic int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
189159687Snetchildstatic int envy24chan_trigger(kobj_t, void *, int);
190159687Snetchildstatic int envy24chan_getptr(kobj_t, void *);
191159687Snetchildstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
192159687Snetchild
193159687Snetchild/* mixer interface */
194159687Snetchildstatic int envy24mixer_init(struct snd_mixer *);
195159687Snetchildstatic int envy24mixer_reinit(struct snd_mixer *);
196159687Snetchildstatic int envy24mixer_uninit(struct snd_mixer *);
197159687Snetchildstatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
198159687Snetchildstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
199159687Snetchild
200159687Snetchild/* M-Audio Delta series AK4524 access interface */
201159687Snetchildstatic void *envy24_delta_ak4524_create(device_t, void *, int, int);
202159687Snetchildstatic void envy24_delta_ak4524_destroy(void *);
203159687Snetchildstatic void envy24_delta_ak4524_init(void *);
204159687Snetchildstatic void envy24_delta_ak4524_reinit(void *);
205159687Snetchildstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
206159687Snetchild
207159687Snetchild/* -------------------------------------------------------------------- */
208159687Snetchild
209159687Snetchild/*
210159687Snetchild  system constant tables
211159687Snetchild*/
212159687Snetchild
213159687Snetchild/* API -> hardware channel map */
214159687Snetchildstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
215159687Snetchild	ENVY24_CHAN_PLAY_SPDIF, /* 0 */
216159687Snetchild	ENVY24_CHAN_PLAY_DAC1,  /* 1 */
217159687Snetchild	ENVY24_CHAN_PLAY_DAC2,  /* 2 */
218159687Snetchild	ENVY24_CHAN_PLAY_DAC3,  /* 3 */
219159687Snetchild	ENVY24_CHAN_PLAY_DAC4,  /* 4 */
220159687Snetchild	ENVY24_CHAN_REC_MIX,    /* 5 */
221159687Snetchild	ENVY24_CHAN_REC_SPDIF,  /* 6 */
222159687Snetchild	ENVY24_CHAN_REC_ADC1,   /* 7 */
223159687Snetchild	ENVY24_CHAN_REC_ADC2,   /* 8 */
224159687Snetchild	ENVY24_CHAN_REC_ADC3,   /* 9 */
225159687Snetchild	ENVY24_CHAN_REC_ADC4,   /* 10 */
226159687Snetchild};
227159687Snetchild
228159687Snetchild/* mixer -> API channel map. see above */
229159687Snetchildstatic int envy24_mixmap[] = {
230159687Snetchild	-1, /* Master output level. It is depend on codec support */
231159687Snetchild	-1, /* Treble level of all output channels */
232159687Snetchild	-1, /* Bass level of all output channels */
233159687Snetchild	-1, /* Volume of synthesier input */
234159687Snetchild	0,  /* Output level for the audio device */
235159687Snetchild	-1, /* Output level for the PC speaker */
236159687Snetchild	7,  /* line in jack */
237159687Snetchild	-1, /* microphone jack */
238159687Snetchild	-1, /* CD audio input */
239159687Snetchild	-1, /* Recording monitor */
240159687Snetchild	1,  /* alternative codec */
241159687Snetchild	-1, /* global recording level */
242159687Snetchild	-1, /* Input gain */
243159687Snetchild	-1, /* Output gain */
244159687Snetchild	8,  /* Input source 1 */
245159687Snetchild	9,  /* Input source 2 */
246159687Snetchild	10, /* Input source 3 */
247159687Snetchild	6,  /* Digital (input) 1 */
248159687Snetchild	-1, /* Digital (input) 2 */
249159687Snetchild	-1, /* Digital (input) 3 */
250159687Snetchild	-1, /* Phone input */
251159687Snetchild	-1, /* Phone output */
252159687Snetchild	-1, /* Video/TV (audio) in */
253159687Snetchild	-1, /* Radio in */
254159687Snetchild	-1, /* Monitor volume */
255159687Snetchild};
256159687Snetchild
257159687Snetchild/* variable rate audio */
258159687Snetchildstatic u_int32_t envy24_speed[] = {
259159687Snetchild    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
260159687Snetchild    12000, 11025, 9600, 8000, 0
261159687Snetchild};
262159687Snetchild
263159687Snetchild/* known boards configuration */
264159687Snetchildstatic struct codec_entry delta_codec = {
265159687Snetchild	envy24_delta_ak4524_create,
266159687Snetchild	envy24_delta_ak4524_destroy,
267159687Snetchild	envy24_delta_ak4524_init,
268159687Snetchild	envy24_delta_ak4524_reinit,
269159687Snetchild	envy24_delta_ak4524_setvolume,
270159687Snetchild	NULL, /* setrate */
271159687Snetchild};
272159687Snetchild
273159687Snetchildstatic struct cfg_info cfg_table[] = {
274159687Snetchild	{
275159689Snetchild		"Envy24 audio (M Audio Delta Dio 2496)",
276159687Snetchild		0x1412, 0xd631,
277159687Snetchild		0x10, 0x80, 0xf0, 0x03,
278159687Snetchild		0xff, 0x00, 0x00,
279159689Snetchild		0x10, 0x20, 0x40, 0x00, 0x00,
280159689Snetchild		0x00,
281159687Snetchild		&delta_codec,
282159687Snetchild	},
283159687Snetchild	{
284159689Snetchild		"Envy24 audio (Terratec DMX 6fire)",
285159689Snetchild		0x153b, 0x1138,
286159689Snetchild		0x2f, 0x80, 0xf0, 0x03,
287159689Snetchild		0xc0, 0xff, 0x7f,
288159689Snetchild		0x10, 0x20, 0x01, 0x01, 0x00,
289159689Snetchild		0x00,
290159689Snetchild 		&delta_codec,
291159689Snetchild 	},
292159689Snetchild	{
293159689Snetchild		"Envy24 audio (M Audio Audiophile 2496)",
294159689Snetchild		0x1412, 0xd634,
295159689Snetchild		0x10, 0x80, 0x72, 0x03,
296159689Snetchild		0x04, 0xfe, 0xfb,
297159689Snetchild		0x08, 0x02, 0x20, 0x00, 0x01,
298159689Snetchild		0x00,
299159689Snetchild 		&delta_codec,
300159689Snetchild 	},
301159689Snetchild	{
302159689Snetchild		"Envy24 audio (Generic)",
303159687Snetchild		0, 0,
304159687Snetchild		0x0f, 0x00, 0x01, 0x03,
305159687Snetchild		0xff, 0x00, 0x00,
306159689Snetchild		0x10, 0x20, 0x40, 0x00, 0x00,
307159689Snetchild		0x00,
308159687Snetchild		&delta_codec, /* default codec routines */
309159687Snetchild	}
310159687Snetchild};
311159687Snetchild
312159687Snetchildstatic u_int32_t envy24_recfmt[] = {
313159687Snetchild	AFMT_STEREO | AFMT_S16_LE,
314159687Snetchild	AFMT_STEREO | AFMT_S32_LE,
315159687Snetchild	0
316159687Snetchild};
317159687Snetchildstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
318159687Snetchild
319159687Snetchildstatic u_int32_t envy24_playfmt[] = {
320159687Snetchild	AFMT_STEREO | AFMT_U8,
321159687Snetchild	AFMT_STEREO | AFMT_S16_LE,
322159687Snetchild	AFMT_STEREO | AFMT_S32_LE,
323159687Snetchild	0
324159687Snetchild};
325159687Snetchild
326159687Snetchildstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
327159687Snetchild
328159687Snetchildstruct envy24_emldma {
329159687Snetchild	u_int32_t	format;
330159687Snetchild	void		(*emldma)(struct sc_chinfo *);
331159687Snetchild	int		unit;
332159687Snetchild};
333159687Snetchild
334159687Snetchildstatic struct envy24_emldma envy24_pemltab[] = {
335159687Snetchild	{AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
336159687Snetchild	{AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
337159687Snetchild	{AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
338159687Snetchild	{0, NULL, 0}
339159687Snetchild};
340159687Snetchild
341159687Snetchildstatic struct envy24_emldma envy24_remltab[] = {
342159687Snetchild	{AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
343159687Snetchild	{AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
344159687Snetchild	{0, NULL, 0}
345159687Snetchild};
346159687Snetchild
347159687Snetchild/* -------------------------------------------------------------------- */
348159687Snetchild
349159687Snetchild/* common routines */
350159687Snetchildstatic u_int32_t
351159687Snetchildenvy24_rdcs(struct sc_info *sc, int regno, int size)
352159687Snetchild{
353159687Snetchild	switch (size) {
354159687Snetchild	case 1:
355159687Snetchild		return bus_space_read_1(sc->cst, sc->csh, regno);
356159687Snetchild	case 2:
357159687Snetchild		return bus_space_read_2(sc->cst, sc->csh, regno);
358159687Snetchild	case 4:
359159687Snetchild		return bus_space_read_4(sc->cst, sc->csh, regno);
360159687Snetchild	default:
361159687Snetchild		return 0xffffffff;
362159687Snetchild	}
363159687Snetchild}
364159687Snetchild
365159687Snetchildstatic void
366159687Snetchildenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
367159687Snetchild{
368159687Snetchild	switch (size) {
369159687Snetchild	case 1:
370159687Snetchild		bus_space_write_1(sc->cst, sc->csh, regno, data);
371159687Snetchild		break;
372159687Snetchild	case 2:
373159687Snetchild		bus_space_write_2(sc->cst, sc->csh, regno, data);
374159687Snetchild		break;
375159687Snetchild	case 4:
376159687Snetchild		bus_space_write_4(sc->cst, sc->csh, regno, data);
377159687Snetchild		break;
378159687Snetchild	}
379159687Snetchild}
380159687Snetchild
381159687Snetchildstatic u_int32_t
382159687Snetchildenvy24_rdmt(struct sc_info *sc, int regno, int size)
383159687Snetchild{
384159687Snetchild	switch (size) {
385159687Snetchild	case 1:
386159687Snetchild		return bus_space_read_1(sc->mtt, sc->mth, regno);
387159687Snetchild	case 2:
388159687Snetchild		return bus_space_read_2(sc->mtt, sc->mth, regno);
389159687Snetchild	case 4:
390159687Snetchild		return bus_space_read_4(sc->mtt, sc->mth, regno);
391159687Snetchild	default:
392159687Snetchild		return 0xffffffff;
393159687Snetchild	}
394159687Snetchild}
395159687Snetchild
396159687Snetchildstatic void
397159687Snetchildenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
398159687Snetchild{
399159687Snetchild	switch (size) {
400159687Snetchild	case 1:
401159687Snetchild		bus_space_write_1(sc->mtt, sc->mth, regno, data);
402159687Snetchild		break;
403159687Snetchild	case 2:
404159687Snetchild		bus_space_write_2(sc->mtt, sc->mth, regno, data);
405159687Snetchild		break;
406159687Snetchild	case 4:
407159687Snetchild		bus_space_write_4(sc->mtt, sc->mth, regno, data);
408159687Snetchild		break;
409159687Snetchild	}
410159687Snetchild}
411159687Snetchild
412159687Snetchildstatic u_int32_t
413159687Snetchildenvy24_rdci(struct sc_info *sc, int regno)
414159687Snetchild{
415159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
416159687Snetchild	return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
417159687Snetchild}
418159687Snetchild
419159687Snetchildstatic void
420159687Snetchildenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
421159687Snetchild{
422159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
423159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
424159687Snetchild}
425159687Snetchild
426159687Snetchild/* -------------------------------------------------------------------- */
427159687Snetchild
428159687Snetchild/* I2C port/E2PROM access routines */
429159687Snetchild
430159687Snetchildstatic int
431159687Snetchildenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
432159687Snetchild{
433159687Snetchild	u_int32_t data;
434159687Snetchild	int i;
435159687Snetchild
436159687Snetchild#if(0)
437159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
438159687Snetchild#endif
439159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
440159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
441159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
442159687Snetchild			break;
443159687Snetchild		DELAY(32); /* 31.25kHz */
444159687Snetchild	}
445159687Snetchild	if (i == ENVY24_TIMEOUT) {
446159687Snetchild		return -1;
447159687Snetchild	}
448159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
449159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
450159687Snetchild	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
451159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
452159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
453159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
454159687Snetchild			break;
455159687Snetchild		DELAY(32); /* 31.25kHz */
456159687Snetchild	}
457159687Snetchild	if (i == ENVY24_TIMEOUT) {
458159687Snetchild		return -1;
459159687Snetchild	}
460159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
461159687Snetchild
462159687Snetchild#if(0)
463159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
464159687Snetchild#endif
465159687Snetchild	return (int)data;
466159687Snetchild}
467159687Snetchild
468159689Snetchild#if 0
469159687Snetchildstatic int
470159687Snetchildenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
471159687Snetchild{
472159687Snetchild	u_int32_t tmp;
473159687Snetchild	int i;
474159687Snetchild
475159687Snetchild#if(0)
476159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
477159687Snetchild#endif
478159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
479159687Snetchild		tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
480159687Snetchild		if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
481159687Snetchild			break;
482159687Snetchild		DELAY(32); /* 31.25kHz */
483159687Snetchild	}
484159687Snetchild	if (i == ENVY24_TIMEOUT) {
485159687Snetchild		return -1;
486159687Snetchild	}
487159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
488159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
489159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
490159687Snetchild	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
491159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
492159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
493159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
494159687Snetchild			break;
495159687Snetchild		DELAY(32); /* 31.25kHz */
496159687Snetchild	}
497159687Snetchild	if (i == ENVY24_TIMEOUT) {
498159687Snetchild		return -1;
499159687Snetchild	}
500159687Snetchild
501159687Snetchild	return 0;
502159687Snetchild}
503159689Snetchild#endif
504159687Snetchild
505159687Snetchildstatic int
506159687Snetchildenvy24_rdrom(struct sc_info *sc, u_int32_t addr)
507159687Snetchild{
508159687Snetchild	u_int32_t data;
509159687Snetchild
510159687Snetchild#if(0)
511159687Snetchild	device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
512159687Snetchild#endif
513159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
514159687Snetchild	if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
515159687Snetchild#if(0)
516159687Snetchild		device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
517159687Snetchild#endif
518159687Snetchild		return -1;
519159687Snetchild	}
520159687Snetchild
521159687Snetchild	return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
522159687Snetchild}
523159687Snetchild
524159687Snetchildstatic struct cfg_info *
525159687Snetchildenvy24_rom2cfg(struct sc_info *sc)
526159687Snetchild{
527159687Snetchild	struct cfg_info *buff;
528159687Snetchild	int size;
529159687Snetchild	int i;
530159687Snetchild
531159687Snetchild#if(0)
532159687Snetchild	device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
533159687Snetchild#endif
534159687Snetchild	size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
535159687Snetchild	if (size < ENVY24_E2PROM_GPIODIR + 1) {
536159687Snetchild#if(0)
537159687Snetchild		device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
538159687Snetchild#endif
539159687Snetchild		return NULL;
540159687Snetchild	}
541159687Snetchild	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
542159687Snetchild	if (buff == NULL) {
543159687Snetchild#if(0)
544159687Snetchild		device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
545159687Snetchild#endif
546159687Snetchild		return NULL;
547159687Snetchild	}
548159687Snetchild	buff->free = 1;
549159687Snetchild
550159687Snetchild	buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
551159687Snetchild	buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
552159687Snetchild	buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
553159687Snetchild	buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
554159687Snetchild	buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
555159687Snetchild	buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
556159687Snetchild	buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
557159687Snetchild	buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
558159687Snetchild	buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
559159687Snetchild	buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
560159687Snetchild	buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
561159687Snetchild
562159687Snetchild	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
563159687Snetchild		if (cfg_table[i].subvendor == buff->subvendor &&
564159687Snetchild		    cfg_table[i].subdevice == buff->subdevice)
565159687Snetchild			break;
566159687Snetchild	buff->name = cfg_table[i].name;
567159687Snetchild	buff->codec = cfg_table[i].codec;
568159687Snetchild
569159687Snetchild	return buff;
570159687Snetchild}
571159687Snetchild
572159687Snetchildstatic void
573159687Snetchildenvy24_cfgfree(struct cfg_info *cfg) {
574159687Snetchild	if (cfg == NULL)
575159687Snetchild		return;
576159687Snetchild	if (cfg->free)
577159687Snetchild		free(cfg, M_ENVY24);
578159687Snetchild	return;
579159687Snetchild}
580159687Snetchild
581159687Snetchild/* -------------------------------------------------------------------- */
582159687Snetchild
583159687Snetchild/* AC'97 codec access routines */
584159687Snetchild
585159689Snetchild#if 0
586159687Snetchildstatic int
587159687Snetchildenvy24_coldcd(struct sc_info *sc)
588159687Snetchild{
589159687Snetchild	u_int32_t data;
590159687Snetchild	int i;
591159687Snetchild
592159687Snetchild#if(0)
593159687Snetchild	device_printf(sc->dev, "envy24_coldcd()\n");
594159687Snetchild#endif
595159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
596159687Snetchild	DELAY(10);
597159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
598159687Snetchild	DELAY(1000);
599159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
600159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
601159687Snetchild		if (data & ENVY24_MT_AC97CMD_RDY) {
602159687Snetchild			return 0;
603159687Snetchild		}
604159687Snetchild	}
605159687Snetchild
606159687Snetchild	return -1;
607159687Snetchild}
608159689Snetchild#endif
609159687Snetchild
610159687Snetchildstatic int
611159687Snetchildenvy24_slavecd(struct sc_info *sc)
612159687Snetchild{
613159687Snetchild	u_int32_t data;
614159687Snetchild	int i;
615159687Snetchild
616159687Snetchild#if(0)
617159687Snetchild	device_printf(sc->dev, "envy24_slavecd()\n");
618159687Snetchild#endif
619159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD,
620159687Snetchild	    ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
621159687Snetchild	DELAY(10);
622159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
623159687Snetchild	DELAY(1000);
624159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
625159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
626159687Snetchild		if (data & ENVY24_MT_AC97CMD_RDY) {
627159687Snetchild			return 0;
628159687Snetchild		}
629159687Snetchild	}
630159687Snetchild
631159687Snetchild	return -1;
632159687Snetchild}
633159687Snetchild
634159689Snetchild#if 0
635159687Snetchildstatic int
636159687Snetchildenvy24_rdcd(kobj_t obj, void *devinfo, int regno)
637159687Snetchild{
638159687Snetchild	struct sc_info *sc = (struct sc_info *)devinfo;
639159687Snetchild	u_int32_t data;
640159687Snetchild	int i;
641159687Snetchild
642159687Snetchild#if(0)
643159687Snetchild	device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
644159687Snetchild#endif
645159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
646159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
647159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
648159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
649159687Snetchild		if ((data & ENVY24_MT_AC97CMD_RD) == 0)
650159687Snetchild			break;
651159687Snetchild	}
652159687Snetchild	data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
653159687Snetchild
654159687Snetchild#if(0)
655159687Snetchild	device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
656159687Snetchild#endif
657159687Snetchild	return (int)data;
658159687Snetchild}
659159687Snetchild
660159687Snetchildstatic int
661159687Snetchildenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
662159687Snetchild{
663159687Snetchild	struct sc_info *sc = (struct sc_info *)devinfo;
664159687Snetchild	u_int32_t cmd;
665159687Snetchild	int i;
666159687Snetchild
667159687Snetchild#if(0)
668159687Snetchild	device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
669159687Snetchild#endif
670159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
671159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
672159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
673159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
674159687Snetchild		cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
675159687Snetchild		if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
676159687Snetchild			break;
677159687Snetchild	}
678159687Snetchild
679159687Snetchild	return 0;
680159687Snetchild}
681159687Snetchild
682159687Snetchildstatic kobj_method_t envy24_ac97_methods[] = {
683159687Snetchild	KOBJMETHOD(ac97_read,	envy24_rdcd),
684159687Snetchild	KOBJMETHOD(ac97_write,	envy24_wrcd),
685159687Snetchild	{0, 0}
686159687Snetchild};
687159687SnetchildAC97_DECLARE(envy24_ac97);
688159689Snetchild#endif
689159687Snetchild
690159687Snetchild/* -------------------------------------------------------------------- */
691159687Snetchild
692159687Snetchild/* GPIO access routines */
693159687Snetchild
694159687Snetchildstatic u_int32_t
695159687Snetchildenvy24_gpiord(struct sc_info *sc)
696159687Snetchild{
697159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
698159687Snetchild}
699159687Snetchild
700159687Snetchildstatic void
701159687Snetchildenvy24_gpiowr(struct sc_info *sc, u_int32_t data)
702159687Snetchild{
703159687Snetchild#if(0)
704159687Snetchild	device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
705159687Snetchild	return;
706159687Snetchild#endif
707159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
708159687Snetchild	return;
709159687Snetchild}
710159687Snetchild
711159689Snetchild#if 0
712159687Snetchildstatic u_int32_t
713159687Snetchildenvy24_gpiogetmask(struct sc_info *sc)
714159687Snetchild{
715159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
716159687Snetchild}
717159689Snetchild#endif
718159687Snetchild
719159687Snetchildstatic void
720159687Snetchildenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
721159687Snetchild{
722159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
723159687Snetchild	return;
724159687Snetchild}
725159687Snetchild
726159689Snetchild#if 0
727159687Snetchildstatic u_int32_t
728159687Snetchildenvy24_gpiogetdir(struct sc_info *sc)
729159687Snetchild{
730159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
731159687Snetchild}
732159689Snetchild#endif
733159687Snetchild
734159687Snetchildstatic void
735159687Snetchildenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
736159687Snetchild{
737159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
738159687Snetchild	return;
739159687Snetchild}
740159687Snetchild
741159687Snetchild/* -------------------------------------------------------------------- */
742159687Snetchild
743159687Snetchild/* M-Audio Delta series AK4524 access interface routine */
744159687Snetchild
745159687Snetchildstruct envy24_delta_ak4524_codec {
746162876Snetchild	struct spicds_info *info;
747159687Snetchild	struct sc_info *parent;
748159687Snetchild	int dir;
749159687Snetchild	int num;
750159687Snetchild	int cs, cclk, cdti;
751159687Snetchild};
752159687Snetchild
753159687Snetchildstatic void
754159687Snetchildenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
755159687Snetchild{
756159687Snetchild	u_int32_t data = 0;
757159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
758159687Snetchild
759159687Snetchild#if(0)
760159687Snetchild	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
761159687Snetchild#endif
762159687Snetchild	data = envy24_gpiord(ptr->parent);
763159687Snetchild	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
764159687Snetchild	if (cs) data += ptr->cs;
765159687Snetchild	if (cclk) data += ptr->cclk;
766159687Snetchild	if (cdti) data += ptr->cdti;
767159687Snetchild	envy24_gpiowr(ptr->parent, data);
768159687Snetchild	return;
769159687Snetchild}
770159687Snetchild
771159687Snetchildstatic void *
772159687Snetchildenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
773159687Snetchild{
774159687Snetchild	struct sc_info *sc = info;
775159687Snetchild	struct envy24_delta_ak4524_codec *buff = NULL;
776159687Snetchild
777159687Snetchild#if(0)
778159687Snetchild	device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
779159687Snetchild#endif
780159687Snetchild
781159687Snetchild	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
782159687Snetchild	if (buff == NULL)
783159687Snetchild		return NULL;
784159687Snetchild
785160796Snetchild	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
786159687Snetchild		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
787160796Snetchild	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
788159687Snetchild		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
789159687Snetchild	else
790162876Snetchild		buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
791159687Snetchild	if (buff->info == NULL) {
792159687Snetchild		free(buff, M_ENVY24);
793159687Snetchild		return NULL;
794159687Snetchild	}
795159687Snetchild
796159687Snetchild	buff->parent = sc;
797159687Snetchild	buff->dir = dir;
798159687Snetchild	buff->num = num;
799159687Snetchild
800159687Snetchild	return (void *)buff;
801159687Snetchild}
802159687Snetchild
803159687Snetchildstatic void
804159687Snetchildenvy24_delta_ak4524_destroy(void *codec)
805159687Snetchild{
806159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
807159687Snetchild	if (ptr == NULL)
808159687Snetchild		return;
809159687Snetchild#if(0)
810159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
811159687Snetchild#endif
812159687Snetchild
813159687Snetchild	if (ptr->dir == PCMDIR_PLAY) {
814162876Snetchild		if (ptr->parent->dac[ptr->num] != NULL)
815162876Snetchild			spicds_destroy(ptr->info);
816159687Snetchild	}
817159687Snetchild	else {
818162876Snetchild		if (ptr->parent->adc[ptr->num] != NULL)
819162876Snetchild			spicds_destroy(ptr->info);
820159687Snetchild	}
821159687Snetchild
822159687Snetchild	free(codec, M_ENVY24);
823159687Snetchild}
824159687Snetchild
825159687Snetchildstatic void
826159687Snetchildenvy24_delta_ak4524_init(void *codec)
827159687Snetchild{
828159689Snetchild#if 0
829159687Snetchild	u_int32_t gpiomask, gpiodir;
830159689Snetchild#endif
831159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
832159687Snetchild	if (ptr == NULL)
833159687Snetchild		return;
834159687Snetchild#if(0)
835159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
836159687Snetchild#endif
837159687Snetchild
838159687Snetchild	/*
839159687Snetchild	gpiomask = envy24_gpiogetmask(ptr->parent);
840159687Snetchild	gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
841159687Snetchild	envy24_gpiosetmask(ptr->parent, gpiomask);
842159687Snetchild	gpiodir = envy24_gpiogetdir(ptr->parent);
843159687Snetchild	gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
844159687Snetchild	envy24_gpiosetdir(ptr->parent, gpiodir);
845159687Snetchild	*/
846159689Snetchild	ptr->cs = ptr->parent->cfg->cs;
847159689Snetchild#if 0
848159687Snetchild	envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
849159687Snetchild	envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
850159687Snetchild	if (ptr->num == 0)
851159687Snetchild		ptr->cs = ENVY24_GPIO_AK4524_CS0;
852159687Snetchild	else
853159687Snetchild		ptr->cs = ENVY24_GPIO_AK4524_CS1;
854159687Snetchild	ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
855159689Snetchild#endif
856159689Snetchild	ptr->cclk = ptr->parent->cfg->cclk;
857159689Snetchild	ptr->cdti = ptr->parent->cfg->cdti;
858162876Snetchild	spicds_settype(ptr->info,  ptr->parent->cfg->type);
859162876Snetchild	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
860162876Snetchild	spicds_setformat(ptr->info,
861159687Snetchild	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
862162876Snetchild	spicds_setdvc(ptr->info, 0);
863162876Snetchild	/* for the time being, init only first codec */
864162876Snetchild	if (ptr->num == 0)
865162876Snetchild		spicds_init(ptr->info);
866159687Snetchild}
867159687Snetchild
868159687Snetchildstatic void
869159687Snetchildenvy24_delta_ak4524_reinit(void *codec)
870159687Snetchild{
871159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
872159687Snetchild	if (ptr == NULL)
873159687Snetchild		return;
874159687Snetchild#if(0)
875159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
876159687Snetchild#endif
877159687Snetchild
878162876Snetchild	spicds_reinit(ptr->info);
879159687Snetchild}
880159687Snetchild
881159687Snetchildstatic void
882159687Snetchildenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
883159687Snetchild{
884159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
885159687Snetchild	if (ptr == NULL)
886159687Snetchild		return;
887159687Snetchild#if(0)
888159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
889159687Snetchild#endif
890159687Snetchild
891162876Snetchild	spicds_set(ptr->info, dir, left, right);
892159687Snetchild}
893159687Snetchild
894159687Snetchild/*
895159687Snetchild  There is no need for AK452[48] codec to set sample rate
896159687Snetchild  static void
897159687Snetchild  envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
898159687Snetchild  {
899159687Snetchild  }
900159687Snetchild*/
901159687Snetchild
902159687Snetchild/* -------------------------------------------------------------------- */
903159687Snetchild
904159687Snetchild/* hardware access routeines */
905159687Snetchild
906159687Snetchildstatic struct {
907159687Snetchild	u_int32_t speed;
908159687Snetchild	u_int32_t code;
909159687Snetchild} envy24_speedtab[] = {
910159687Snetchild	{48000, ENVY24_MT_RATE_48000},
911159687Snetchild	{24000, ENVY24_MT_RATE_24000},
912159687Snetchild	{12000, ENVY24_MT_RATE_12000},
913159687Snetchild	{9600, ENVY24_MT_RATE_9600},
914159687Snetchild	{32000, ENVY24_MT_RATE_32000},
915159687Snetchild	{16000, ENVY24_MT_RATE_16000},
916159687Snetchild	{8000, ENVY24_MT_RATE_8000},
917159687Snetchild	{96000, ENVY24_MT_RATE_96000},
918159687Snetchild	{64000, ENVY24_MT_RATE_64000},
919159687Snetchild	{44100, ENVY24_MT_RATE_44100},
920159687Snetchild	{22050, ENVY24_MT_RATE_22050},
921159687Snetchild	{11025, ENVY24_MT_RATE_11025},
922159687Snetchild	{88200, ENVY24_MT_RATE_88200},
923159687Snetchild	{0, 0x10}
924159687Snetchild};
925159687Snetchild
926159687Snetchildstatic int
927159687Snetchildenvy24_setspeed(struct sc_info *sc, u_int32_t speed) {
928159687Snetchild	u_int32_t code;
929159687Snetchild	int i = 0;
930159687Snetchild
931159687Snetchild#if(0)
932159687Snetchild	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
933159687Snetchild#endif
934159687Snetchild	if (speed == 0) {
935159687Snetchild		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
936159687Snetchild		envy24_slavecd(sc);
937159687Snetchild	}
938159687Snetchild	else {
939159687Snetchild		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
940159687Snetchild			if (envy24_speedtab[i].speed == speed)
941159687Snetchild				break;
942159687Snetchild		}
943159687Snetchild		code = envy24_speedtab[i].code;
944159687Snetchild	}
945159687Snetchild#if(0)
946159687Snetchild	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
947159687Snetchild#endif
948159687Snetchild	if (code < 0x10) {
949159687Snetchild		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
950159687Snetchild		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
951159687Snetchild		code &= ENVY24_MT_RATE_MASK;
952159687Snetchild		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
953159687Snetchild			if (envy24_speedtab[i].code == code)
954159687Snetchild				break;
955159687Snetchild		}
956159687Snetchild		speed = envy24_speedtab[i].speed;
957159687Snetchild	}
958159687Snetchild	else
959159687Snetchild		speed = 0;
960159687Snetchild
961159687Snetchild#if(0)
962159687Snetchild	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
963159687Snetchild#endif
964159687Snetchild	return speed;
965159687Snetchild}
966159687Snetchild
967159687Snetchildstatic void
968159687Snetchildenvy24_setvolume(struct sc_info *sc, unsigned ch)
969159687Snetchild{
970159687Snetchild#if(0)
971159687Snetchild	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
972159687Snetchild#endif
973159689Snetchildif (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
974159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
975159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
976159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
977159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
978159689Snetchild	}
979159689Snetchild
980159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
981159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
982159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
983159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
984159687Snetchild}
985159687Snetchild
986159687Snetchildstatic void
987159687Snetchildenvy24_mutevolume(struct sc_info *sc, unsigned ch)
988159687Snetchild{
989159687Snetchild	u_int32_t vol;
990159687Snetchild
991159687Snetchild#if(0)
992159687Snetchild	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
993159687Snetchild#endif
994159687Snetchild	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
995159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
996159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
997159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
998159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
999159687Snetchild}
1000159687Snetchild
1001159687Snetchildstatic u_int32_t
1002159687Snetchildenvy24_gethwptr(struct sc_info *sc, int dir)
1003159687Snetchild{
1004159687Snetchild	int unit, regno;
1005159687Snetchild	u_int32_t ptr, rtn;
1006159687Snetchild
1007159687Snetchild#if(0)
1008159687Snetchild	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1009159687Snetchild#endif
1010159687Snetchild	if (dir == PCMDIR_PLAY) {
1011159687Snetchild		rtn = sc->psize / 4;
1012159687Snetchild		unit = ENVY24_PLAY_BUFUNIT / 4;
1013159687Snetchild		regno = ENVY24_MT_PCNT;
1014159687Snetchild	}
1015159687Snetchild	else {
1016159687Snetchild		rtn = sc->rsize / 4;
1017159687Snetchild		unit = ENVY24_REC_BUFUNIT / 4;
1018159687Snetchild		regno = ENVY24_MT_RCNT;
1019159687Snetchild	}
1020159687Snetchild
1021159687Snetchild	ptr = envy24_rdmt(sc, regno, 2);
1022159687Snetchild	rtn -= (ptr + 1);
1023159687Snetchild	rtn /= unit;
1024159687Snetchild
1025159687Snetchild#if(0)
1026159687Snetchild	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1027159687Snetchild#endif
1028159687Snetchild	return rtn;
1029159687Snetchild}
1030159687Snetchild
1031159687Snetchildstatic void
1032159687Snetchildenvy24_updintr(struct sc_info *sc, int dir)
1033159687Snetchild{
1034159687Snetchild	int regptr, regintr;
1035159687Snetchild	u_int32_t mask, intr;
1036159687Snetchild	u_int32_t ptr, size, cnt;
1037159687Snetchild	u_int16_t blk;
1038159687Snetchild
1039159687Snetchild#if(0)
1040159687Snetchild	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1041159687Snetchild#endif
1042159687Snetchild	if (dir == PCMDIR_PLAY) {
1043159687Snetchild		blk = sc->blk[0];
1044159687Snetchild		size = sc->psize / 4;
1045159687Snetchild		regptr = ENVY24_MT_PCNT;
1046159687Snetchild		regintr = ENVY24_MT_PTERM;
1047159687Snetchild		mask = ~ENVY24_MT_INT_PMASK;
1048159687Snetchild	}
1049159687Snetchild	else {
1050159687Snetchild		blk = sc->blk[1];
1051159687Snetchild		size = sc->rsize / 4;
1052159687Snetchild		regptr = ENVY24_MT_RCNT;
1053159687Snetchild		regintr = ENVY24_MT_RTERM;
1054159687Snetchild		mask = ~ENVY24_MT_INT_RMASK;
1055159687Snetchild	}
1056159687Snetchild
1057159687Snetchild	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1058159687Snetchild	/*
1059159687Snetchild	cnt = blk - ptr % blk - 1;
1060159687Snetchild	if (cnt == 0)
1061159687Snetchild		cnt = blk - 1;
1062159687Snetchild	*/
1063159687Snetchild	cnt = blk - 1;
1064159687Snetchild#if(0)
1065159687Snetchild	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1066159687Snetchild#endif
1067159687Snetchild	envy24_wrmt(sc, regintr, cnt, 2);
1068159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1069159687Snetchild#if(0)
1070159687Snetchild	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1071159687Snetchild#endif
1072159687Snetchild	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1073159687Snetchild#if(0)
1074159687Snetchild	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1075159687Snetchild		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1076159687Snetchild#endif
1077159687Snetchild
1078159687Snetchild	return;
1079159687Snetchild}
1080159687Snetchild
1081159689Snetchild#if 0
1082159687Snetchildstatic void
1083159687Snetchildenvy24_maskintr(struct sc_info *sc, int dir)
1084159687Snetchild{
1085159687Snetchild	u_int32_t mask, intr;
1086159687Snetchild
1087159687Snetchild#if(0)
1088159687Snetchild	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1089159687Snetchild#endif
1090159687Snetchild	if (dir == PCMDIR_PLAY)
1091159687Snetchild		mask = ENVY24_MT_INT_PMASK;
1092159687Snetchild	else
1093159687Snetchild		mask = ENVY24_MT_INT_RMASK;
1094159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1095159687Snetchild	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1096159687Snetchild
1097159687Snetchild	return;
1098159687Snetchild}
1099159689Snetchild#endif
1100159687Snetchild
1101159687Snetchildstatic int
1102159687Snetchildenvy24_checkintr(struct sc_info *sc, int dir)
1103159687Snetchild{
1104159687Snetchild	u_int32_t mask, stat, intr, rtn;
1105159687Snetchild
1106159687Snetchild#if(0)
1107159687Snetchild	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1108159687Snetchild#endif
1109159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1110159687Snetchild	if (dir == PCMDIR_PLAY) {
1111159687Snetchild		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1112159687Snetchild			mask = ~ENVY24_MT_INT_RSTAT;
1113159687Snetchild			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1114159687Snetchild			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1115159687Snetchild		}
1116159687Snetchild	}
1117159687Snetchild	else {
1118159687Snetchild		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1119159687Snetchild			mask = ~ENVY24_MT_INT_PSTAT;
1120159687Snetchild			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1121159687Snetchild			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1122159687Snetchild		}
1123159687Snetchild	}
1124159687Snetchild
1125159687Snetchild	return rtn;
1126159687Snetchild}
1127159687Snetchild
1128159687Snetchildstatic void
1129159687Snetchildenvy24_start(struct sc_info *sc, int dir)
1130159687Snetchild{
1131159687Snetchild	u_int32_t stat, sw;
1132159687Snetchild
1133159687Snetchild#if(0)
1134159687Snetchild	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1135159687Snetchild#endif
1136159687Snetchild	if (dir == PCMDIR_PLAY)
1137159687Snetchild		sw = ENVY24_MT_PCTL_PSTART;
1138159687Snetchild	else
1139159687Snetchild		sw = ENVY24_MT_PCTL_RSTART;
1140159687Snetchild
1141159687Snetchild	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1142159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1143159687Snetchild#if(0)
1144159687Snetchild	DELAY(100);
1145159687Snetchild	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1146159687Snetchild	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1147159687Snetchild#endif
1148159687Snetchild
1149159687Snetchild	return;
1150159687Snetchild}
1151159687Snetchild
1152159687Snetchildstatic void
1153159687Snetchildenvy24_stop(struct sc_info *sc, int dir)
1154159687Snetchild{
1155159687Snetchild	u_int32_t stat, sw;
1156159687Snetchild
1157159687Snetchild#if(0)
1158159687Snetchild	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1159159687Snetchild#endif
1160159687Snetchild	if (dir == PCMDIR_PLAY)
1161159687Snetchild		sw = ~ENVY24_MT_PCTL_PSTART;
1162159687Snetchild	else
1163159687Snetchild		sw = ~ENVY24_MT_PCTL_RSTART;
1164159687Snetchild
1165159687Snetchild	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1166159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1167159687Snetchild
1168159687Snetchild	return;
1169159687Snetchild}
1170159687Snetchild
1171159687Snetchildstatic int
1172159687Snetchildenvy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1173159687Snetchild{
1174159687Snetchild	u_int32_t reg, mask;
1175159687Snetchild	u_int32_t left, right;
1176159687Snetchild
1177159687Snetchild#if(0)
1178159687Snetchild	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1179159687Snetchild	    dac, class, adc, rev);
1180159687Snetchild#endif
1181159687Snetchild	/* parameter pattern check */
1182159687Snetchild	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1183159687Snetchild		return -1;
1184159687Snetchild	if (class == ENVY24_ROUTE_CLASS_MIX &&
1185159687Snetchild	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1186159687Snetchild		return -1;
1187159687Snetchild	if (rev) {
1188159687Snetchild		left = ENVY24_ROUTE_RIGHT;
1189159687Snetchild		right = ENVY24_ROUTE_LEFT;
1190159687Snetchild	}
1191159687Snetchild	else {
1192159687Snetchild		left = ENVY24_ROUTE_LEFT;
1193159687Snetchild		right = ENVY24_ROUTE_RIGHT;
1194159687Snetchild	}
1195159687Snetchild
1196159687Snetchild	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1197159687Snetchild		reg = class | class << 2 |
1198159687Snetchild			((adc << 1 | left) | left << 3) << 8 |
1199159687Snetchild			((adc << 1 | right) | right << 3) << 12;
1200159687Snetchild#if(0)
1201159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1202159687Snetchild#endif
1203159687Snetchild		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1204159687Snetchild	}
1205159687Snetchild	else {
1206159687Snetchild		mask = ~(0x0303 << dac * 2);
1207159687Snetchild		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1208159687Snetchild		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1209159687Snetchild#if(0)
1210159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1211159687Snetchild#endif
1212159687Snetchild		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1213159687Snetchild		mask = ~(0xff << dac * 8);
1214159687Snetchild		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1215159687Snetchild		reg = (reg & mask) |
1216159687Snetchild			(((adc << 1 | left) | left << 3) |
1217159687Snetchild			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1218159687Snetchild#if(0)
1219159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1220159687Snetchild#endif
1221159687Snetchild		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1222159687Snetchild	}
1223159687Snetchild
1224159687Snetchild	return 0;
1225159687Snetchild}
1226159687Snetchild
1227159687Snetchild/* -------------------------------------------------------------------- */
1228159687Snetchild
1229159687Snetchild/* buffer copy routines */
1230159687Snetchildstatic void
1231159687Snetchildenvy24_p32sl(struct sc_chinfo *ch)
1232159687Snetchild{
1233159687Snetchild	int length;
1234159687Snetchild	sample32_t *dmabuf;
1235159687Snetchild	u_int32_t *data;
1236159687Snetchild	int src, dst, ssize, dsize, slot;
1237159687Snetchild	int i;
1238159687Snetchild
1239159687Snetchild	length = sndbuf_getready(ch->buffer) / 8;
1240159687Snetchild	dmabuf = ch->parent->pbuf;
1241159687Snetchild	data = (u_int32_t *)ch->data;
1242159687Snetchild	src = sndbuf_getreadyptr(ch->buffer) / 4;
1243159687Snetchild	dst = src / 2 + ch->offset;
1244159687Snetchild	ssize = ch->size / 4;
1245159687Snetchild	dsize = ch->size / 8;
1246159687Snetchild	slot = ch->num * 2;
1247159687Snetchild
1248159687Snetchild	for (i = 0; i < length; i++) {
1249159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1250159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1251159687Snetchild		dst++;
1252159687Snetchild		dst %= dsize;
1253159687Snetchild		src += 2;
1254159687Snetchild		src %= ssize;
1255159687Snetchild	}
1256159687Snetchild
1257159687Snetchild	return;
1258159687Snetchild}
1259159687Snetchild
1260159687Snetchildstatic void
1261159687Snetchildenvy24_p16sl(struct sc_chinfo *ch)
1262159687Snetchild{
1263159687Snetchild	int length;
1264159687Snetchild	sample32_t *dmabuf;
1265159687Snetchild	u_int16_t *data;
1266159687Snetchild	int src, dst, ssize, dsize, slot;
1267159687Snetchild	int i;
1268159687Snetchild
1269159687Snetchild#if(0)
1270159687Snetchild	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1271159687Snetchild#endif
1272159687Snetchild	length = sndbuf_getready(ch->buffer) / 4;
1273159687Snetchild	dmabuf = ch->parent->pbuf;
1274159687Snetchild	data = (u_int16_t *)ch->data;
1275159687Snetchild	src = sndbuf_getreadyptr(ch->buffer) / 2;
1276159687Snetchild	dst = src / 2 + ch->offset;
1277159687Snetchild	ssize = ch->size / 2;
1278159687Snetchild	dsize = ch->size / 4;
1279159687Snetchild	slot = ch->num * 2;
1280159687Snetchild#if(0)
1281159687Snetchild	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1282159687Snetchild#endif
1283159687Snetchild
1284159687Snetchild	for (i = 0; i < length; i++) {
1285159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1286159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1287159687Snetchild#if(0)
1288159687Snetchild		if (i < 16) {
1289159687Snetchild			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1290159687Snetchild			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1291159687Snetchild		}
1292159687Snetchild#endif
1293159687Snetchild		dst++;
1294159687Snetchild		dst %= dsize;
1295159687Snetchild		src += 2;
1296159687Snetchild		src %= ssize;
1297159687Snetchild	}
1298159687Snetchild#if(0)
1299159687Snetchild	printf("\n");
1300159687Snetchild#endif
1301159687Snetchild
1302159687Snetchild	return;
1303159687Snetchild}
1304159687Snetchild
1305159687Snetchildstatic void
1306159687Snetchildenvy24_p8u(struct sc_chinfo *ch)
1307159687Snetchild{
1308159687Snetchild	int length;
1309159687Snetchild	sample32_t *dmabuf;
1310159687Snetchild	u_int8_t *data;
1311159687Snetchild	int src, dst, ssize, dsize, slot;
1312159687Snetchild	int i;
1313159687Snetchild
1314159687Snetchild	length = sndbuf_getready(ch->buffer) / 2;
1315159687Snetchild	dmabuf = ch->parent->pbuf;
1316159687Snetchild	data = (u_int8_t *)ch->data;
1317159687Snetchild	src = sndbuf_getreadyptr(ch->buffer);
1318159687Snetchild	dst = src / 2 + ch->offset;
1319159687Snetchild	ssize = ch->size;
1320159687Snetchild	dsize = ch->size / 4;
1321159687Snetchild	slot = ch->num * 2;
1322159687Snetchild
1323159687Snetchild	for (i = 0; i < length; i++) {
1324159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1325159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1326159687Snetchild		dst++;
1327159687Snetchild		dst %= dsize;
1328159687Snetchild		src += 2;
1329159687Snetchild		src %= ssize;
1330159687Snetchild	}
1331159687Snetchild
1332159687Snetchild	return;
1333159687Snetchild}
1334159687Snetchild
1335159687Snetchildstatic void
1336159687Snetchildenvy24_r32sl(struct sc_chinfo *ch)
1337159687Snetchild{
1338159687Snetchild	int length;
1339159687Snetchild	sample32_t *dmabuf;
1340159687Snetchild	u_int32_t *data;
1341159687Snetchild	int src, dst, ssize, dsize, slot;
1342159687Snetchild	int i;
1343159687Snetchild
1344159687Snetchild	length = sndbuf_getfree(ch->buffer) / 8;
1345159687Snetchild	dmabuf = ch->parent->rbuf;
1346159687Snetchild	data = (u_int32_t *)ch->data;
1347159687Snetchild	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1348159687Snetchild	src = dst / 2 + ch->offset;
1349159687Snetchild	dsize = ch->size / 4;
1350159687Snetchild	ssize = ch->size / 8;
1351159687Snetchild	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1352159687Snetchild
1353159687Snetchild	for (i = 0; i < length; i++) {
1354159689Snetchild		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1355159689Snetchild		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1356159687Snetchild		dst += 2;
1357159687Snetchild		dst %= dsize;
1358159687Snetchild		src++;
1359159687Snetchild		src %= ssize;
1360159687Snetchild	}
1361159687Snetchild
1362159687Snetchild	return;
1363159687Snetchild}
1364159687Snetchild
1365159687Snetchildstatic void
1366159687Snetchildenvy24_r16sl(struct sc_chinfo *ch)
1367159687Snetchild{
1368159687Snetchild	int length;
1369159687Snetchild	sample32_t *dmabuf;
1370159689Snetchild	u_int16_t *data;
1371159687Snetchild	int src, dst, ssize, dsize, slot;
1372159687Snetchild	int i;
1373159687Snetchild
1374159687Snetchild	length = sndbuf_getfree(ch->buffer) / 4;
1375159687Snetchild	dmabuf = ch->parent->rbuf;
1376159687Snetchild	data = (u_int16_t *)ch->data;
1377159687Snetchild	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1378159687Snetchild	src = dst / 2 + ch->offset;
1379159687Snetchild	dsize = ch->size / 2;
1380159687Snetchild	ssize = ch->size / 8;
1381159687Snetchild	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1382159687Snetchild
1383159687Snetchild	for (i = 0; i < length; i++) {
1384159689Snetchild		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1385159689Snetchild		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1386159687Snetchild		dst += 2;
1387159687Snetchild		dst %= dsize;
1388159687Snetchild		src++;
1389159687Snetchild		src %= ssize;
1390159687Snetchild	}
1391159687Snetchild
1392159687Snetchild	return;
1393159687Snetchild}
1394159687Snetchild
1395159687Snetchild/* -------------------------------------------------------------------- */
1396159687Snetchild
1397159687Snetchild/* channel interface */
1398159687Snetchildstatic void *
1399159687Snetchildenvy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1400159687Snetchild{
1401159687Snetchild	struct sc_info	*sc = (struct sc_info *)devinfo;
1402159687Snetchild	struct sc_chinfo *ch;
1403159687Snetchild	unsigned num;
1404159687Snetchild
1405159687Snetchild#if(0)
1406159687Snetchild	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1407159687Snetchild#endif
1408159687Snetchild	snd_mtxlock(sc->lock);
1409159687Snetchild	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1410159687Snetchild	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1411159687Snetchild		snd_mtxunlock(sc->lock);
1412159687Snetchild		return NULL;
1413159687Snetchild	}
1414159687Snetchild	num = sc->chnum;
1415159687Snetchild
1416159687Snetchild	ch = &sc->chan[num];
1417159687Snetchild	ch->size = 8 * ENVY24_SAMPLE_NUM;
1418159687Snetchild	ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1419159687Snetchild	if (ch->data == NULL) {
1420159687Snetchild		ch->size = 0;
1421159687Snetchild		ch = NULL;
1422159687Snetchild	}
1423159687Snetchild	else {
1424159687Snetchild		ch->buffer = b;
1425159687Snetchild		ch->channel = c;
1426159687Snetchild		ch->parent = sc;
1427159687Snetchild		ch->dir = dir;
1428159687Snetchild		/* set channel map */
1429159687Snetchild		ch->num = envy24_chanmap[num];
1430165306Sariff		snd_mtxunlock(sc->lock);
1431159687Snetchild		sndbuf_setup(ch->buffer, ch->data, ch->size);
1432165306Sariff		snd_mtxlock(sc->lock);
1433159687Snetchild		/* these 2 values are dummy */
1434159687Snetchild		ch->unit = 4;
1435159687Snetchild		ch->blk = 10240;
1436159687Snetchild	}
1437159687Snetchild	snd_mtxunlock(sc->lock);
1438159687Snetchild
1439159687Snetchild	return ch;
1440159687Snetchild}
1441159687Snetchild
1442159687Snetchildstatic int
1443159687Snetchildenvy24chan_free(kobj_t obj, void *data)
1444159687Snetchild{
1445159687Snetchild	struct sc_chinfo *ch = data;
1446159687Snetchild	struct sc_info *sc = ch->parent;
1447159687Snetchild
1448159687Snetchild#if(0)
1449159687Snetchild	device_printf(sc->dev, "envy24chan_free()\n");
1450159687Snetchild#endif
1451159687Snetchild	snd_mtxlock(sc->lock);
1452159687Snetchild	if (ch->data != NULL) {
1453159687Snetchild		free(ch->data, M_ENVY24);
1454159687Snetchild		ch->data = NULL;
1455159687Snetchild	}
1456159687Snetchild	snd_mtxunlock(sc->lock);
1457159687Snetchild
1458159687Snetchild	return 0;
1459159687Snetchild}
1460159687Snetchild
1461159687Snetchildstatic int
1462159687Snetchildenvy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1463159687Snetchild{
1464159687Snetchild	struct sc_chinfo *ch = data;
1465159687Snetchild	struct sc_info *sc = ch->parent;
1466159687Snetchild	struct envy24_emldma *emltab;
1467165306Sariff	/* unsigned int bcnt, bsize; */
1468159687Snetchild	int i;
1469159687Snetchild
1470159687Snetchild#if(0)
1471159687Snetchild	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1472159687Snetchild#endif
1473159687Snetchild	snd_mtxlock(sc->lock);
1474159687Snetchild	/* check and get format related information */
1475159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1476159687Snetchild		emltab = envy24_pemltab;
1477159687Snetchild	else
1478159687Snetchild		emltab = envy24_remltab;
1479159687Snetchild	if (emltab == NULL) {
1480159687Snetchild		snd_mtxunlock(sc->lock);
1481159687Snetchild		return -1;
1482159687Snetchild	}
1483159687Snetchild	for (i = 0; emltab[i].format != 0; i++)
1484159687Snetchild		if (emltab[i].format == format)
1485159687Snetchild			break;
1486159687Snetchild	if (emltab[i].format == 0) {
1487159687Snetchild		snd_mtxunlock(sc->lock);
1488159687Snetchild		return -1;
1489159687Snetchild	}
1490159687Snetchild
1491159687Snetchild	/* set format information */
1492159687Snetchild	ch->format = format;
1493159687Snetchild	ch->emldma = emltab[i].emldma;
1494159687Snetchild	if (ch->unit > emltab[i].unit)
1495159687Snetchild		ch->blk *= ch->unit / emltab[i].unit;
1496159687Snetchild	else
1497159687Snetchild		ch->blk /= emltab[i].unit / ch->unit;
1498159687Snetchild	ch->unit = emltab[i].unit;
1499159687Snetchild
1500159687Snetchild	/* set channel buffer information */
1501159687Snetchild	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1502165306Sariff#if 0
1503159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1504159687Snetchild		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1505159687Snetchild	else
1506159687Snetchild		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1507159687Snetchild	bsize *= ch->unit;
1508159687Snetchild	bcnt = ch->size / bsize;
1509159687Snetchild	sndbuf_resize(ch->buffer, bcnt, bsize);
1510165306Sariff#endif
1511159687Snetchild	snd_mtxunlock(sc->lock);
1512159687Snetchild
1513159687Snetchild#if(0)
1514159687Snetchild	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1515159687Snetchild#endif
1516159687Snetchild	return 0;
1517159687Snetchild}
1518159687Snetchild
1519159687Snetchild/*
1520159687Snetchild  IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1521159687Snetchild  of speed information value. And real hardware speed setting is done
1522159687Snetchild  at start triggered(see envy24chan_trigger()). So, at this function
1523159687Snetchild  is called, any value that ENVY24 can use is able to set. But, at
1524159687Snetchild  start triggerd, some other channel is running, and that channel's
1525159687Snetchild  speed isn't same with, then trigger function will fail.
1526159687Snetchild*/
1527159687Snetchildstatic int
1528159687Snetchildenvy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1529159687Snetchild{
1530159687Snetchild	struct sc_chinfo *ch = data;
1531159687Snetchild	u_int32_t val, prev;
1532159687Snetchild	int i;
1533159687Snetchild
1534159687Snetchild#if(0)
1535159687Snetchild	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1536159687Snetchild#endif
1537159687Snetchild	prev = 0x7fffffff;
1538159687Snetchild	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1539159687Snetchild		if (abs(val - speed) < abs(prev - speed))
1540159687Snetchild			prev = val;
1541159687Snetchild		else
1542159687Snetchild			break;
1543159687Snetchild	}
1544159687Snetchild	ch->speed = prev;
1545159687Snetchild
1546159687Snetchild#if(0)
1547159687Snetchild	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1548159687Snetchild#endif
1549159687Snetchild	return ch->speed;
1550159687Snetchild}
1551159687Snetchild
1552159687Snetchildstatic int
1553159687Snetchildenvy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1554159687Snetchild{
1555159687Snetchild	struct sc_chinfo *ch = data;
1556165306Sariff	/* struct sc_info *sc = ch->parent; */
1557159687Snetchild	u_int32_t size, prev;
1558165306Sariff        unsigned int bcnt, bsize;
1559159687Snetchild
1560159687Snetchild#if(0)
1561159687Snetchild	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1562159687Snetchild#endif
1563159687Snetchild	prev = 0x7fffffff;
1564165306Sariff	/* snd_mtxlock(sc->lock); */
1565159687Snetchild	for (size = ch->size / 2; size > 0; size /= 2) {
1566159687Snetchild		if (abs(size - blocksize) < abs(prev - blocksize))
1567159687Snetchild			prev = size;
1568159687Snetchild		else
1569159687Snetchild			break;
1570159687Snetchild	}
1571159687Snetchild
1572159687Snetchild	ch->blk = prev / ch->unit;
1573159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1574159687Snetchild		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1575159687Snetchild	else
1576159687Snetchild		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1577165306Sariff	/* set channel buffer information */
1578165306Sariff	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1579165306Sariff        if (ch->dir == PCMDIR_PLAY)
1580165306Sariff                bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1581165306Sariff        else
1582165306Sariff                bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1583165306Sariff        bsize *= ch->unit;
1584165306Sariff        bcnt = ch->size / bsize;
1585165306Sariff        sndbuf_resize(ch->buffer, bcnt, bsize);
1586165306Sariff	/* snd_mtxunlock(sc->lock); */
1587159687Snetchild
1588159687Snetchild#if(0)
1589159687Snetchild	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1590159687Snetchild#endif
1591159687Snetchild	return prev;
1592159687Snetchild}
1593159687Snetchild
1594159687Snetchild/* semantic note: must start at beginning of buffer */
1595159687Snetchildstatic int
1596159687Snetchildenvy24chan_trigger(kobj_t obj, void *data, int go)
1597159687Snetchild{
1598159687Snetchild	struct sc_chinfo *ch = data;
1599159687Snetchild	struct sc_info *sc = ch->parent;
1600159687Snetchild	u_int32_t ptr;
1601159687Snetchild	int slot;
1602160796Snetchild#if 0
1603159687Snetchild	int i;
1604159687Snetchild
1605159687Snetchild	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1606159687Snetchild#endif
1607159687Snetchild	snd_mtxlock(sc->lock);
1608159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1609159687Snetchild		slot = 0;
1610159687Snetchild	else
1611159687Snetchild		slot = 1;
1612159687Snetchild	switch (go) {
1613159687Snetchild	case PCMTRIG_START:
1614159687Snetchild#if(0)
1615159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1616159687Snetchild#endif
1617159687Snetchild		/* check or set channel speed */
1618159687Snetchild		if (sc->run[0] == 0 && sc->run[1] == 0) {
1619159687Snetchild			sc->speed = envy24_setspeed(sc, ch->speed);
1620159687Snetchild			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1621159687Snetchild			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1622159687Snetchild		}
1623159687Snetchild		else if (ch->speed != 0 && ch->speed != sc->speed)
1624159687Snetchild			return -1;
1625159687Snetchild		if (ch->speed == 0)
1626159687Snetchild			ch->channel->speed = sc->speed;
1627159687Snetchild		/* start or enable channel */
1628159687Snetchild		sc->run[slot]++;
1629159687Snetchild		if (sc->run[slot] == 1) {
1630159687Snetchild			/* first channel */
1631159687Snetchild			ch->offset = 0;
1632159687Snetchild			sc->blk[slot] = ch->blk;
1633159687Snetchild		}
1634159687Snetchild		else {
1635159687Snetchild			ptr = envy24_gethwptr(sc, ch->dir);
1636159687Snetchild			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1637159687Snetchild			    (ch->size / 4)) * 4 / ch->unit;
1638159687Snetchild			if (ch->blk < sc->blk[slot])
1639159687Snetchild				sc->blk[slot] = ch->blk;
1640159687Snetchild		}
1641159687Snetchild		if (ch->dir == PCMDIR_PLAY) {
1642159687Snetchild			ch->emldma(ch);
1643159687Snetchild			envy24_setvolume(sc, ch->num);
1644159687Snetchild		}
1645159687Snetchild		envy24_updintr(sc, ch->dir);
1646159687Snetchild		if (sc->run[slot] == 1)
1647159687Snetchild			envy24_start(sc, ch->dir);
1648159687Snetchild		ch->run = 1;
1649159687Snetchild		break;
1650159687Snetchild	case PCMTRIG_EMLDMAWR:
1651159687Snetchild#if(0)
1652159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1653159687Snetchild#endif
1654159687Snetchild		if (ch->run != 1)
1655159687Snetchild			return -1;
1656159687Snetchild		ch->emldma(ch);
1657159687Snetchild		break;
1658159687Snetchild	case PCMTRIG_EMLDMARD:
1659159687Snetchild#if(0)
1660159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1661159687Snetchild#endif
1662159687Snetchild		if (ch->run != 1)
1663159687Snetchild			return -1;
1664159687Snetchild		ch->emldma(ch);
1665159687Snetchild		break;
1666159687Snetchild	case PCMTRIG_ABORT:
1667159687Snetchild#if(0)
1668159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1669159687Snetchild#endif
1670159687Snetchild		ch->run = 0;
1671159687Snetchild		sc->run[slot]--;
1672159687Snetchild		if (ch->dir == PCMDIR_PLAY)
1673159687Snetchild			envy24_mutevolume(sc, ch->num);
1674159687Snetchild		if (sc->run[slot] == 0) {
1675159687Snetchild			envy24_stop(sc, ch->dir);
1676159687Snetchild			sc->intr[slot] = 0;
1677159687Snetchild		}
1678160796Snetchild#if 0
1679159687Snetchild		else if (ch->blk == sc->blk[slot]) {
1680159687Snetchild			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1681159687Snetchild			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1682159687Snetchild				if (sc->chan[i].dir == ch->dir &&
1683159687Snetchild				    sc->chan[i].run == 1 &&
1684159687Snetchild				    sc->chan[i].blk < sc->blk[slot])
1685159687Snetchild					sc->blk[slot] = sc->chan[i].blk;
1686159687Snetchild			}
1687159687Snetchild			if (ch->blk != sc->blk[slot])
1688159687Snetchild				envy24_updintr(sc, ch->dir);
1689159687Snetchild		}
1690160796Snetchild#endif
1691159687Snetchild		break;
1692159687Snetchild	}
1693159687Snetchild	snd_mtxunlock(sc->lock);
1694159687Snetchild
1695159687Snetchild	return 0;
1696159687Snetchild}
1697159687Snetchild
1698159687Snetchildstatic int
1699159687Snetchildenvy24chan_getptr(kobj_t obj, void *data)
1700159687Snetchild{
1701159687Snetchild	struct sc_chinfo *ch = data;
1702159687Snetchild	struct sc_info *sc = ch->parent;
1703159687Snetchild	u_int32_t ptr;
1704159687Snetchild	int rtn;
1705159687Snetchild
1706159687Snetchild#if(0)
1707159687Snetchild	device_printf(sc->dev, "envy24chan_getptr()\n");
1708159687Snetchild#endif
1709159687Snetchild	snd_mtxlock(sc->lock);
1710159687Snetchild	ptr = envy24_gethwptr(sc, ch->dir);
1711159687Snetchild	rtn = ptr * ch->unit;
1712159687Snetchild	snd_mtxunlock(sc->lock);
1713159687Snetchild
1714159687Snetchild#if(0)
1715159687Snetchild	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1716159687Snetchild	    rtn);
1717159687Snetchild#endif
1718159687Snetchild	return rtn;
1719159687Snetchild}
1720159687Snetchild
1721159687Snetchildstatic struct pcmchan_caps *
1722159687Snetchildenvy24chan_getcaps(kobj_t obj, void *data)
1723159687Snetchild{
1724159687Snetchild	struct sc_chinfo *ch = data;
1725159687Snetchild	struct sc_info *sc = ch->parent;
1726159687Snetchild	struct pcmchan_caps *rtn;
1727159687Snetchild
1728159687Snetchild#if(0)
1729159687Snetchild	device_printf(sc->dev, "envy24chan_getcaps()\n");
1730159687Snetchild#endif
1731159687Snetchild	snd_mtxlock(sc->lock);
1732159687Snetchild	if (ch->dir == PCMDIR_PLAY) {
1733159687Snetchild		if (sc->run[0] == 0)
1734159687Snetchild			rtn = &envy24_playcaps;
1735159687Snetchild		else
1736159687Snetchild			rtn = &sc->caps[0];
1737159687Snetchild	}
1738159687Snetchild	else {
1739159687Snetchild		if (sc->run[1] == 0)
1740159687Snetchild			rtn = &envy24_reccaps;
1741159687Snetchild		else
1742159687Snetchild			rtn = &sc->caps[1];
1743159687Snetchild	}
1744159687Snetchild	snd_mtxunlock(sc->lock);
1745159687Snetchild
1746159687Snetchild	return rtn;
1747159687Snetchild}
1748159687Snetchild
1749159687Snetchildstatic kobj_method_t envy24chan_methods[] = {
1750159687Snetchild	KOBJMETHOD(channel_init,		envy24chan_init),
1751159687Snetchild	KOBJMETHOD(channel_free,		envy24chan_free),
1752159687Snetchild	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1753159687Snetchild	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1754159687Snetchild	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1755159687Snetchild	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1756159687Snetchild	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1757159687Snetchild	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1758159687Snetchild	{ 0, 0 }
1759159687Snetchild};
1760159687SnetchildCHANNEL_DECLARE(envy24chan);
1761159687Snetchild
1762159687Snetchild/* -------------------------------------------------------------------- */
1763159687Snetchild
1764159687Snetchild/* mixer interface */
1765159687Snetchild
1766159687Snetchildstatic int
1767159687Snetchildenvy24mixer_init(struct snd_mixer *m)
1768159687Snetchild{
1769159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1770159687Snetchild
1771159687Snetchild#if(0)
1772159687Snetchild	device_printf(sc->dev, "envy24mixer_init()\n");
1773159687Snetchild#endif
1774159687Snetchild	if (sc == NULL)
1775159687Snetchild		return -1;
1776159687Snetchild
1777159687Snetchild	/* set volume control rate */
1778159687Snetchild	snd_mtxlock(sc->lock);
1779159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1780159687Snetchild
1781159687Snetchild	mix_setdevs(m, ENVY24_MIX_MASK);
1782159687Snetchild	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1783159687Snetchild	snd_mtxunlock(sc->lock);
1784159687Snetchild
1785159687Snetchild	return 0;
1786159687Snetchild}
1787159687Snetchild
1788159687Snetchildstatic int
1789159687Snetchildenvy24mixer_reinit(struct snd_mixer *m)
1790159687Snetchild{
1791159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1792159687Snetchild
1793159687Snetchild	if (sc == NULL)
1794159687Snetchild		return -1;
1795159687Snetchild#if(0)
1796159687Snetchild	device_printf(sc->dev, "envy24mixer_reinit()\n");
1797159687Snetchild#endif
1798159687Snetchild
1799159687Snetchild	return 0;
1800159687Snetchild}
1801159687Snetchild
1802159687Snetchildstatic int
1803159687Snetchildenvy24mixer_uninit(struct snd_mixer *m)
1804159687Snetchild{
1805159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1806159687Snetchild
1807159687Snetchild	if (sc == NULL)
1808159687Snetchild		return -1;
1809159687Snetchild#if(0)
1810159687Snetchild	device_printf(sc->dev, "envy24mixer_uninit()\n");
1811159687Snetchild#endif
1812159687Snetchild
1813159687Snetchild	return 0;
1814159687Snetchild}
1815159687Snetchild
1816159687Snetchildstatic int
1817159687Snetchildenvy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1818159687Snetchild{
1819159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1820159687Snetchild	int ch = envy24_mixmap[dev];
1821159687Snetchild	int hwch;
1822159687Snetchild	int i;
1823159687Snetchild
1824159687Snetchild	if (sc == NULL)
1825159687Snetchild		return -1;
1826159687Snetchild	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1827159687Snetchild		return -1;
1828159687Snetchild	if (dev != 0 && ch == -1)
1829159687Snetchild		return -1;
1830159687Snetchild	hwch = envy24_chanmap[ch];
1831159687Snetchild#if(0)
1832159687Snetchild	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1833159687Snetchild	    dev, left, right);
1834159687Snetchild#endif
1835159687Snetchild
1836159687Snetchild	snd_mtxlock(sc->lock);
1837159687Snetchild	if (dev == 0) {
1838159687Snetchild		for (i = 0; i < sc->dacn; i++) {
1839159687Snetchild			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1840159687Snetchild		}
1841159687Snetchild	}
1842159687Snetchild	else {
1843159687Snetchild		/* set volume value for hardware */
1844159687Snetchild		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1845159687Snetchild			sc->left[hwch] = ENVY24_VOL_MUTE;
1846159687Snetchild		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1847159687Snetchild			sc->right[hwch] = ENVY24_VOL_MUTE;
1848159687Snetchild
1849159687Snetchild		/* set volume for record channel and running play channel */
1850159687Snetchild		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1851159687Snetchild			envy24_setvolume(sc, hwch);
1852159687Snetchild	}
1853159687Snetchild	snd_mtxunlock(sc->lock);
1854159687Snetchild
1855159687Snetchild	return right << 8 | left;
1856159687Snetchild}
1857159687Snetchild
1858159687Snetchildstatic u_int32_t
1859159687Snetchildenvy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1860159687Snetchild{
1861159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1862159687Snetchild	int ch = envy24_mixmap[src];
1863159687Snetchild#if(0)
1864159687Snetchild	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1865159687Snetchild#endif
1866159687Snetchild
1867159687Snetchild	if (ch > ENVY24_CHAN_PLAY_SPDIF)
1868159687Snetchild		sc->src = ch;
1869159687Snetchild	return src;
1870159687Snetchild}
1871159687Snetchild
1872159687Snetchildstatic kobj_method_t envy24mixer_methods[] = {
1873159687Snetchild	KOBJMETHOD(mixer_init,		envy24mixer_init),
1874159687Snetchild	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
1875159687Snetchild	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
1876159687Snetchild	KOBJMETHOD(mixer_set,		envy24mixer_set),
1877159687Snetchild	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
1878159687Snetchild	{ 0, 0 }
1879159687Snetchild};
1880159687SnetchildMIXER_DECLARE(envy24mixer);
1881159687Snetchild
1882159687Snetchild/* -------------------------------------------------------------------- */
1883159687Snetchild
1884159687Snetchild/* The interrupt handler */
1885159687Snetchildstatic void
1886159687Snetchildenvy24_intr(void *p)
1887159687Snetchild{
1888159687Snetchild	struct sc_info *sc = (struct sc_info *)p;
1889159687Snetchild	struct sc_chinfo *ch;
1890159687Snetchild	u_int32_t ptr, dsize, feed;
1891159687Snetchild	int i;
1892159687Snetchild
1893159687Snetchild#if(0)
1894159687Snetchild	device_printf(sc->dev, "envy24_intr()\n");
1895159687Snetchild#endif
1896159687Snetchild	snd_mtxlock(sc->lock);
1897159687Snetchild	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
1898159687Snetchild#if(0)
1899159687Snetchild		device_printf(sc->dev, "envy24_intr(): play\n");
1900159687Snetchild#endif
1901159687Snetchild		dsize = sc->psize / 4;
1902159687Snetchild		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
1903159687Snetchild#if(0)
1904159687Snetchild		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
1905159687Snetchild#endif
1906159687Snetchild		ptr -= ptr % sc->blk[0];
1907159687Snetchild		feed = (ptr + dsize - sc->intr[0]) % dsize;
1908159687Snetchild#if(0)
1909159687Snetchild		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1910159687Snetchild#endif
1911159687Snetchild		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
1912159687Snetchild			ch = &sc->chan[i];
1913159687Snetchild#if(0)
1914159687Snetchild			if (ch->run)
1915159687Snetchild				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
1916159687Snetchild#endif
1917165306Sariff			if (ch->run && ch->blk <= feed) {
1918165306Sariff				snd_mtxunlock(sc->lock);
1919159687Snetchild				chn_intr(ch->channel);
1920165306Sariff				snd_mtxlock(sc->lock);
1921165306Sariff			}
1922159687Snetchild		}
1923159687Snetchild		sc->intr[0] = ptr;
1924159687Snetchild		envy24_updintr(sc, PCMDIR_PLAY);
1925159687Snetchild	}
1926159687Snetchild	if (envy24_checkintr(sc, PCMDIR_REC)) {
1927159687Snetchild#if(0)
1928159687Snetchild		device_printf(sc->dev, "envy24_intr(): rec\n");
1929159687Snetchild#endif
1930159687Snetchild		dsize = sc->rsize / 4;
1931159687Snetchild		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
1932159687Snetchild		ptr -= ptr % sc->blk[1];
1933159687Snetchild		feed = (ptr + dsize - sc->intr[1]) % dsize;
1934159687Snetchild		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
1935159687Snetchild			ch = &sc->chan[i];
1936165306Sariff			if (ch->run && ch->blk <= feed) {
1937165306Sariff				snd_mtxunlock(sc->lock);
1938159687Snetchild				chn_intr(ch->channel);
1939165306Sariff				snd_mtxlock(sc->lock);
1940165306Sariff			}
1941159687Snetchild		}
1942159687Snetchild		sc->intr[1] = ptr;
1943159687Snetchild		envy24_updintr(sc, PCMDIR_REC);
1944159687Snetchild	}
1945159687Snetchild	snd_mtxunlock(sc->lock);
1946159687Snetchild
1947159687Snetchild	return;
1948159687Snetchild}
1949159687Snetchild
1950159687Snetchild/*
1951159687Snetchild * Probe and attach the card
1952159687Snetchild */
1953159687Snetchild
1954159687Snetchildstatic int
1955159687Snetchildenvy24_pci_probe(device_t dev)
1956159687Snetchild{
1957159687Snetchild	u_int16_t sv, sd;
1958159687Snetchild	int i;
1959159687Snetchild
1960159687Snetchild#if(0)
1961159687Snetchild	printf("envy24_pci_probe()\n");
1962159687Snetchild#endif
1963159687Snetchild	if (pci_get_device(dev) == PCID_ENVY24 &&
1964159687Snetchild	    pci_get_vendor(dev) == PCIV_ENVY24) {
1965159687Snetchild		sv = pci_get_subvendor(dev);
1966159687Snetchild		sd = pci_get_subdevice(dev);
1967159687Snetchild		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
1968159687Snetchild			if (cfg_table[i].subvendor == sv &&
1969159687Snetchild			    cfg_table[i].subdevice == sd) {
1970159687Snetchild				break;
1971159687Snetchild			}
1972159687Snetchild		}
1973159687Snetchild		device_set_desc(dev, cfg_table[i].name);
1974159687Snetchild#if(0)
1975159687Snetchild		printf("envy24_pci_probe(): return 0\n");
1976159687Snetchild#endif
1977159687Snetchild		return 0;
1978159687Snetchild	}
1979159687Snetchild	else {
1980159687Snetchild#if(0)
1981159687Snetchild		printf("envy24_pci_probe(): return ENXIO\n");
1982159687Snetchild#endif
1983159687Snetchild		return ENXIO;
1984159687Snetchild	}
1985159687Snetchild}
1986159687Snetchild
1987159687Snetchildstatic void
1988159687Snetchildenvy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1989159687Snetchild{
1990165306Sariff	/* struct sc_info *sc = (struct sc_info *)arg; */
1991159687Snetchild
1992159687Snetchild#if(0)
1993159687Snetchild	device_printf(sc->dev, "envy24_dmapsetmap()\n");
1994159687Snetchild	if (bootverbose) {
1995159687Snetchild		printf("envy24(play): setmap %lx, %lx; ",
1996159687Snetchild		    (unsigned long)segs->ds_addr,
1997159687Snetchild		    (unsigned long)segs->ds_len);
1998159687Snetchild		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
1999159687Snetchild	}
2000165306Sariff#endif
2001159687Snetchild}
2002159687Snetchild
2003159687Snetchildstatic void
2004159687Snetchildenvy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2005159687Snetchild{
2006165306Sariff	/* struct sc_info *sc = (struct sc_info *)arg; */
2007159687Snetchild
2008159687Snetchild#if(0)
2009159687Snetchild	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2010159687Snetchild	if (bootverbose) {
2011159687Snetchild		printf("envy24(record): setmap %lx, %lx; ",
2012159687Snetchild		    (unsigned long)segs->ds_addr,
2013159687Snetchild		    (unsigned long)segs->ds_len);
2014159687Snetchild		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2015159687Snetchild	}
2016165306Sariff#endif
2017159687Snetchild}
2018159687Snetchild
2019159687Snetchildstatic void
2020159687Snetchildenvy24_dmafree(struct sc_info *sc)
2021159687Snetchild{
2022159687Snetchild#if(0)
2023159687Snetchild	device_printf(sc->dev, "envy24_dmafree():");
2024159687Snetchild	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2025159687Snetchild	else printf(" sc->rmap(null)");
2026159687Snetchild	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2027159687Snetchild	else printf(" sc->pmap(null)");
2028159687Snetchild	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2029159687Snetchild	else printf(" sc->rbuf(null)");
2030159687Snetchild	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2031159687Snetchild	else printf(" sc->pbuf(null)\n");
2032159687Snetchild#endif
2033159687Snetchild#if(0)
2034159687Snetchild	if (sc->rmap)
2035159687Snetchild		bus_dmamap_unload(sc->dmat, sc->rmap);
2036159687Snetchild	if (sc->pmap)
2037159687Snetchild		bus_dmamap_unload(sc->dmat, sc->pmap);
2038159687Snetchild	if (sc->rbuf)
2039159687Snetchild		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2040159687Snetchild	if (sc->pbuf)
2041159687Snetchild		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2042159687Snetchild#else
2043159687Snetchild	bus_dmamap_unload(sc->dmat, sc->rmap);
2044159687Snetchild	bus_dmamap_unload(sc->dmat, sc->pmap);
2045159687Snetchild	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2046159687Snetchild	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2047159687Snetchild#endif
2048159687Snetchild
2049159687Snetchild	sc->rmap = sc->pmap = NULL;
2050159687Snetchild	sc->pbuf = NULL;
2051159687Snetchild	sc->rbuf = NULL;
2052159687Snetchild
2053159687Snetchild	return;
2054159687Snetchild}
2055159687Snetchild
2056159687Snetchildstatic int
2057159687Snetchildenvy24_dmainit(struct sc_info *sc)
2058159687Snetchild{
2059159687Snetchild	u_int32_t addr;
2060159687Snetchild
2061159687Snetchild#if(0)
2062159687Snetchild	device_printf(sc->dev, "envy24_dmainit()\n");
2063159687Snetchild#endif
2064159687Snetchild	/* init values */
2065159687Snetchild	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2066159687Snetchild	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2067159687Snetchild	sc->pbuf = NULL;
2068159687Snetchild	sc->rbuf = NULL;
2069159687Snetchild	sc->pmap = sc->rmap = NULL;
2070159687Snetchild	sc->blk[0] = sc->blk[1] = 0;
2071159687Snetchild
2072159687Snetchild	/* allocate DMA buffer */
2073159687Snetchild#if(0)
2074159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2075159687Snetchild#endif
2076159687Snetchild	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2077159687Snetchild		goto bad;
2078159687Snetchild#if(0)
2079159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2080159687Snetchild#endif
2081159687Snetchild	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2082159687Snetchild		goto bad;
2083159687Snetchild#if(0)
2084159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2085159687Snetchild#endif
2086159687Snetchild	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2087159687Snetchild		goto bad;
2088159687Snetchild#if(0)
2089159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2090159687Snetchild#endif
2091159687Snetchild	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2092159687Snetchild		goto bad;
2093159687Snetchild	bzero(sc->pbuf, sc->psize);
2094159687Snetchild	bzero(sc->rbuf, sc->rsize);
2095159687Snetchild
2096159687Snetchild	/* set values to register */
2097159687Snetchild	addr = vtophys(sc->pbuf);
2098159687Snetchild#if(0)
2099159687Snetchild	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2100159687Snetchild#endif
2101159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2102159687Snetchild#if(0)
2103159687Snetchild	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2104159687Snetchild	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2105159687Snetchild#endif
2106159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2107159687Snetchild#if(0)
2108159687Snetchild	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2109159687Snetchild#endif
2110159687Snetchild	addr = vtophys(sc->rbuf);
2111159687Snetchild	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2112159687Snetchild	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2113159687Snetchild
2114159687Snetchild	return 0;
2115159687Snetchild bad:
2116159687Snetchild	envy24_dmafree(sc);
2117159687Snetchild	return ENOSPC;
2118159687Snetchild}
2119159687Snetchild
2120159687Snetchildstatic void
2121159687Snetchildenvy24_putcfg(struct sc_info *sc)
2122159687Snetchild{
2123159689Snetchild	device_printf(sc->dev, "system configuration\n");
2124159687Snetchild	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2125159687Snetchild	    sc->cfg->subvendor, sc->cfg->subdevice);
2126159687Snetchild	printf("  XIN2 Clock Source: ");
2127159687Snetchild	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2128159687Snetchild	case 0x00:
2129159687Snetchild		printf("22.5792MHz(44.1kHz*512)\n");
2130159687Snetchild		break;
2131159687Snetchild	case 0x40:
2132159687Snetchild		printf("16.9344MHz(44.1kHz*384)\n");
2133159687Snetchild		break;
2134159687Snetchild	case 0x80:
2135159687Snetchild		printf("from external clock synthesizer chip\n");
2136159687Snetchild		break;
2137159687Snetchild	default:
2138159687Snetchild		printf("illeagal system setting\n");
2139159687Snetchild	}
2140159687Snetchild	printf("  MPU-401 UART(s) #: ");
2141159687Snetchild	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2142159687Snetchild		printf("2\n");
2143159687Snetchild	else
2144159687Snetchild		printf("1\n");
2145159687Snetchild	printf("  AC'97 codec: ");
2146159687Snetchild	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2147159687Snetchild		printf("not exist\n");
2148159687Snetchild	else
2149159687Snetchild		printf("exist\n");
2150159687Snetchild	printf("  ADC #: ");
2151159687Snetchild	printf("%d\n", sc->adcn);
2152159687Snetchild	printf("  DAC #: ");
2153159687Snetchild	printf("%d\n", sc->dacn);
2154159687Snetchild	printf("  Multi-track converter type: ");
2155159687Snetchild	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2156159687Snetchild		printf("AC'97(SDATA_OUT:");
2157159687Snetchild		if (sc->cfg->acl & PCIM_ACL_OMODE)
2158159687Snetchild			printf("packed");
2159159687Snetchild		else
2160159687Snetchild			printf("split");
2161159687Snetchild		printf("|SDATA_IN:");
2162159687Snetchild		if (sc->cfg->acl & PCIM_ACL_IMODE)
2163159687Snetchild			printf("packed");
2164159687Snetchild		else
2165159687Snetchild			printf("split");
2166159687Snetchild		printf(")\n");
2167159687Snetchild	}
2168159687Snetchild	else {
2169159687Snetchild		printf("I2S(");
2170159687Snetchild		if (sc->cfg->i2s & PCIM_I2S_VOL)
2171159687Snetchild			printf("with volume, ");
2172159687Snetchild		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2173159687Snetchild			printf("96KHz support, ");
2174159687Snetchild		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2175159687Snetchild		case PCIM_I2S_16BIT:
2176159687Snetchild			printf("16bit resolution, ");
2177159687Snetchild			break;
2178159687Snetchild		case PCIM_I2S_18BIT:
2179159687Snetchild			printf("18bit resolution, ");
2180159687Snetchild			break;
2181159687Snetchild		case PCIM_I2S_20BIT:
2182159687Snetchild			printf("20bit resolution, ");
2183159687Snetchild			break;
2184159687Snetchild		case PCIM_I2S_24BIT:
2185159687Snetchild			printf("24bit resolution, ");
2186159687Snetchild			break;
2187159687Snetchild		}
2188159687Snetchild		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2189159687Snetchild	}
2190159687Snetchild	printf("  S/PDIF(IN/OUT): ");
2191159687Snetchild	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2192159687Snetchild		printf("1/");
2193159687Snetchild	else
2194159687Snetchild		printf("0/");
2195159687Snetchild	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2196159687Snetchild		printf("1 ");
2197159687Snetchild	else
2198159687Snetchild		printf("0 ");
2199159687Snetchild	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2200159687Snetchild		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2201159687Snetchild	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2202159687Snetchild	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2203159687Snetchild}
2204159687Snetchild
2205159687Snetchildstatic int
2206159687Snetchildenvy24_init(struct sc_info *sc)
2207159687Snetchild{
2208159687Snetchild	u_int32_t data;
2209159687Snetchild#if(0)
2210159687Snetchild	int rtn;
2211159687Snetchild#endif
2212159687Snetchild	int i;
2213159687Snetchild	u_int32_t sv, sd;
2214159687Snetchild
2215159687Snetchild
2216159687Snetchild#if(0)
2217159687Snetchild	device_printf(sc->dev, "envy24_init()\n");
2218159687Snetchild#endif
2219159687Snetchild
2220159687Snetchild	/* reset chip */
2221159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2222159687Snetchild	DELAY(200);
2223159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2224159687Snetchild	DELAY(200);
2225159687Snetchild
2226159687Snetchild	/* legacy hardware disable */
2227159687Snetchild	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2228159687Snetchild	data |= PCIM_LAC_DISABLE;
2229159687Snetchild	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2230159687Snetchild
2231159687Snetchild	/* check system configuration */
2232159687Snetchild	sc->cfg = NULL;
2233159687Snetchild	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2234159687Snetchild		/* 1st: search configuration from table */
2235159687Snetchild		sv = pci_get_subvendor(sc->dev);
2236159687Snetchild		sd = pci_get_subdevice(sc->dev);
2237159687Snetchild		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2238159687Snetchild#if(0)
2239159687Snetchild			device_printf(sc->dev, "Set configuration from table\n");
2240159687Snetchild#endif
2241159687Snetchild			sc->cfg = &cfg_table[i];
2242159687Snetchild			break;
2243159687Snetchild		}
2244159687Snetchild	}
2245159687Snetchild	if (sc->cfg == NULL) {
2246159687Snetchild		/* 2nd: read configuration from table */
2247159687Snetchild		sc->cfg = envy24_rom2cfg(sc);
2248159687Snetchild	}
2249159687Snetchild	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2250159687Snetchild	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2251159687Snetchild
2252159687Snetchild	if (1 /* bootverbose */) {
2253159687Snetchild		envy24_putcfg(sc);
2254159687Snetchild	}
2255159687Snetchild
2256159687Snetchild	/* set system configuration */
2257159687Snetchild	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2258159687Snetchild	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2259159687Snetchild	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2260159687Snetchild	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2261159687Snetchild	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2262159687Snetchild	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2263159687Snetchild	envy24_gpiowr(sc, sc->cfg->gpiostate);
2264159687Snetchild	for (i = 0; i < sc->adcn; i++) {
2265159687Snetchild		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2266159687Snetchild		sc->cfg->codec->init(sc->adc[i]);
2267159687Snetchild	}
2268159687Snetchild	for (i = 0; i < sc->dacn; i++) {
2269159687Snetchild		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2270159687Snetchild		sc->cfg->codec->init(sc->dac[i]);
2271159687Snetchild	}
2272159687Snetchild
2273159687Snetchild	/* initialize DMA buffer */
2274159687Snetchild#if(0)
2275159687Snetchild	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2276159687Snetchild#endif
2277159687Snetchild	if (envy24_dmainit(sc))
2278159687Snetchild		return ENOSPC;
2279159687Snetchild
2280159687Snetchild	/* initialize status */
2281159687Snetchild	sc->run[0] = sc->run[1] = 0;
2282159687Snetchild	sc->intr[0] = sc->intr[1] = 0;
2283159687Snetchild	sc->speed = 0;
2284159687Snetchild	sc->caps[0].fmtlist = envy24_playfmt;
2285159687Snetchild	sc->caps[1].fmtlist = envy24_recfmt;
2286159687Snetchild
2287159687Snetchild	/* set channel router */
2288159687Snetchild	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2289159687Snetchild	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2290159687Snetchild	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2291159687Snetchild
2292159687Snetchild	/* set macro interrupt mask */
2293159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2294159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2295159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2296159687Snetchild#if(0)
2297159687Snetchild	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2298159687Snetchild#endif
2299159687Snetchild
2300159687Snetchild	return 0;
2301159687Snetchild}
2302159687Snetchild
2303159687Snetchildstatic int
2304166919Sariffenvy24_alloc_resource(struct sc_info *sc)
2305159687Snetchild{
2306159687Snetchild	/* allocate I/O port resource */
2307159687Snetchild	sc->csid = PCIR_CCS;
2308159687Snetchild	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2309159687Snetchild	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2310159687Snetchild	sc->ddmaid = PCIR_DDMA;
2311159687Snetchild	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2312159687Snetchild	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2313159687Snetchild	sc->dsid = PCIR_DS;
2314159687Snetchild	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2315159687Snetchild	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2316159687Snetchild	sc->mtid = PCIR_MT;
2317159687Snetchild	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2318159687Snetchild	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2319159687Snetchild	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2320159687Snetchild		device_printf(sc->dev, "unable to map IO port space\n");
2321159687Snetchild		return ENXIO;
2322159687Snetchild	}
2323159687Snetchild	sc->cst = rman_get_bustag(sc->cs);
2324159687Snetchild	sc->csh = rman_get_bushandle(sc->cs);
2325159687Snetchild	sc->ddmat = rman_get_bustag(sc->ddma);
2326159687Snetchild	sc->ddmah = rman_get_bushandle(sc->ddma);
2327159687Snetchild	sc->dst = rman_get_bustag(sc->ds);
2328159687Snetchild	sc->dsh = rman_get_bushandle(sc->ds);
2329159687Snetchild	sc->mtt = rman_get_bustag(sc->mt);
2330159687Snetchild	sc->mth = rman_get_bushandle(sc->mt);
2331159687Snetchild#if(0)
2332159687Snetchild	device_printf(sc->dev,
2333159687Snetchild	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2334159687Snetchild	    pci_read_config(sc->dev, PCIR_CCS, 4),
2335159687Snetchild	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2336159687Snetchild	    pci_read_config(sc->dev, PCIR_DS, 4),
2337159687Snetchild	    pci_read_config(sc->dev, PCIR_MT, 4));
2338159687Snetchild#endif
2339159687Snetchild
2340159687Snetchild	/* allocate interupt resource */
2341159687Snetchild	sc->irqid = 0;
2342159687Snetchild	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2343159687Snetchild				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2344159687Snetchild	if (!sc->irq ||
2345159687Snetchild	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2346159687Snetchild		device_printf(sc->dev, "unable to map interrupt\n");
2347159687Snetchild		return ENXIO;
2348159687Snetchild	}
2349159687Snetchild
2350159687Snetchild	/* allocate DMA resource */
2351166919Sariff	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2352166919Sariff	    /*alignment*/4,
2353166904Snetchild	    /*boundary*/0,
2354159687Snetchild	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2355159687Snetchild	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2356159687Snetchild	    /*filter*/NULL, /*filterarg*/NULL,
2357159687Snetchild	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2358159687Snetchild	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2359159689Snetchild	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2360159689Snetchild	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2361159687Snetchild		device_printf(sc->dev, "unable to create dma tag\n");
2362159687Snetchild		return ENXIO;
2363159687Snetchild	}
2364159687Snetchild
2365159687Snetchild	return 0;
2366159687Snetchild}
2367159687Snetchild
2368159687Snetchildstatic int
2369159687Snetchildenvy24_pci_attach(device_t dev)
2370159687Snetchild{
2371159687Snetchild	u_int32_t		data;
2372159687Snetchild	struct sc_info 		*sc;
2373159687Snetchild	char 			status[SND_STATUSLEN];
2374159687Snetchild	int			err = 0;
2375159687Snetchild	int			i;
2376159687Snetchild
2377159687Snetchild#if(0)
2378159687Snetchild	device_printf(dev, "envy24_pci_attach()\n");
2379159687Snetchild#endif
2380159687Snetchild	/* get sc_info data area */
2381159687Snetchild	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2382159687Snetchild		device_printf(dev, "cannot allocate softc\n");
2383159687Snetchild		return ENXIO;
2384159687Snetchild	}
2385159687Snetchild
2386159687Snetchild	bzero(sc, sizeof(*sc));
2387167608Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2388159687Snetchild	sc->dev = dev;
2389159687Snetchild
2390159687Snetchild	/* initialize PCI interface */
2391159687Snetchild	data = pci_read_config(dev, PCIR_COMMAND, 2);
2392159687Snetchild	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2393159687Snetchild	pci_write_config(dev, PCIR_COMMAND, data, 2);
2394159687Snetchild	data = pci_read_config(dev, PCIR_COMMAND, 2);
2395159687Snetchild
2396159687Snetchild	/* allocate resources */
2397166919Sariff	err = envy24_alloc_resource(sc);
2398159689Snetchild	if (err) {
2399159687Snetchild		device_printf(dev, "unable to allocate system resources\n");
2400159687Snetchild		goto bad;
2401159687Snetchild	}
2402159687Snetchild
2403159687Snetchild	/* initialize card */
2404159689Snetchild	err = envy24_init(sc);
2405159689Snetchild	if (err) {
2406159687Snetchild		device_printf(dev, "unable to initialize the card\n");
2407159687Snetchild		goto bad;
2408159687Snetchild	}
2409159687Snetchild
2410159687Snetchild	/* set multi track mixer */
2411159687Snetchild	mixer_init(dev, &envy24mixer_class, sc);
2412159687Snetchild
2413159687Snetchild	/* set channel information */
2414167220Sariff	err = pcm_register(dev, sc, sc->dacn, sc->adcn);
2415159689Snetchild	if (err)
2416159687Snetchild		goto bad;
2417167220Sariff	sc->chnum = ENVY24_CHAN_PLAY_DAC1;
2418167220Sariff	for (i = 0; i < sc->dacn; i++) {
2419159687Snetchild		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2420159687Snetchild		sc->chnum++;
2421159687Snetchild	}
2422167220Sariff	sc->chnum = ENVY24_CHAN_REC_ADC1;
2423167220Sariff	for (i = 0; i < sc->adcn; i++) {
2424159687Snetchild		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2425159687Snetchild		sc->chnum++;
2426159687Snetchild	}
2427159687Snetchild
2428159687Snetchild	/* set status iformation */
2429159687Snetchild	snprintf(status, SND_STATUSLEN,
2430159687Snetchild	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2431159687Snetchild	    rman_get_start(sc->cs),
2432159687Snetchild	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2433159687Snetchild	    rman_get_start(sc->ddma),
2434159687Snetchild	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2435159687Snetchild	    rman_get_start(sc->ds),
2436159687Snetchild	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2437159687Snetchild	    rman_get_start(sc->mt),
2438159687Snetchild	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2439159687Snetchild	    rman_get_start(sc->irq));
2440159687Snetchild	pcm_setstatus(dev, status);
2441159687Snetchild
2442159687Snetchild	return 0;
2443159687Snetchild
2444159687Snetchildbad:
2445159687Snetchild	if (sc->ih)
2446159687Snetchild		bus_teardown_intr(dev, sc->irq, sc->ih);
2447159687Snetchild	if (sc->irq)
2448159687Snetchild		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2449159687Snetchild	envy24_dmafree(sc);
2450159687Snetchild	if (sc->dmat)
2451159687Snetchild		bus_dma_tag_destroy(sc->dmat);
2452160796Snetchild	if (sc->cfg->codec->destroy != NULL) {
2453160796Snetchild                for (i = 0; i < sc->adcn; i++)
2454160796Snetchild                        sc->cfg->codec->destroy(sc->adc[i]);
2455160796Snetchild                for (i = 0; i < sc->dacn; i++)
2456160796Snetchild                        sc->cfg->codec->destroy(sc->dac[i]);
2457160796Snetchild        }
2458159687Snetchild	envy24_cfgfree(sc->cfg);
2459159687Snetchild	if (sc->cs)
2460159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2461159687Snetchild	if (sc->ddma)
2462159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2463159687Snetchild	if (sc->ds)
2464159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2465159687Snetchild	if (sc->mt)
2466159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2467159687Snetchild	if (sc->lock)
2468159687Snetchild		snd_mtxfree(sc->lock);
2469159687Snetchild	free(sc, M_ENVY24);
2470159687Snetchild	return err;
2471159687Snetchild}
2472159687Snetchild
2473159687Snetchildstatic int
2474159687Snetchildenvy24_pci_detach(device_t dev)
2475159687Snetchild{
2476159687Snetchild	struct sc_info *sc;
2477159687Snetchild	int r;
2478159687Snetchild	int i;
2479159687Snetchild
2480159687Snetchild#if(0)
2481159687Snetchild	device_printf(dev, "envy24_pci_detach()\n");
2482159687Snetchild#endif
2483159687Snetchild	sc = pcm_getdevinfo(dev);
2484159687Snetchild	if (sc == NULL)
2485159687Snetchild		return 0;
2486159687Snetchild	r = pcm_unregister(dev);
2487159687Snetchild	if (r)
2488159687Snetchild		return r;
2489159687Snetchild
2490159687Snetchild	envy24_dmafree(sc);
2491159687Snetchild	if (sc->cfg->codec->destroy != NULL) {
2492159687Snetchild		for (i = 0; i < sc->adcn; i++)
2493159687Snetchild			sc->cfg->codec->destroy(sc->adc[i]);
2494159687Snetchild		for (i = 0; i < sc->dacn; i++)
2495159687Snetchild			sc->cfg->codec->destroy(sc->dac[i]);
2496159687Snetchild	}
2497159687Snetchild	envy24_cfgfree(sc->cfg);
2498159687Snetchild	bus_dma_tag_destroy(sc->dmat);
2499159687Snetchild	bus_teardown_intr(dev, sc->irq, sc->ih);
2500159687Snetchild	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2501159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2502159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2503159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2504159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2505159687Snetchild	snd_mtxfree(sc->lock);
2506159687Snetchild	free(sc, M_ENVY24);
2507159687Snetchild	return 0;
2508159687Snetchild}
2509159687Snetchild
2510159687Snetchildstatic device_method_t envy24_methods[] = {
2511159687Snetchild	/* Device interface */
2512159687Snetchild	DEVMETHOD(device_probe,		envy24_pci_probe),
2513159687Snetchild	DEVMETHOD(device_attach,	envy24_pci_attach),
2514159687Snetchild	DEVMETHOD(device_detach,	envy24_pci_detach),
2515159687Snetchild	{ 0, 0 }
2516159687Snetchild};
2517159687Snetchild
2518159687Snetchildstatic driver_t envy24_driver = {
2519159687Snetchild	"pcm",
2520159687Snetchild	envy24_methods,
2521159687Snetchild#if __FreeBSD_version > 500000
2522159687Snetchild	PCM_SOFTC_SIZE,
2523159687Snetchild#else
2524159687Snetchild	sizeof(struct snddev_info),
2525159687Snetchild#endif
2526159687Snetchild};
2527159687Snetchild
2528159687SnetchildDRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2529159689SnetchildMODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2530168883SariffMODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2531159687SnetchildMODULE_VERSION(snd_envy24, 1);
2532