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