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