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