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