xref: /dragonfly/sys/dev/sound/pci/envy24.c (revision 92fc8b5c)
1 /*
2  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/sound/pci/envy24.c,v 1.11.2.2 2007/06/11 19:33:27 ariff Exp $
27  * $DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.3 2008/01/05 14:02:38 swildner Exp $
28  */
29 
30 #include <dev/sound/pcm/sound.h>
31 #include <dev/sound/pcm/ac97.h>
32 #include <dev/sound/pci/spicds.h>
33 #include <dev/sound/pci/envy24.h>
34 
35 #include <bus/pci/pcireg.h>
36 #include <bus/pci/pcivar.h>
37 
38 #include "mixer_if.h"
39 
40 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/envy24.c,v 1.3 2008/01/05 14:02:38 swildner Exp $");
41 
42 MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
43 
44 /* -------------------------------------------------------------------- */
45 
46 struct sc_info;
47 
48 #define ENVY24_PLAY_CHNUM 10
49 #define ENVY24_REC_CHNUM 12
50 #define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
51 #define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
52 #define ENVY24_SAMPLE_NUM   4096
53 
54 #define ENVY24_TIMEOUT 1000
55 
56 #define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
57 
58 #define ENVY24_NAMELEN 32
59 
60 #define SDA_GPIO 0x10
61 #define SCL_GPIO 0x20
62 
63 #define abs(i) (i < 0 ? -i : i)
64 
65 struct envy24_sample {
66         volatile u_int32_t buffer;
67 };
68 
69 typedef struct envy24_sample sample32_t;
70 
71 /* channel registers */
72 struct sc_chinfo {
73 	struct snd_dbuf		*buffer;
74 	struct pcm_channel	*channel;
75 	struct sc_info		*parent;
76 	int			dir;
77 	unsigned		num; /* hw channel number */
78 
79 	/* channel information */
80 	u_int32_t		format;
81 	u_int32_t		speed;
82 	u_int32_t		blk; /* hw block size(dword) */
83 
84 	/* format conversion structure */
85 	u_int8_t		*data;
86 	unsigned int		size; /* data buffer size(byte) */
87 	int			unit; /* sample size(byte) */
88 	unsigned int		offset; /* samples number offset */
89 	void			(*emldma)(struct sc_chinfo *);
90 
91 	/* flags */
92 	int			run;
93 };
94 
95 /* codec interface entrys */
96 struct codec_entry {
97 	void *(*create)(device_t dev, void *devinfo, int dir, int num);
98 	void (*destroy)(void *codec);
99 	void (*init)(void *codec);
100 	void (*reinit)(void *codec);
101 	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
102 	void (*setrate)(void *codec, int which, int rate);
103 };
104 
105 /* system configuration information */
106 struct cfg_info {
107 	char *name;
108 	u_int16_t subvendor, subdevice;
109 	u_int8_t scfg, acl, i2s, spdif;
110 	u_int8_t gpiomask, gpiostate, gpiodir;
111 	u_int8_t cdti, cclk, cs, cif, type;
112 	u_int8_t free;
113 	struct codec_entry *codec;
114 };
115 
116 /* device private data */
117 struct sc_info {
118 	device_t	dev;
119 	sndlock_t	lock;
120 
121 	/* Control/Status registor */
122 	struct resource *cs;
123 	int		csid;
124 	bus_space_tag_t cst;
125 	bus_space_handle_t csh;
126 	/* DDMA registor */
127 	struct resource *ddma;
128 	int		ddmaid;
129 	bus_space_tag_t ddmat;
130 	bus_space_handle_t ddmah;
131 	/* Consumer Section DMA Channel Registers */
132 	struct resource *ds;
133 	int		dsid;
134 	bus_space_tag_t dst;
135 	bus_space_handle_t dsh;
136 	/* MultiTrack registor */
137 	struct resource *mt;
138 	int		mtid;
139 	bus_space_tag_t mtt;
140 	bus_space_handle_t mth;
141 	/* DMA tag */
142 	bus_dma_tag_t dmat;
143 	/* IRQ resource */
144 	struct resource *irq;
145 	int		irqid;
146 	void		*ih;
147 
148 	/* system configuration data */
149 	struct cfg_info *cfg;
150 
151 	/* ADC/DAC number and info */
152 	int		adcn, dacn;
153 	void		*adc[4], *dac[4];
154 
155 	/* mixer control data */
156 	u_int32_t	src;
157 	u_int8_t	left[ENVY24_CHAN_NUM];
158 	u_int8_t	right[ENVY24_CHAN_NUM];
159 
160 	/* Play/Record DMA fifo */
161 	sample32_t	*pbuf;
162 	sample32_t	*rbuf;
163 	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
164 	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
165 	bus_dmamap_t	pmap, rmap;
166 
167 	/* current status */
168 	u_int32_t	speed;
169 	int		run[2];
170 	u_int16_t	intr[2];
171 	struct pcmchan_caps	caps[2];
172 
173 	/* channel info table */
174 	unsigned	chnum;
175 	struct sc_chinfo chan[11];
176 };
177 
178 /* -------------------------------------------------------------------- */
179 
180 /*
181  * prototypes
182  */
183 
184 /* DMA emulator */
185 static void envy24_p8u(struct sc_chinfo *);
186 static void envy24_p16sl(struct sc_chinfo *);
187 static void envy24_p32sl(struct sc_chinfo *);
188 static void envy24_r16sl(struct sc_chinfo *);
189 static void envy24_r32sl(struct sc_chinfo *);
190 
191 /* channel interface */
192 static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193 static int envy24chan_setformat(kobj_t, void *, u_int32_t);
194 static int envy24chan_setspeed(kobj_t, void *, u_int32_t);
195 static int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
196 static int envy24chan_trigger(kobj_t, void *, int);
197 static int envy24chan_getptr(kobj_t, void *);
198 static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
199 
200 /* mixer interface */
201 static int envy24mixer_init(struct snd_mixer *);
202 static int envy24mixer_reinit(struct snd_mixer *);
203 static int envy24mixer_uninit(struct snd_mixer *);
204 static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205 static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
206 
207 /* M-Audio Delta series AK4524 access interface */
208 static void *envy24_delta_ak4524_create(device_t, void *, int, int);
209 static void envy24_delta_ak4524_destroy(void *);
210 static void envy24_delta_ak4524_init(void *);
211 static void envy24_delta_ak4524_reinit(void *);
212 static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
213 
214 /* -------------------------------------------------------------------- */
215 
216 /*
217   system constant tables
218 */
219 
220 /* API -> hardware channel map */
221 static unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
222 	ENVY24_CHAN_PLAY_SPDIF, /* 0 */
223 	ENVY24_CHAN_PLAY_DAC1,  /* 1 */
224 	ENVY24_CHAN_PLAY_DAC2,  /* 2 */
225 	ENVY24_CHAN_PLAY_DAC3,  /* 3 */
226 	ENVY24_CHAN_PLAY_DAC4,  /* 4 */
227 	ENVY24_CHAN_REC_MIX,    /* 5 */
228 	ENVY24_CHAN_REC_SPDIF,  /* 6 */
229 	ENVY24_CHAN_REC_ADC1,   /* 7 */
230 	ENVY24_CHAN_REC_ADC2,   /* 8 */
231 	ENVY24_CHAN_REC_ADC3,   /* 9 */
232 	ENVY24_CHAN_REC_ADC4,   /* 10 */
233 };
234 
235 /* mixer -> API channel map. see above */
236 static int envy24_mixmap[] = {
237 	-1, /* Master output level. It is depend on codec support */
238 	-1, /* Treble level of all output channels */
239 	-1, /* Bass level of all output channels */
240 	-1, /* Volume of synthesier input */
241 	0,  /* Output level for the audio device */
242 	-1, /* Output level for the PC speaker */
243 	7,  /* line in jack */
244 	-1, /* microphone jack */
245 	-1, /* CD audio input */
246 	-1, /* Recording monitor */
247 	1,  /* alternative codec */
248 	-1, /* global recording level */
249 	-1, /* Input gain */
250 	-1, /* Output gain */
251 	8,  /* Input source 1 */
252 	9,  /* Input source 2 */
253 	10, /* Input source 3 */
254 	6,  /* Digital (input) 1 */
255 	-1, /* Digital (input) 2 */
256 	-1, /* Digital (input) 3 */
257 	-1, /* Phone input */
258 	-1, /* Phone output */
259 	-1, /* Video/TV (audio) in */
260 	-1, /* Radio in */
261 	-1, /* Monitor volume */
262 };
263 
264 /* variable rate audio */
265 static u_int32_t envy24_speed[] = {
266     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267     12000, 11025, 9600, 8000, 0
268 };
269 
270 /* known boards configuration */
271 static struct codec_entry delta_codec = {
272 	envy24_delta_ak4524_create,
273 	envy24_delta_ak4524_destroy,
274 	envy24_delta_ak4524_init,
275 	envy24_delta_ak4524_reinit,
276 	envy24_delta_ak4524_setvolume,
277 	NULL, /* setrate */
278 };
279 
280 static struct cfg_info cfg_table[] = {
281 	{
282 		"Envy24 audio (M Audio Delta Dio 2496)",
283 		0x1412, 0xd631,
284 		0x10, 0x80, 0xf0, 0x03,
285 		0xff, 0x00, 0x00,
286 		0x10, 0x20, 0x40, 0x00, 0x00,
287 		0x00,
288 		&delta_codec,
289 	},
290 	{
291 		"Envy24 audio (Terratec DMX 6fire)",
292 		0x153b, 0x1138,
293 		0x2f, 0x80, 0xf0, 0x03,
294 		0xc0, 0xff, 0x7f,
295 		0x10, 0x20, 0x01, 0x01, 0x00,
296 		0x00,
297  		&delta_codec,
298  	},
299 	{
300 		"Envy24 audio (M Audio Audiophile 2496)",
301 		0x1412, 0xd634,
302 		0x10, 0x80, 0x72, 0x03,
303 		0x04, 0xfe, 0xfb,
304 		0x08, 0x02, 0x20, 0x00, 0x01,
305 		0x00,
306  		&delta_codec,
307  	},
308 	{
309 		"Envy24 audio (Generic)",
310 		0, 0,
311 		0x0f, 0x00, 0x01, 0x03,
312 		0xff, 0x00, 0x00,
313 		0x10, 0x20, 0x40, 0x00, 0x00,
314 		0x00,
315 		&delta_codec, /* default codec routines */
316 	}
317 };
318 
319 static u_int32_t envy24_recfmt[] = {
320 	AFMT_STEREO | AFMT_S16_LE,
321 	AFMT_STEREO | AFMT_S32_LE,
322 	0
323 };
324 static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
325 
326 static u_int32_t envy24_playfmt[] = {
327 	AFMT_STEREO | AFMT_U8,
328 	AFMT_STEREO | AFMT_S16_LE,
329 	AFMT_STEREO | AFMT_S32_LE,
330 	0
331 };
332 
333 static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
334 
335 struct envy24_emldma {
336 	u_int32_t	format;
337 	void		(*emldma)(struct sc_chinfo *);
338 	int		unit;
339 };
340 
341 static struct envy24_emldma envy24_pemltab[] = {
342 	{AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
343 	{AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
344 	{AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
345 	{0, NULL, 0}
346 };
347 
348 static struct envy24_emldma envy24_remltab[] = {
349 	{AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
350 	{AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
351 	{0, NULL, 0}
352 };
353 
354 /* -------------------------------------------------------------------- */
355 
356 /* common routines */
357 static u_int32_t
358 envy24_rdcs(struct sc_info *sc, int regno, int size)
359 {
360 	switch (size) {
361 	case 1:
362 		return bus_space_read_1(sc->cst, sc->csh, regno);
363 	case 2:
364 		return bus_space_read_2(sc->cst, sc->csh, regno);
365 	case 4:
366 		return bus_space_read_4(sc->cst, sc->csh, regno);
367 	default:
368 		return 0xffffffff;
369 	}
370 }
371 
372 static void
373 envy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
374 {
375 	switch (size) {
376 	case 1:
377 		bus_space_write_1(sc->cst, sc->csh, regno, data);
378 		break;
379 	case 2:
380 		bus_space_write_2(sc->cst, sc->csh, regno, data);
381 		break;
382 	case 4:
383 		bus_space_write_4(sc->cst, sc->csh, regno, data);
384 		break;
385 	}
386 }
387 
388 static u_int32_t
389 envy24_rdmt(struct sc_info *sc, int regno, int size)
390 {
391 	switch (size) {
392 	case 1:
393 		return bus_space_read_1(sc->mtt, sc->mth, regno);
394 	case 2:
395 		return bus_space_read_2(sc->mtt, sc->mth, regno);
396 	case 4:
397 		return bus_space_read_4(sc->mtt, sc->mth, regno);
398 	default:
399 		return 0xffffffff;
400 	}
401 }
402 
403 static void
404 envy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
405 {
406 	switch (size) {
407 	case 1:
408 		bus_space_write_1(sc->mtt, sc->mth, regno, data);
409 		break;
410 	case 2:
411 		bus_space_write_2(sc->mtt, sc->mth, regno, data);
412 		break;
413 	case 4:
414 		bus_space_write_4(sc->mtt, sc->mth, regno, data);
415 		break;
416 	}
417 }
418 
419 static u_int32_t
420 envy24_rdci(struct sc_info *sc, int regno)
421 {
422 	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
423 	return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
424 }
425 
426 static void
427 envy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
428 {
429 	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
430 	envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
431 }
432 
433 /* -------------------------------------------------------------------- */
434 
435 /* I2C port/E2PROM access routines */
436 
437 static int
438 envy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
439 {
440 	u_int32_t data;
441 	int i;
442 
443 #if(0)
444 	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
445 #endif
446 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
447 		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
448 		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
449 			break;
450 		DELAY(32); /* 31.25kHz */
451 	}
452 	if (i == ENVY24_TIMEOUT) {
453 		return -1;
454 	}
455 	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
456 	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
457 	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
458 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
459 		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
460 		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
461 			break;
462 		DELAY(32); /* 31.25kHz */
463 	}
464 	if (i == ENVY24_TIMEOUT) {
465 		return -1;
466 	}
467 	data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
468 
469 #if(0)
470 	device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
471 #endif
472 	return (int)data;
473 }
474 
475 #if 0
476 static int
477 envy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
478 {
479 	u_int32_t tmp;
480 	int i;
481 
482 #if(0)
483 	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
484 #endif
485 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
486 		tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
487 		if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
488 			break;
489 		DELAY(32); /* 31.25kHz */
490 	}
491 	if (i == ENVY24_TIMEOUT) {
492 		return -1;
493 	}
494 	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
495 	envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
496 	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
497 	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
498 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
499 		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
500 		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
501 			break;
502 		DELAY(32); /* 31.25kHz */
503 	}
504 	if (i == ENVY24_TIMEOUT) {
505 		return -1;
506 	}
507 
508 	return 0;
509 }
510 #endif
511 
512 static int
513 envy24_rdrom(struct sc_info *sc, u_int32_t addr)
514 {
515 	u_int32_t data;
516 
517 #if(0)
518 	device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
519 #endif
520 	data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
521 	if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
522 #if(0)
523 		device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
524 #endif
525 		return -1;
526 	}
527 
528 	return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
529 }
530 
531 static struct cfg_info *
532 envy24_rom2cfg(struct sc_info *sc)
533 {
534 	struct cfg_info *buff;
535 	int size;
536 	int i;
537 
538 #if(0)
539 	device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
540 #endif
541 	size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
542 	if (size < ENVY24_E2PROM_GPIODIR + 1) {
543 #if(0)
544 		device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
545 #endif
546 		return NULL;
547 	}
548 	buff = kmalloc(sizeof(*buff), M_ENVY24, M_WAITOK);
549 	buff->free = 1;
550 
551 	buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
552 	buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
553 	buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
554 	buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
555 	buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
556 	buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
557 	buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
558 	buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
559 	buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
560 	buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
561 	buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
562 
563 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
564 		if (cfg_table[i].subvendor == buff->subvendor &&
565 		    cfg_table[i].subdevice == buff->subdevice)
566 			break;
567 	buff->name = cfg_table[i].name;
568 	buff->codec = cfg_table[i].codec;
569 
570 	return buff;
571 }
572 
573 static void
574 envy24_cfgfree(struct cfg_info *cfg) {
575 	if (cfg == NULL)
576 		return;
577 	if (cfg->free)
578 		kfree(cfg, M_ENVY24);
579 	return;
580 }
581 
582 /* -------------------------------------------------------------------- */
583 
584 /* AC'97 codec access routines */
585 
586 #if 0
587 static int
588 envy24_coldcd(struct sc_info *sc)
589 {
590 	u_int32_t data;
591 	int i;
592 
593 #if(0)
594 	device_printf(sc->dev, "envy24_coldcd()\n");
595 #endif
596 	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
597 	DELAY(10);
598 	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
599 	DELAY(1000);
600 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
601 		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
602 		if (data & ENVY24_MT_AC97CMD_RDY) {
603 			return 0;
604 		}
605 	}
606 
607 	return -1;
608 }
609 #endif
610 
611 static int
612 envy24_slavecd(struct sc_info *sc)
613 {
614 	u_int32_t data;
615 	int i;
616 
617 #if(0)
618 	device_printf(sc->dev, "envy24_slavecd()\n");
619 #endif
620 	envy24_wrmt(sc, ENVY24_MT_AC97CMD,
621 	    ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
622 	DELAY(10);
623 	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
624 	DELAY(1000);
625 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
626 		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
627 		if (data & ENVY24_MT_AC97CMD_RDY) {
628 			return 0;
629 		}
630 	}
631 
632 	return -1;
633 }
634 
635 #if 0
636 static int
637 envy24_rdcd(kobj_t obj, void *devinfo, int regno)
638 {
639 	struct sc_info *sc = (struct sc_info *)devinfo;
640 	u_int32_t data;
641 	int i;
642 
643 #if(0)
644 	device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
645 #endif
646 	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
647 	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
648 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
649 		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
650 		if ((data & ENVY24_MT_AC97CMD_RD) == 0)
651 			break;
652 	}
653 	data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
654 
655 #if(0)
656 	device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
657 #endif
658 	return (int)data;
659 }
660 
661 static int
662 envy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
663 {
664 	struct sc_info *sc = (struct sc_info *)devinfo;
665 	u_int32_t cmd;
666 	int i;
667 
668 #if(0)
669 	device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
670 #endif
671 	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
672 	envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
673 	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
674 	for (i = 0; i < ENVY24_TIMEOUT; i++) {
675 		cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
676 		if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
677 			break;
678 	}
679 
680 	return 0;
681 }
682 
683 static kobj_method_t envy24_ac97_methods[] = {
684 	KOBJMETHOD(ac97_read,	envy24_rdcd),
685 	KOBJMETHOD(ac97_write,	envy24_wrcd),
686 	{0, 0}
687 };
688 AC97_DECLARE(envy24_ac97);
689 #endif
690 
691 /* -------------------------------------------------------------------- */
692 
693 /* GPIO access routines */
694 
695 static u_int32_t
696 envy24_gpiord(struct sc_info *sc)
697 {
698 	return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
699 }
700 
701 static void
702 envy24_gpiowr(struct sc_info *sc, u_int32_t data)
703 {
704 #if(0)
705 	device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
706 	return;
707 #endif
708 	envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
709 	return;
710 }
711 
712 #if 0
713 static u_int32_t
714 envy24_gpiogetmask(struct sc_info *sc)
715 {
716 	return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
717 }
718 #endif
719 
720 static void
721 envy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
722 {
723 	envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
724 	return;
725 }
726 
727 #if 0
728 static u_int32_t
729 envy24_gpiogetdir(struct sc_info *sc)
730 {
731 	return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
732 }
733 #endif
734 
735 static void
736 envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
737 {
738 	envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
739 	return;
740 }
741 
742 /* -------------------------------------------------------------------- */
743 
744 /* Envy24 I2C through GPIO bit-banging */
745 
746 struct envy24_delta_ak4524_codec {
747 	struct spicds_info *info;
748 	struct sc_info *parent;
749 	int dir;
750 	int num;
751 	int cs, cclk, cdti;
752 };
753 
754 static void
755 envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
756 {
757         u_int32_t data = 0;
758         struct envy24_delta_ak4524_codec *ptr = codec;
759 #if(0)
760         device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
761 #endif
762         data = envy24_gpiord(ptr->parent);
763         data &= ~(SDA_GPIO | SCL_GPIO);
764         if (scl) data += SCL_GPIO;
765         if (sda) data += SDA_GPIO;
766         envy24_gpiowr(ptr->parent, data);
767         return;
768 }
769 
770 static void
771 i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
772 {
773         struct envy24_delta_ak4524_codec *ptr = codec;
774         unsigned int sda;
775 
776         if (bit)
777                 sda = 1;
778         else
779                 sda = 0;
780 
781         ctrl(ptr, 0, sda);
782         DELAY(I2C_DELAY);
783         ctrl(ptr, 1, sda);
784         DELAY(I2C_DELAY);
785         ctrl(ptr, 0, sda);
786         DELAY(I2C_DELAY);
787 }
788 
789 static void
790 i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
791 {
792         struct envy24_delta_ak4524_codec *ptr = codec;
793 
794         ctrl(ptr, 1, 1);
795         DELAY(I2C_DELAY);
796         ctrl(ptr, 1, 0);
797         DELAY(I2C_DELAY);
798         ctrl(ptr, 0, 0);
799         DELAY(I2C_DELAY);
800 }
801 
802 static void
803 i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
804 {
805         struct envy24_delta_ak4524_codec *ptr = codec;
806 
807         ctrl(ptr, 0, 0);
808         DELAY(I2C_DELAY);
809         ctrl(ptr, 1, 0);
810         DELAY(I2C_DELAY);
811         ctrl(ptr, 1, 1);
812         DELAY(I2C_DELAY);
813 }
814 
815 static void
816 i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
817 {
818         struct envy24_delta_ak4524_codec *ptr = codec;
819 
820         ctrl(ptr, 0, 1);
821         DELAY(I2C_DELAY);
822         ctrl(ptr, 1, 1);
823         DELAY(I2C_DELAY);
824         /* dummy, need routine to change gpio direction */
825         ctrl(ptr, 0, 1);
826         DELAY(I2C_DELAY);
827 }
828 
829 static void
830 i2c_wr(void *codec,  void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
831 {
832         struct envy24_delta_ak4524_codec *ptr = codec;
833         int mask;
834 
835         i2c_start(ptr, ctrl);
836 
837         for (mask = 0x80; mask != 0; mask >>= 1)
838                 i2c_wrbit(ptr, ctrl, dev & mask);
839         i2c_ack(ptr, ctrl);
840 
841         if (reg != 0xff) {
842         for (mask = 0x80; mask != 0; mask >>= 1)
843                 i2c_wrbit(ptr, ctrl, reg & mask);
844         i2c_ack(ptr, ctrl);
845         }
846 
847         for (mask = 0x80; mask != 0; mask >>= 1)
848                 i2c_wrbit(ptr, ctrl, val & mask);
849         i2c_ack(ptr, ctrl);
850 
851         i2c_stop(ptr, ctrl);
852 }
853 
854 /* -------------------------------------------------------------------- */
855 
856 /* M-Audio Delta series AK4524 access interface routine */
857 
858 static void
859 envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
860 {
861 	u_int32_t data = 0;
862 	struct envy24_delta_ak4524_codec *ptr = codec;
863 
864 #if(0)
865 	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
866 #endif
867 	data = envy24_gpiord(ptr->parent);
868 	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
869 	if (cs) data += ptr->cs;
870 	if (cclk) data += ptr->cclk;
871 	if (cdti) data += ptr->cdti;
872 	envy24_gpiowr(ptr->parent, data);
873 	return;
874 }
875 
876 static void *
877 envy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
878 {
879 	struct sc_info *sc = info;
880 	struct envy24_delta_ak4524_codec *buff = NULL;
881 
882 #if(0)
883 	device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
884 #endif
885 
886 	buff = kmalloc(sizeof(*buff), M_ENVY24, M_WAITOK);
887 
888 	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
889 		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
890 	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
891 		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
892 	else
893 		buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
894 	if (buff->info == NULL) {
895 		kfree(buff, M_ENVY24);
896 		return NULL;
897 	}
898 
899 	buff->parent = sc;
900 	buff->dir = dir;
901 	buff->num = num;
902 
903 	return (void *)buff;
904 }
905 
906 static void
907 envy24_delta_ak4524_destroy(void *codec)
908 {
909 	struct envy24_delta_ak4524_codec *ptr = codec;
910 	if (ptr == NULL)
911 		return;
912 #if(0)
913 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
914 #endif
915 
916 	if (ptr->dir == PCMDIR_PLAY) {
917 		if (ptr->parent->dac[ptr->num] != NULL)
918 			spicds_destroy(ptr->info);
919 	}
920 	else {
921 		if (ptr->parent->adc[ptr->num] != NULL)
922 			spicds_destroy(ptr->info);
923 	}
924 
925 	kfree(codec, M_ENVY24);
926 }
927 
928 static void
929 envy24_delta_ak4524_init(void *codec)
930 {
931 #if 0
932 	u_int32_t gpiomask, gpiodir;
933 #endif
934 	struct envy24_delta_ak4524_codec *ptr = codec;
935 	if (ptr == NULL)
936 		return;
937 #if(0)
938 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
939 #endif
940 
941 	/*
942 	gpiomask = envy24_gpiogetmask(ptr->parent);
943 	gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
944 	envy24_gpiosetmask(ptr->parent, gpiomask);
945 	gpiodir = envy24_gpiogetdir(ptr->parent);
946 	gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
947 	envy24_gpiosetdir(ptr->parent, gpiodir);
948 	*/
949 	ptr->cs = ptr->parent->cfg->cs;
950 #if 0
951 	envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
952 	envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
953 	if (ptr->num == 0)
954 		ptr->cs = ENVY24_GPIO_AK4524_CS0;
955 	else
956 		ptr->cs = ENVY24_GPIO_AK4524_CS1;
957 	ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
958 #endif
959 	ptr->cclk = ptr->parent->cfg->cclk;
960 	ptr->cdti = ptr->parent->cfg->cdti;
961 	spicds_settype(ptr->info,  ptr->parent->cfg->type);
962 	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
963 	spicds_setformat(ptr->info,
964 	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
965 	spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
966 	/* for the time being, init only first codec */
967 	if (ptr->num == 0)
968 		spicds_init(ptr->info);
969 
970         /* 6fire rear input init test, set ptr->num to 1 for test */
971         if (ptr->parent->cfg->subvendor == 0x153b && \
972                 ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
973                 ptr->cs = 0x02;
974                 spicds_init(ptr->info);
975                 device_printf(ptr->parent->dev, "6fire rear input init\n");
976                 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
977                         PCA9554_I2CDEV, PCA9554_DIR, 0x80);
978                 i2c_wr(ptr, envy24_gpio_i2c_ctl, \
979                         PCA9554_I2CDEV, PCA9554_OUT, 0x02);
980         }
981 }
982 
983 static void
984 envy24_delta_ak4524_reinit(void *codec)
985 {
986 	struct envy24_delta_ak4524_codec *ptr = codec;
987 	if (ptr == NULL)
988 		return;
989 #if(0)
990 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
991 #endif
992 
993 	spicds_reinit(ptr->info);
994 }
995 
996 static void
997 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
998 {
999 	struct envy24_delta_ak4524_codec *ptr = codec;
1000 	if (ptr == NULL)
1001 		return;
1002 #if(0)
1003 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1004 #endif
1005 
1006 	spicds_set(ptr->info, dir, left, right);
1007 }
1008 
1009 /*
1010   There is no need for AK452[48] codec to set sample rate
1011   static void
1012   envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1013   {
1014   }
1015 */
1016 
1017 /* -------------------------------------------------------------------- */
1018 
1019 /* hardware access routeines */
1020 
1021 static struct {
1022 	u_int32_t speed;
1023 	u_int32_t code;
1024 } envy24_speedtab[] = {
1025 	{48000, ENVY24_MT_RATE_48000},
1026 	{24000, ENVY24_MT_RATE_24000},
1027 	{12000, ENVY24_MT_RATE_12000},
1028 	{9600, ENVY24_MT_RATE_9600},
1029 	{32000, ENVY24_MT_RATE_32000},
1030 	{16000, ENVY24_MT_RATE_16000},
1031 	{8000, ENVY24_MT_RATE_8000},
1032 	{96000, ENVY24_MT_RATE_96000},
1033 	{64000, ENVY24_MT_RATE_64000},
1034 	{44100, ENVY24_MT_RATE_44100},
1035 	{22050, ENVY24_MT_RATE_22050},
1036 	{11025, ENVY24_MT_RATE_11025},
1037 	{88200, ENVY24_MT_RATE_88200},
1038 	{0, 0x10}
1039 };
1040 
1041 static int
1042 envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1043 	u_int32_t code;
1044 	int i = 0;
1045 
1046 #if(0)
1047 	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1048 #endif
1049 	if (speed == 0) {
1050 		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1051 		envy24_slavecd(sc);
1052 	}
1053 	else {
1054 		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1055 			if (envy24_speedtab[i].speed == speed)
1056 				break;
1057 		}
1058 		code = envy24_speedtab[i].code;
1059 	}
1060 #if(0)
1061 	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1062 #endif
1063 	if (code < 0x10) {
1064 		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1065 		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1066 		code &= ENVY24_MT_RATE_MASK;
1067 		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1068 			if (envy24_speedtab[i].code == code)
1069 				break;
1070 		}
1071 		speed = envy24_speedtab[i].speed;
1072 	}
1073 	else
1074 		speed = 0;
1075 
1076 #if(0)
1077 	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1078 #endif
1079 	return speed;
1080 }
1081 
1082 static void
1083 envy24_setvolume(struct sc_info *sc, unsigned ch)
1084 {
1085 #if(0)
1086 	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1087 #endif
1088 if (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
1089         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1090         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1091         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1092         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1093 	}
1094 
1095 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1096 	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1097 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1098 	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1099 }
1100 
1101 static void
1102 envy24_mutevolume(struct sc_info *sc, unsigned ch)
1103 {
1104 	u_int32_t vol;
1105 
1106 #if(0)
1107 	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1108 #endif
1109 	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1110 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1111 	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1112 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1113 	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1114 }
1115 
1116 static u_int32_t
1117 envy24_gethwptr(struct sc_info *sc, int dir)
1118 {
1119 	int unit, regno;
1120 	u_int32_t ptr, rtn;
1121 
1122 #if(0)
1123 	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1124 #endif
1125 	if (dir == PCMDIR_PLAY) {
1126 		rtn = sc->psize / 4;
1127 		unit = ENVY24_PLAY_BUFUNIT / 4;
1128 		regno = ENVY24_MT_PCNT;
1129 	}
1130 	else {
1131 		rtn = sc->rsize / 4;
1132 		unit = ENVY24_REC_BUFUNIT / 4;
1133 		regno = ENVY24_MT_RCNT;
1134 	}
1135 
1136 	ptr = envy24_rdmt(sc, regno, 2);
1137 	rtn -= (ptr + 1);
1138 	rtn /= unit;
1139 
1140 #if(0)
1141 	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1142 #endif
1143 	return rtn;
1144 }
1145 
1146 static void
1147 envy24_updintr(struct sc_info *sc, int dir)
1148 {
1149 	int regptr, regintr;
1150 	u_int32_t mask, intr;
1151 	u_int32_t ptr, size, cnt;
1152 	u_int16_t blk;
1153 
1154 #if(0)
1155 	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1156 #endif
1157 	if (dir == PCMDIR_PLAY) {
1158 		blk = sc->blk[0];
1159 		size = sc->psize / 4;
1160 		regptr = ENVY24_MT_PCNT;
1161 		regintr = ENVY24_MT_PTERM;
1162 		mask = ~ENVY24_MT_INT_PMASK;
1163 	}
1164 	else {
1165 		blk = sc->blk[1];
1166 		size = sc->rsize / 4;
1167 		regptr = ENVY24_MT_RCNT;
1168 		regintr = ENVY24_MT_RTERM;
1169 		mask = ~ENVY24_MT_INT_RMASK;
1170 	}
1171 
1172 	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1173 	/*
1174 	cnt = blk - ptr % blk - 1;
1175 	if (cnt == 0)
1176 		cnt = blk - 1;
1177 	*/
1178 	cnt = blk - 1;
1179 #if(0)
1180 	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1181 #endif
1182 	envy24_wrmt(sc, regintr, cnt, 2);
1183 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1184 #if(0)
1185 	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1186 #endif
1187 	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1188 #if(0)
1189 	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1190 		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1191 #endif
1192 
1193 	return;
1194 }
1195 
1196 #if 0
1197 static void
1198 envy24_maskintr(struct sc_info *sc, int dir)
1199 {
1200 	u_int32_t mask, intr;
1201 
1202 #if(0)
1203 	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1204 #endif
1205 	if (dir == PCMDIR_PLAY)
1206 		mask = ENVY24_MT_INT_PMASK;
1207 	else
1208 		mask = ENVY24_MT_INT_RMASK;
1209 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1210 	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1211 
1212 	return;
1213 }
1214 #endif
1215 
1216 static int
1217 envy24_checkintr(struct sc_info *sc, int dir)
1218 {
1219 	u_int32_t mask, stat, intr, rtn;
1220 
1221 #if(0)
1222 	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1223 #endif
1224 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1225 	if (dir == PCMDIR_PLAY) {
1226 		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1227 			mask = ~ENVY24_MT_INT_RSTAT;
1228 			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1229 			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1230 		}
1231 	}
1232 	else {
1233 		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1234 			mask = ~ENVY24_MT_INT_PSTAT;
1235 			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1236 			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1237 		}
1238 	}
1239 
1240 	return rtn;
1241 }
1242 
1243 static void
1244 envy24_start(struct sc_info *sc, int dir)
1245 {
1246 	u_int32_t stat, sw;
1247 
1248 #if(0)
1249 	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1250 #endif
1251 	if (dir == PCMDIR_PLAY)
1252 		sw = ENVY24_MT_PCTL_PSTART;
1253 	else
1254 		sw = ENVY24_MT_PCTL_RSTART;
1255 
1256 	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1257 	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1258 #if(0)
1259 	DELAY(100);
1260 	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1261 	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1262 #endif
1263 
1264 	return;
1265 }
1266 
1267 static void
1268 envy24_stop(struct sc_info *sc, int dir)
1269 {
1270 	u_int32_t stat, sw;
1271 
1272 #if(0)
1273 	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1274 #endif
1275 	if (dir == PCMDIR_PLAY)
1276 		sw = ~ENVY24_MT_PCTL_PSTART;
1277 	else
1278 		sw = ~ENVY24_MT_PCTL_RSTART;
1279 
1280 	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1281 	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1282 
1283 	return;
1284 }
1285 
1286 static int
1287 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1288 {
1289 	u_int32_t reg, mask;
1290 	u_int32_t left, right;
1291 
1292 #if(0)
1293 	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1294 	    dac, class, adc, rev);
1295 #endif
1296 	/* parameter pattern check */
1297 	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1298 		return -1;
1299 	if (class == ENVY24_ROUTE_CLASS_MIX &&
1300 	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1301 		return -1;
1302 	if (rev) {
1303 		left = ENVY24_ROUTE_RIGHT;
1304 		right = ENVY24_ROUTE_LEFT;
1305 	}
1306 	else {
1307 		left = ENVY24_ROUTE_LEFT;
1308 		right = ENVY24_ROUTE_RIGHT;
1309 	}
1310 
1311 	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1312 		reg = class | class << 2 |
1313 			((adc << 1 | left) | left << 3) << 8 |
1314 			((adc << 1 | right) | right << 3) << 12;
1315 #if(0)
1316 		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1317 #endif
1318 		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1319 	}
1320 	else {
1321 		mask = ~(0x0303 << dac * 2);
1322 		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1323 		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1324 #if(0)
1325 		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1326 #endif
1327 		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1328 		mask = ~(0xff << dac * 8);
1329 		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1330 		reg = (reg & mask) |
1331 			(((adc << 1 | left) | left << 3) |
1332 			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1333 #if(0)
1334 		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1335 #endif
1336 		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1337 
1338 		/* 6fire rear input init test */
1339 		envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1340 	}
1341 
1342 	return 0;
1343 }
1344 
1345 /* -------------------------------------------------------------------- */
1346 
1347 /* buffer copy routines */
1348 static void
1349 envy24_p32sl(struct sc_chinfo *ch)
1350 {
1351 	int length;
1352 	sample32_t *dmabuf;
1353 	u_int32_t *data;
1354 	int src, dst, ssize, dsize, slot;
1355 	int i;
1356 
1357 	length = sndbuf_getready(ch->buffer) / 8;
1358 	dmabuf = ch->parent->pbuf;
1359 	data = (u_int32_t *)ch->data;
1360 	src = sndbuf_getreadyptr(ch->buffer) / 4;
1361 	dst = src / 2 + ch->offset;
1362 	ssize = ch->size / 4;
1363 	dsize = ch->size / 8;
1364 	slot = ch->num * 2;
1365 
1366 	for (i = 0; i < length; i++) {
1367 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1368 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1369 		dst++;
1370 		dst %= dsize;
1371 		src += 2;
1372 		src %= ssize;
1373 	}
1374 
1375 	return;
1376 }
1377 
1378 static void
1379 envy24_p16sl(struct sc_chinfo *ch)
1380 {
1381 	int length;
1382 	sample32_t *dmabuf;
1383 	u_int16_t *data;
1384 	int src, dst, ssize, dsize, slot;
1385 	int i;
1386 
1387 #if(0)
1388 	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1389 #endif
1390 	length = sndbuf_getready(ch->buffer) / 4;
1391 	dmabuf = ch->parent->pbuf;
1392 	data = (u_int16_t *)ch->data;
1393 	src = sndbuf_getreadyptr(ch->buffer) / 2;
1394 	dst = src / 2 + ch->offset;
1395 	ssize = ch->size / 2;
1396 	dsize = ch->size / 4;
1397 	slot = ch->num * 2;
1398 #if(0)
1399 	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1400 #endif
1401 
1402 	for (i = 0; i < length; i++) {
1403 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1404 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1405 #if(0)
1406 		if (i < 16) {
1407 			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1408 			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1409 		}
1410 #endif
1411 		dst++;
1412 		dst %= dsize;
1413 		src += 2;
1414 		src %= ssize;
1415 	}
1416 #if(0)
1417 	printf("\n");
1418 #endif
1419 
1420 	return;
1421 }
1422 
1423 static void
1424 envy24_p8u(struct sc_chinfo *ch)
1425 {
1426 	int length;
1427 	sample32_t *dmabuf;
1428 	u_int8_t *data;
1429 	int src, dst, ssize, dsize, slot;
1430 	int i;
1431 
1432 	length = sndbuf_getready(ch->buffer) / 2;
1433 	dmabuf = ch->parent->pbuf;
1434 	data = (u_int8_t *)ch->data;
1435 	src = sndbuf_getreadyptr(ch->buffer);
1436 	dst = src / 2 + ch->offset;
1437 	ssize = ch->size;
1438 	dsize = ch->size / 4;
1439 	slot = ch->num * 2;
1440 
1441 	for (i = 0; i < length; i++) {
1442 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1443 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1444 		dst++;
1445 		dst %= dsize;
1446 		src += 2;
1447 		src %= ssize;
1448 	}
1449 
1450 	return;
1451 }
1452 
1453 static void
1454 envy24_r32sl(struct sc_chinfo *ch)
1455 {
1456 	int length;
1457 	sample32_t *dmabuf;
1458 	u_int32_t *data;
1459 	int src, dst, ssize, dsize, slot;
1460 	int i;
1461 
1462 	length = sndbuf_getfree(ch->buffer) / 8;
1463 	dmabuf = ch->parent->rbuf;
1464 	data = (u_int32_t *)ch->data;
1465 	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1466 	src = dst / 2 + ch->offset;
1467 	dsize = ch->size / 4;
1468 	ssize = ch->size / 8;
1469 	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1470 
1471 	for (i = 0; i < length; i++) {
1472 		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1473 		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1474 		dst += 2;
1475 		dst %= dsize;
1476 		src++;
1477 		src %= ssize;
1478 	}
1479 
1480 	return;
1481 }
1482 
1483 static void
1484 envy24_r16sl(struct sc_chinfo *ch)
1485 {
1486 	int length;
1487 	sample32_t *dmabuf;
1488 	u_int16_t *data;
1489 	int src, dst, ssize, dsize, slot;
1490 	int i;
1491 
1492 	length = sndbuf_getfree(ch->buffer) / 4;
1493 	dmabuf = ch->parent->rbuf;
1494 	data = (u_int16_t *)ch->data;
1495 	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1496 	src = dst / 2 + ch->offset;
1497 	dsize = ch->size / 2;
1498 	ssize = ch->size / 8;
1499 	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1500 
1501 	for (i = 0; i < length; i++) {
1502 		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1503 		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1504 		dst += 2;
1505 		dst %= dsize;
1506 		src++;
1507 		src %= ssize;
1508 	}
1509 
1510 	return;
1511 }
1512 
1513 /* -------------------------------------------------------------------- */
1514 
1515 /* channel interface */
1516 static void *
1517 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1518 {
1519 	struct sc_info	*sc = (struct sc_info *)devinfo;
1520 	struct sc_chinfo *ch;
1521 	unsigned num;
1522 
1523 #if(0)
1524 	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1525 #endif
1526 	snd_mtxlock(sc->lock);
1527 	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1528 	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1529 		snd_mtxunlock(sc->lock);
1530 		return NULL;
1531 	}
1532 	num = sc->chnum;
1533 
1534 	ch = &sc->chan[num];
1535 	ch->size = 8 * ENVY24_SAMPLE_NUM;
1536 	ch->data = kmalloc(ch->size, M_ENVY24, M_WAITOK);
1537 	{
1538 		ch->buffer = b;
1539 		ch->channel = c;
1540 		ch->parent = sc;
1541 		ch->dir = dir;
1542 		/* set channel map */
1543 		ch->num = envy24_chanmap[num];
1544 		snd_mtxunlock(sc->lock);
1545 		sndbuf_setup(ch->buffer, ch->data, ch->size);
1546 		snd_mtxlock(sc->lock);
1547 		/* these 2 values are dummy */
1548 		ch->unit = 4;
1549 		ch->blk = 10240;
1550 	}
1551 	snd_mtxunlock(sc->lock);
1552 
1553 	return ch;
1554 }
1555 
1556 static int
1557 envy24chan_free(kobj_t obj, void *data)
1558 {
1559 	struct sc_chinfo *ch = data;
1560 	struct sc_info *sc = ch->parent;
1561 
1562 #if(0)
1563 	device_printf(sc->dev, "envy24chan_free()\n");
1564 #endif
1565 	snd_mtxlock(sc->lock);
1566 	if (ch->data != NULL) {
1567 		kfree(ch->data, M_ENVY24);
1568 		ch->data = NULL;
1569 	}
1570 	snd_mtxunlock(sc->lock);
1571 
1572 	return 0;
1573 }
1574 
1575 static int
1576 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1577 {
1578 	struct sc_chinfo *ch = data;
1579 	struct sc_info *sc = ch->parent;
1580 	struct envy24_emldma *emltab;
1581 	/* unsigned int bcnt, bsize; */
1582 	int i;
1583 
1584 #if(0)
1585 	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1586 #endif
1587 	snd_mtxlock(sc->lock);
1588 	/* check and get format related information */
1589 	if (ch->dir == PCMDIR_PLAY)
1590 		emltab = envy24_pemltab;
1591 	else
1592 		emltab = envy24_remltab;
1593 	if (emltab == NULL) {
1594 		snd_mtxunlock(sc->lock);
1595 		return -1;
1596 	}
1597 	for (i = 0; emltab[i].format != 0; i++)
1598 		if (emltab[i].format == format)
1599 			break;
1600 	if (emltab[i].format == 0) {
1601 		snd_mtxunlock(sc->lock);
1602 		return -1;
1603 	}
1604 
1605 	/* set format information */
1606 	ch->format = format;
1607 	ch->emldma = emltab[i].emldma;
1608 	if (ch->unit > emltab[i].unit)
1609 		ch->blk *= ch->unit / emltab[i].unit;
1610 	else
1611 		ch->blk /= emltab[i].unit / ch->unit;
1612 	ch->unit = emltab[i].unit;
1613 
1614 	/* set channel buffer information */
1615 	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1616 #if 0
1617 	if (ch->dir == PCMDIR_PLAY)
1618 		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1619 	else
1620 		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1621 	bsize *= ch->unit;
1622 	bcnt = ch->size / bsize;
1623 	sndbuf_resize(ch->buffer, bcnt, bsize);
1624 #endif
1625 	snd_mtxunlock(sc->lock);
1626 
1627 #if(0)
1628 	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1629 #endif
1630 	return 0;
1631 }
1632 
1633 /*
1634   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1635   of speed information value. And real hardware speed setting is done
1636   at start triggered(see envy24chan_trigger()). So, at this function
1637   is called, any value that ENVY24 can use is able to set. But, at
1638   start triggerd, some other channel is running, and that channel's
1639   speed isn't same with, then trigger function will fail.
1640 */
1641 static int
1642 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1643 {
1644 	struct sc_chinfo *ch = data;
1645 	u_int32_t val, prev;
1646 	int i;
1647 
1648 #if(0)
1649 	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1650 #endif
1651 	prev = 0x7fffffff;
1652 	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1653 		if (abs(val - speed) < abs(prev - speed))
1654 			prev = val;
1655 		else
1656 			break;
1657 	}
1658 	ch->speed = prev;
1659 
1660 #if(0)
1661 	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1662 #endif
1663 	return ch->speed;
1664 }
1665 
1666 static int
1667 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1668 {
1669 	struct sc_chinfo *ch = data;
1670 	/* struct sc_info *sc = ch->parent; */
1671 	u_int32_t size, prev;
1672         unsigned int bcnt, bsize;
1673 
1674 #if(0)
1675 	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1676 #endif
1677 	prev = 0x7fffffff;
1678 	/* snd_mtxlock(sc->lock); */
1679 	for (size = ch->size / 2; size > 0; size /= 2) {
1680 		if (abs(size - blocksize) < abs(prev - blocksize))
1681 			prev = size;
1682 		else
1683 			break;
1684 	}
1685 
1686 	ch->blk = prev / ch->unit;
1687 	if (ch->dir == PCMDIR_PLAY)
1688 		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1689 	else
1690 		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1691 	/* set channel buffer information */
1692 	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1693         if (ch->dir == PCMDIR_PLAY)
1694                 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1695         else
1696                 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1697         bsize *= ch->unit;
1698         bcnt = ch->size / bsize;
1699         sndbuf_resize(ch->buffer, bcnt, bsize);
1700 	/* snd_mtxunlock(sc->lock); */
1701 
1702 #if(0)
1703 	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1704 #endif
1705 	return prev;
1706 }
1707 
1708 /* semantic note: must start at beginning of buffer */
1709 static int
1710 envy24chan_trigger(kobj_t obj, void *data, int go)
1711 {
1712 	struct sc_chinfo *ch = data;
1713 	struct sc_info *sc = ch->parent;
1714 	u_int32_t ptr;
1715 	int slot;
1716 #if 0
1717 	int i;
1718 
1719 	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1720 #endif
1721 	snd_mtxlock(sc->lock);
1722 	if (ch->dir == PCMDIR_PLAY)
1723 		slot = 0;
1724 	else
1725 		slot = 1;
1726 	switch (go) {
1727 	case PCMTRIG_START:
1728 #if(0)
1729 		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1730 #endif
1731 		/* check or set channel speed */
1732 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1733 			sc->speed = envy24_setspeed(sc, ch->speed);
1734 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1735 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1736 		}
1737 		else if (ch->speed != 0 && ch->speed != sc->speed)
1738 			return -1;
1739 		if (ch->speed == 0)
1740 			ch->channel->speed = sc->speed;
1741 		/* start or enable channel */
1742 		sc->run[slot]++;
1743 		if (sc->run[slot] == 1) {
1744 			/* first channel */
1745 			ch->offset = 0;
1746 			sc->blk[slot] = ch->blk;
1747 		}
1748 		else {
1749 			ptr = envy24_gethwptr(sc, ch->dir);
1750 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1751 			    (ch->size / 4)) * 4 / ch->unit;
1752 			if (ch->blk < sc->blk[slot])
1753 				sc->blk[slot] = ch->blk;
1754 		}
1755 		if (ch->dir == PCMDIR_PLAY) {
1756 			ch->emldma(ch);
1757 			envy24_setvolume(sc, ch->num);
1758 		}
1759 		envy24_updintr(sc, ch->dir);
1760 		if (sc->run[slot] == 1)
1761 			envy24_start(sc, ch->dir);
1762 		ch->run = 1;
1763 		break;
1764 	case PCMTRIG_EMLDMAWR:
1765 #if(0)
1766 		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1767 #endif
1768 		if (ch->run != 1)
1769 			return -1;
1770 		ch->emldma(ch);
1771 		break;
1772 	case PCMTRIG_EMLDMARD:
1773 #if(0)
1774 		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1775 #endif
1776 		if (ch->run != 1)
1777 			return -1;
1778 		ch->emldma(ch);
1779 		break;
1780 	case PCMTRIG_ABORT:
1781 		if (ch->run) {
1782 #if(0)
1783 		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1784 #endif
1785 		ch->run = 0;
1786 		sc->run[slot]--;
1787 		if (ch->dir == PCMDIR_PLAY)
1788 			envy24_mutevolume(sc, ch->num);
1789 		if (sc->run[slot] == 0) {
1790 			envy24_stop(sc, ch->dir);
1791 			sc->intr[slot] = 0;
1792 		}
1793 #if 0
1794 		else if (ch->blk == sc->blk[slot]) {
1795 			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1796 			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1797 				if (sc->chan[i].dir == ch->dir &&
1798 				    sc->chan[i].run == 1 &&
1799 				    sc->chan[i].blk < sc->blk[slot])
1800 					sc->blk[slot] = sc->chan[i].blk;
1801 			}
1802 			if (ch->blk != sc->blk[slot])
1803 				envy24_updintr(sc, ch->dir);
1804 		}
1805 #endif
1806 		}
1807 		break;
1808 	}
1809 	snd_mtxunlock(sc->lock);
1810 
1811 	return 0;
1812 }
1813 
1814 static int
1815 envy24chan_getptr(kobj_t obj, void *data)
1816 {
1817 	struct sc_chinfo *ch = data;
1818 	struct sc_info *sc = ch->parent;
1819 	u_int32_t ptr;
1820 	int rtn;
1821 
1822 #if(0)
1823 	device_printf(sc->dev, "envy24chan_getptr()\n");
1824 #endif
1825 	snd_mtxlock(sc->lock);
1826 	ptr = envy24_gethwptr(sc, ch->dir);
1827 	rtn = ptr * ch->unit;
1828 	snd_mtxunlock(sc->lock);
1829 
1830 #if(0)
1831 	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1832 	    rtn);
1833 #endif
1834 	return rtn;
1835 }
1836 
1837 static struct pcmchan_caps *
1838 envy24chan_getcaps(kobj_t obj, void *data)
1839 {
1840 	struct sc_chinfo *ch = data;
1841 	struct sc_info *sc = ch->parent;
1842 	struct pcmchan_caps *rtn;
1843 
1844 #if(0)
1845 	device_printf(sc->dev, "envy24chan_getcaps()\n");
1846 #endif
1847 	snd_mtxlock(sc->lock);
1848 	if (ch->dir == PCMDIR_PLAY) {
1849 		if (sc->run[0] == 0)
1850 			rtn = &envy24_playcaps;
1851 		else
1852 			rtn = &sc->caps[0];
1853 	}
1854 	else {
1855 		if (sc->run[1] == 0)
1856 			rtn = &envy24_reccaps;
1857 		else
1858 			rtn = &sc->caps[1];
1859 	}
1860 	snd_mtxunlock(sc->lock);
1861 
1862 	return rtn;
1863 }
1864 
1865 static kobj_method_t envy24chan_methods[] = {
1866 	KOBJMETHOD(channel_init,		envy24chan_init),
1867 	KOBJMETHOD(channel_free,		envy24chan_free),
1868 	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1869 	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1870 	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1871 	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1872 	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1873 	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1874 	{ 0, 0 }
1875 };
1876 CHANNEL_DECLARE(envy24chan);
1877 
1878 /* -------------------------------------------------------------------- */
1879 
1880 /* mixer interface */
1881 
1882 static int
1883 envy24mixer_init(struct snd_mixer *m)
1884 {
1885 	struct sc_info *sc = mix_getdevinfo(m);
1886 
1887 #if(0)
1888 	device_printf(sc->dev, "envy24mixer_init()\n");
1889 #endif
1890 	if (sc == NULL)
1891 		return -1;
1892 
1893 	/* set volume control rate */
1894 	snd_mtxlock(sc->lock);
1895 	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1896 
1897 	mix_setdevs(m, ENVY24_MIX_MASK);
1898 	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1899 	snd_mtxunlock(sc->lock);
1900 
1901 	return 0;
1902 }
1903 
1904 static int
1905 envy24mixer_reinit(struct snd_mixer *m)
1906 {
1907 	struct sc_info *sc = mix_getdevinfo(m);
1908 
1909 	if (sc == NULL)
1910 		return -1;
1911 #if(0)
1912 	device_printf(sc->dev, "envy24mixer_reinit()\n");
1913 #endif
1914 
1915 	return 0;
1916 }
1917 
1918 static int
1919 envy24mixer_uninit(struct snd_mixer *m)
1920 {
1921 	struct sc_info *sc = mix_getdevinfo(m);
1922 
1923 	if (sc == NULL)
1924 		return -1;
1925 #if(0)
1926 	device_printf(sc->dev, "envy24mixer_uninit()\n");
1927 #endif
1928 
1929 	return 0;
1930 }
1931 
1932 static int
1933 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1934 {
1935 	struct sc_info *sc = mix_getdevinfo(m);
1936 	int ch = envy24_mixmap[dev];
1937 	int hwch;
1938 	int i;
1939 
1940 	if (sc == NULL)
1941 		return -1;
1942 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1943 		return -1;
1944 	if (dev != 0 && ch == -1)
1945 		return -1;
1946 	hwch = envy24_chanmap[ch];
1947 #if(0)
1948 	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1949 	    dev, left, right);
1950 #endif
1951 
1952 	snd_mtxlock(sc->lock);
1953 	if (dev == 0) {
1954 		for (i = 0; i < sc->dacn; i++) {
1955 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1956 		}
1957 	}
1958 	else {
1959 		/* set volume value for hardware */
1960 		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1961 			sc->left[hwch] = ENVY24_VOL_MUTE;
1962 		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1963 			sc->right[hwch] = ENVY24_VOL_MUTE;
1964 
1965 		/* set volume for record channel and running play channel */
1966 		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1967 			envy24_setvolume(sc, hwch);
1968 	}
1969 	snd_mtxunlock(sc->lock);
1970 
1971 	return right << 8 | left;
1972 }
1973 
1974 static u_int32_t
1975 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1976 {
1977 	struct sc_info *sc = mix_getdevinfo(m);
1978 	int ch = envy24_mixmap[src];
1979 #if(0)
1980 	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1981 #endif
1982 
1983 	if (ch > ENVY24_CHAN_PLAY_SPDIF)
1984 		sc->src = ch;
1985 	return src;
1986 }
1987 
1988 static kobj_method_t envy24mixer_methods[] = {
1989 	KOBJMETHOD(mixer_init,		envy24mixer_init),
1990 	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
1991 	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
1992 	KOBJMETHOD(mixer_set,		envy24mixer_set),
1993 	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
1994 	{ 0, 0 }
1995 };
1996 MIXER_DECLARE(envy24mixer);
1997 
1998 /* -------------------------------------------------------------------- */
1999 
2000 /* The interrupt handler */
2001 static void
2002 envy24_intr(void *p)
2003 {
2004 	struct sc_info *sc = (struct sc_info *)p;
2005 	struct sc_chinfo *ch;
2006 	u_int32_t ptr, dsize, feed;
2007 	int i;
2008 
2009 #if(0)
2010 	device_printf(sc->dev, "envy24_intr()\n");
2011 #endif
2012 	snd_mtxlock(sc->lock);
2013 	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2014 #if(0)
2015 		device_printf(sc->dev, "envy24_intr(): play\n");
2016 #endif
2017 		dsize = sc->psize / 4;
2018 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2019 #if(0)
2020 		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2021 #endif
2022 		ptr -= ptr % sc->blk[0];
2023 		feed = (ptr + dsize - sc->intr[0]) % dsize;
2024 #if(0)
2025 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2026 #endif
2027 		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2028 			ch = &sc->chan[i];
2029 #if(0)
2030 			if (ch->run)
2031 				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2032 #endif
2033 			if (ch->run && ch->blk <= feed) {
2034 				snd_mtxunlock(sc->lock);
2035 				chn_intr(ch->channel);
2036 				snd_mtxlock(sc->lock);
2037 			}
2038 		}
2039 		sc->intr[0] = ptr;
2040 		envy24_updintr(sc, PCMDIR_PLAY);
2041 	}
2042 	if (envy24_checkintr(sc, PCMDIR_REC)) {
2043 #if(0)
2044 		device_printf(sc->dev, "envy24_intr(): rec\n");
2045 #endif
2046 		dsize = sc->rsize / 4;
2047 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2048 		ptr -= ptr % sc->blk[1];
2049 		feed = (ptr + dsize - sc->intr[1]) % dsize;
2050 		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2051 			ch = &sc->chan[i];
2052 			if (ch->run && ch->blk <= feed) {
2053 				snd_mtxunlock(sc->lock);
2054 				chn_intr(ch->channel);
2055 				snd_mtxlock(sc->lock);
2056 			}
2057 		}
2058 		sc->intr[1] = ptr;
2059 		envy24_updintr(sc, PCMDIR_REC);
2060 	}
2061 	snd_mtxunlock(sc->lock);
2062 
2063 	return;
2064 }
2065 
2066 /*
2067  * Probe and attach the card
2068  */
2069 
2070 static int
2071 envy24_pci_probe(device_t dev)
2072 {
2073 	u_int16_t sv, sd;
2074 	int i;
2075 
2076 #if(0)
2077 	printf("envy24_pci_probe()\n");
2078 #endif
2079 	if (pci_get_device(dev) == PCID_ENVY24 &&
2080 	    pci_get_vendor(dev) == PCIV_ENVY24) {
2081 		sv = pci_get_subvendor(dev);
2082 		sd = pci_get_subdevice(dev);
2083 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2084 			if (cfg_table[i].subvendor == sv &&
2085 			    cfg_table[i].subdevice == sd) {
2086 				break;
2087 			}
2088 		}
2089 		device_set_desc(dev, cfg_table[i].name);
2090 #if(0)
2091 		printf("envy24_pci_probe(): return 0\n");
2092 #endif
2093 		return 0;
2094 	}
2095 	else {
2096 #if(0)
2097 		printf("envy24_pci_probe(): return ENXIO\n");
2098 #endif
2099 		return ENXIO;
2100 	}
2101 }
2102 
2103 static void
2104 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2105 {
2106 	/* struct sc_info *sc = (struct sc_info *)arg; */
2107 
2108 #if(0)
2109 	device_printf(sc->dev, "envy24_dmapsetmap()\n");
2110 	if (bootverbose) {
2111 		printf("envy24(play): setmap %lx, %lx; ",
2112 		    (unsigned long)segs->ds_addr,
2113 		    (unsigned long)segs->ds_len);
2114 		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2115 	}
2116 #endif
2117 }
2118 
2119 static void
2120 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2121 {
2122 	/* struct sc_info *sc = (struct sc_info *)arg; */
2123 
2124 #if(0)
2125 	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2126 	if (bootverbose) {
2127 		printf("envy24(record): setmap %lx, %lx; ",
2128 		    (unsigned long)segs->ds_addr,
2129 		    (unsigned long)segs->ds_len);
2130 		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2131 	}
2132 #endif
2133 }
2134 
2135 static void
2136 envy24_dmafree(struct sc_info *sc)
2137 {
2138 #if(0)
2139 	device_printf(sc->dev, "envy24_dmafree():");
2140 	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2141 	else printf(" sc->rmap(null)");
2142 	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2143 	else printf(" sc->pmap(null)");
2144 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2145 	else printf(" sc->rbuf(null)");
2146 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2147 	else printf(" sc->pbuf(null)\n");
2148 #endif
2149 #if(0)
2150 	if (sc->rmap)
2151 		bus_dmamap_unload(sc->dmat, sc->rmap);
2152 	if (sc->pmap)
2153 		bus_dmamap_unload(sc->dmat, sc->pmap);
2154 	if (sc->rbuf)
2155 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2156 	if (sc->pbuf)
2157 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2158 #else
2159 	bus_dmamap_unload(sc->dmat, sc->rmap);
2160 	bus_dmamap_unload(sc->dmat, sc->pmap);
2161 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2162 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2163 #endif
2164 
2165 	sc->rmap = sc->pmap = NULL;
2166 	sc->pbuf = NULL;
2167 	sc->rbuf = NULL;
2168 
2169 	return;
2170 }
2171 
2172 static int
2173 envy24_dmainit(struct sc_info *sc)
2174 {
2175 	u_int32_t addr;
2176 
2177 #if(0)
2178 	device_printf(sc->dev, "envy24_dmainit()\n");
2179 #endif
2180 	/* init values */
2181 	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2182 	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2183 	sc->pbuf = NULL;
2184 	sc->rbuf = NULL;
2185 	sc->pmap = sc->rmap = NULL;
2186 	sc->blk[0] = sc->blk[1] = 0;
2187 
2188 	/* allocate DMA buffer */
2189 #if(0)
2190 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2191 #endif
2192 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2193 		goto bad;
2194 #if(0)
2195 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2196 #endif
2197 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2198 		goto bad;
2199 #if(0)
2200 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2201 #endif
2202 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2203 		goto bad;
2204 #if(0)
2205 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2206 #endif
2207 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2208 		goto bad;
2209 	bzero(sc->pbuf, sc->psize);
2210 	bzero(sc->rbuf, sc->rsize);
2211 
2212 	/* set values to register */
2213 	addr = vtophys(sc->pbuf);
2214 #if(0)
2215 	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2216 #endif
2217 	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2218 #if(0)
2219 	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2220 	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2221 #endif
2222 	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2223 #if(0)
2224 	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2225 #endif
2226 	addr = vtophys(sc->rbuf);
2227 	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2228 	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2229 
2230 	return 0;
2231  bad:
2232 	envy24_dmafree(sc);
2233 	return ENOSPC;
2234 }
2235 
2236 static void
2237 envy24_putcfg(struct sc_info *sc)
2238 {
2239 	device_printf(sc->dev, "system configuration\n");
2240 	kprintf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2241 	    sc->cfg->subvendor, sc->cfg->subdevice);
2242 	kprintf("  XIN2 Clock Source: ");
2243 	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2244 	case 0x00:
2245 		kprintf("22.5792MHz(44.1kHz*512)\n");
2246 		break;
2247 	case 0x40:
2248 		kprintf("16.9344MHz(44.1kHz*384)\n");
2249 		break;
2250 	case 0x80:
2251 		kprintf("from external clock synthesizer chip\n");
2252 		break;
2253 	default:
2254 		kprintf("illegal system setting\n");
2255 	}
2256 	kprintf("  MPU-401 UART(s) #: ");
2257 	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2258 		kprintf("2\n");
2259 	else
2260 		kprintf("1\n");
2261 	kprintf("  AC'97 codec: ");
2262 	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2263 		kprintf("not exist\n");
2264 	else
2265 		kprintf("exist\n");
2266 	kprintf("  ADC #: ");
2267 	kprintf("%d\n", sc->adcn);
2268 	kprintf("  DAC #: ");
2269 	kprintf("%d\n", sc->dacn);
2270 	kprintf("  Multi-track converter type: ");
2271 	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2272 		kprintf("AC'97(SDATA_OUT:");
2273 		if (sc->cfg->acl & PCIM_ACL_OMODE)
2274 			kprintf("packed");
2275 		else
2276 			kprintf("split");
2277 		kprintf("|SDATA_IN:");
2278 		if (sc->cfg->acl & PCIM_ACL_IMODE)
2279 			kprintf("packed");
2280 		else
2281 			kprintf("split");
2282 		kprintf(")\n");
2283 	}
2284 	else {
2285 		kprintf("I2S(");
2286 		if (sc->cfg->i2s & PCIM_I2S_VOL)
2287 			kprintf("with volume, ");
2288 		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2289 			kprintf("96KHz support, ");
2290 		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2291 		case PCIM_I2S_16BIT:
2292 			kprintf("16bit resolution, ");
2293 			break;
2294 		case PCIM_I2S_18BIT:
2295 			kprintf("18bit resolution, ");
2296 			break;
2297 		case PCIM_I2S_20BIT:
2298 			kprintf("20bit resolution, ");
2299 			break;
2300 		case PCIM_I2S_24BIT:
2301 			kprintf("24bit resolution, ");
2302 			break;
2303 		}
2304 		kprintf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2305 	}
2306 	kprintf("  S/PDIF(IN/OUT): ");
2307 	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2308 		kprintf("1/");
2309 	else
2310 		kprintf("0/");
2311 	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2312 		kprintf("1 ");
2313 	else
2314 		kprintf("0 ");
2315 	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2316 		kprintf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2317 	kprintf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2318 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2319 }
2320 
2321 static int
2322 envy24_init(struct sc_info *sc)
2323 {
2324 	u_int32_t data;
2325 #if(0)
2326 	int rtn;
2327 #endif
2328 	int i;
2329 	u_int32_t sv, sd;
2330 
2331 
2332 #if(0)
2333 	device_printf(sc->dev, "envy24_init()\n");
2334 #endif
2335 
2336 	/* reset chip */
2337 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2338 	DELAY(200);
2339 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2340 	DELAY(200);
2341 
2342 	/* legacy hardware disable */
2343 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2344 	data |= PCIM_LAC_DISABLE;
2345 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2346 
2347 	/* check system configuration */
2348 	sc->cfg = NULL;
2349 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2350 		/* 1st: search configuration from table */
2351 		sv = pci_get_subvendor(sc->dev);
2352 		sd = pci_get_subdevice(sc->dev);
2353 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2354 #if(0)
2355 			device_printf(sc->dev, "Set configuration from table\n");
2356 #endif
2357 			sc->cfg = &cfg_table[i];
2358 			break;
2359 		}
2360 	}
2361 	if (sc->cfg == NULL) {
2362 		/* 2nd: read configuration from table */
2363 		sc->cfg = envy24_rom2cfg(sc);
2364 	}
2365 	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2366 	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2367 
2368 	if (1 /* bootverbose */) {
2369 		envy24_putcfg(sc);
2370 	}
2371 
2372 	/* set system configuration */
2373 	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2374 	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2375 	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2376 	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2377 	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2378 	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2379 	envy24_gpiowr(sc, sc->cfg->gpiostate);
2380 	for (i = 0; i < sc->adcn; i++) {
2381 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2382 		sc->cfg->codec->init(sc->adc[i]);
2383 	}
2384 	for (i = 0; i < sc->dacn; i++) {
2385 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2386 		sc->cfg->codec->init(sc->dac[i]);
2387 	}
2388 
2389 	/* initialize DMA buffer */
2390 #if(0)
2391 	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2392 #endif
2393 	if (envy24_dmainit(sc))
2394 		return ENOSPC;
2395 
2396 	/* initialize status */
2397 	sc->run[0] = sc->run[1] = 0;
2398 	sc->intr[0] = sc->intr[1] = 0;
2399 	sc->speed = 0;
2400 	sc->caps[0].fmtlist = envy24_playfmt;
2401 	sc->caps[1].fmtlist = envy24_recfmt;
2402 
2403 	/* set channel router */
2404 	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2405 	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2406 	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2407 
2408 	/* set macro interrupt mask */
2409 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2410 	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2411 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2412 #if(0)
2413 	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2414 #endif
2415 
2416 	return 0;
2417 }
2418 
2419 static int
2420 envy24_alloc_resource(struct sc_info *sc)
2421 {
2422 	/* allocate I/O port resource */
2423 	sc->csid = PCIR_CCS;
2424 	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2425 	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2426 	sc->ddmaid = PCIR_DDMA;
2427 	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2428 	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2429 	sc->dsid = PCIR_DS;
2430 	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2431 	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2432 	sc->mtid = PCIR_MT;
2433 	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2434 	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2435 	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2436 		device_printf(sc->dev, "unable to map IO port space\n");
2437 		return ENXIO;
2438 	}
2439 	sc->cst = rman_get_bustag(sc->cs);
2440 	sc->csh = rman_get_bushandle(sc->cs);
2441 	sc->ddmat = rman_get_bustag(sc->ddma);
2442 	sc->ddmah = rman_get_bushandle(sc->ddma);
2443 	sc->dst = rman_get_bustag(sc->ds);
2444 	sc->dsh = rman_get_bushandle(sc->ds);
2445 	sc->mtt = rman_get_bustag(sc->mt);
2446 	sc->mth = rman_get_bushandle(sc->mt);
2447 #if(0)
2448 	device_printf(sc->dev,
2449 	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2450 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2451 	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2452 	    pci_read_config(sc->dev, PCIR_DS, 4),
2453 	    pci_read_config(sc->dev, PCIR_MT, 4));
2454 #endif
2455 
2456 	/* allocate interupt resource */
2457 	sc->irqid = 0;
2458 	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2459 				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2460 	if (!sc->irq ||
2461 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2462 		device_printf(sc->dev, "unable to map interrupt\n");
2463 		return ENXIO;
2464 	}
2465 
2466 	/* allocate DMA resource */
2467 	if (bus_dma_tag_create(/*parent*/NULL,
2468 	    /*alignment*/4,
2469 	    /*boundary*/0,
2470 	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2471 	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2472 	    /*filter*/NULL, /*filterarg*/NULL,
2473 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2474 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2475 	    /*flags*/0, &sc->dmat) != 0) {
2476 		device_printf(sc->dev, "unable to create dma tag\n");
2477 		return ENXIO;
2478 	}
2479 
2480 	return 0;
2481 }
2482 
2483 static int
2484 envy24_pci_attach(device_t dev)
2485 {
2486 	u_int32_t		data;
2487 	struct sc_info 		*sc;
2488 	char 			status[SND_STATUSLEN];
2489 	int			err = 0;
2490 	int			i;
2491 
2492 #if(0)
2493 	device_printf(dev, "envy24_pci_attach()\n");
2494 #endif
2495 	/* get sc_info data area */
2496 	sc = kmalloc(sizeof(*sc), M_ENVY24, M_WAITOK | M_ZERO);
2497 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2498 	sc->dev = dev;
2499 
2500 	/* initialize PCI interface */
2501 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2502 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2503 	pci_write_config(dev, PCIR_COMMAND, data, 2);
2504 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2505 
2506 	/* allocate resources */
2507 	err = envy24_alloc_resource(sc);
2508 	if (err) {
2509 		device_printf(dev, "unable to allocate system resources\n");
2510 		goto bad;
2511 	}
2512 
2513 	/* initialize card */
2514 	err = envy24_init(sc);
2515 	if (err) {
2516 		device_printf(dev, "unable to initialize the card\n");
2517 		goto bad;
2518 	}
2519 
2520 	/* set multi track mixer */
2521 	mixer_init(dev, &envy24mixer_class, sc);
2522 
2523 	/* set channel information */
2524 	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2525 	if (err)
2526 		goto bad;
2527 	sc->chnum = 0;
2528 	for (i = 0; i < 5; i++) {
2529 		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2530 		sc->chnum++;
2531 	}
2532 	for (i = 0; i < 2 + sc->adcn; i++) {
2533 		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2534 		sc->chnum++;
2535 	}
2536 
2537 	/* set status iformation */
2538 	ksnprintf(status, SND_STATUSLEN,
2539 	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2540 	    rman_get_start(sc->cs),
2541 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2542 	    rman_get_start(sc->ddma),
2543 	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2544 	    rman_get_start(sc->ds),
2545 	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2546 	    rman_get_start(sc->mt),
2547 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2548 	    rman_get_start(sc->irq));
2549 	pcm_setstatus(dev, status);
2550 
2551 	return 0;
2552 
2553 bad:
2554 	if (sc->ih)
2555 		bus_teardown_intr(dev, sc->irq, sc->ih);
2556 	if (sc->irq)
2557 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2558 	envy24_dmafree(sc);
2559 	if (sc->dmat)
2560 		bus_dma_tag_destroy(sc->dmat);
2561 	if (sc->cfg->codec->destroy != NULL) {
2562                 for (i = 0; i < sc->adcn; i++)
2563                         sc->cfg->codec->destroy(sc->adc[i]);
2564                 for (i = 0; i < sc->dacn; i++)
2565                         sc->cfg->codec->destroy(sc->dac[i]);
2566         }
2567 	envy24_cfgfree(sc->cfg);
2568 	if (sc->cs)
2569 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2570 	if (sc->ddma)
2571 		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2572 	if (sc->ds)
2573 		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2574 	if (sc->mt)
2575 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2576 	if (sc->lock)
2577 		snd_mtxfree(sc->lock);
2578 	kfree(sc, M_ENVY24);
2579 	return err;
2580 }
2581 
2582 static int
2583 envy24_pci_detach(device_t dev)
2584 {
2585 	struct sc_info *sc;
2586 	int r;
2587 	int i;
2588 
2589 #if(0)
2590 	device_printf(dev, "envy24_pci_detach()\n");
2591 #endif
2592 	sc = pcm_getdevinfo(dev);
2593 	if (sc == NULL)
2594 		return 0;
2595 	r = pcm_unregister(dev);
2596 	if (r)
2597 		return r;
2598 
2599 	envy24_dmafree(sc);
2600 	if (sc->cfg->codec->destroy != NULL) {
2601 		for (i = 0; i < sc->adcn; i++)
2602 			sc->cfg->codec->destroy(sc->adc[i]);
2603 		for (i = 0; i < sc->dacn; i++)
2604 			sc->cfg->codec->destroy(sc->dac[i]);
2605 	}
2606 	envy24_cfgfree(sc->cfg);
2607 	bus_dma_tag_destroy(sc->dmat);
2608 	bus_teardown_intr(dev, sc->irq, sc->ih);
2609 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2610 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2611 	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2612 	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2613 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2614 	snd_mtxfree(sc->lock);
2615 	kfree(sc, M_ENVY24);
2616 	return 0;
2617 }
2618 
2619 static device_method_t envy24_methods[] = {
2620 	/* Device interface */
2621 	DEVMETHOD(device_probe,		envy24_pci_probe),
2622 	DEVMETHOD(device_attach,	envy24_pci_attach),
2623 	DEVMETHOD(device_detach,	envy24_pci_detach),
2624 	{ 0, 0 }
2625 };
2626 
2627 static driver_t envy24_driver = {
2628 	"pcm",
2629 	envy24_methods,
2630 #if __FreeBSD_version > 500000
2631 	PCM_SOFTC_SIZE,
2632 #else
2633 	sizeof(struct snddev_info),
2634 #endif
2635 };
2636 
2637 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2638 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2639 MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2640 MODULE_VERSION(snd_envy24, 1);
2641