xref: /src/sys/dev/sound/pci/envy24ht.c (revision b1bebaaba9b9c0ddfe503c43ca8e9e3917ee2c57)
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 	mtx_lock(&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 		mtx_unlock(&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 		mtx_unlock(&sc->lock);
1504 		sndbuf_setup(ch->buffer, ch->data, ch->size);
1505 		mtx_lock(&sc->lock);
1506 		/* these 2 values are dummy */
1507 		ch->unit = 4;
1508 		ch->blk = 10240;
1509 	}
1510 	mtx_unlock(&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 	mtx_lock(&sc->lock);
1525 	free(ch->data, M_ENVY24HT);
1526 	ch->data = NULL;
1527 	mtx_unlock(&sc->lock);
1528 
1529 	return 0;
1530 }
1531 
1532 static int
1533 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1534 {
1535 	struct sc_chinfo *ch = data;
1536 	struct sc_info *sc = ch->parent;
1537 	struct envy24ht_emldma *emltab;
1538 	/* unsigned int bcnt, bsize; */
1539 	int i;
1540 
1541 #if(0)
1542 	device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1543 #endif
1544 	mtx_lock(&sc->lock);
1545 	/* check and get format related information */
1546 	if (ch->dir == PCMDIR_PLAY)
1547 		emltab = envy24ht_pemltab;
1548 	else
1549 		emltab = envy24ht_remltab;
1550 	if (emltab == NULL) {
1551 		mtx_unlock(&sc->lock);
1552 		return -1;
1553 	}
1554 	for (i = 0; emltab[i].format != 0; i++)
1555 		if (emltab[i].format == format)
1556 			break;
1557 	if (emltab[i].format == 0) {
1558 		mtx_unlock(&sc->lock);
1559 		return -1;
1560 	}
1561 
1562 	/* set format information */
1563 	ch->format = format;
1564 	ch->emldma = emltab[i].emldma;
1565 	if (ch->unit > emltab[i].unit)
1566 		ch->blk *= ch->unit / emltab[i].unit;
1567 	else
1568 		ch->blk /= emltab[i].unit / ch->unit;
1569 	ch->unit = emltab[i].unit;
1570 
1571 	/* set channel buffer information */
1572 	ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1573 #if 0
1574 	if (ch->dir == PCMDIR_PLAY)
1575 		bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1576 	else
1577 		bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1578 	bsize *= ch->unit;
1579 	bcnt = ch->size / bsize;
1580 	sndbuf_resize(ch->buffer, bcnt, bsize);
1581 #endif
1582 	mtx_unlock(&sc->lock);
1583 
1584 #if(0)
1585 	device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1586 #endif
1587 	return 0;
1588 }
1589 
1590 /*
1591   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1592   of speed information value. And real hardware speed setting is done
1593   at start triggered(see envy24htchan_trigger()). So, at this function
1594   is called, any value that ENVY24 can use is able to set. But, at
1595   start triggerd, some other channel is running, and that channel's
1596   speed isn't same with, then trigger function will fail.
1597 */
1598 static u_int32_t
1599 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1600 {
1601 	struct sc_chinfo *ch = data;
1602 	u_int32_t val, prev;
1603 	int i;
1604 
1605 #if(0)
1606 	device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1607 #endif
1608 	prev = 0x7fffffff;
1609 	for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1610 		if (abs(val - speed) < abs(prev - speed))
1611 			prev = val;
1612 		else
1613 			break;
1614 	}
1615 	ch->speed = prev;
1616 
1617 #if(0)
1618 	device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1619 #endif
1620 	return ch->speed;
1621 }
1622 
1623 static u_int32_t
1624 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1625 {
1626 	struct sc_chinfo *ch = data;
1627 	/* struct sc_info *sc = ch->parent; */
1628 	u_int32_t size, prev;
1629 	unsigned int bcnt, bsize;
1630 
1631 #if(0)
1632 	device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1633 #endif
1634 	prev = 0x7fffffff;
1635 	/* mtx_lock(&sc->lock); */
1636 	for (size = ch->size / 2; size > 0; size /= 2) {
1637 		if (abs(size - blocksize) < abs(prev - blocksize))
1638 			prev = size;
1639 		else
1640 			break;
1641 	}
1642 
1643 	ch->blk = prev / ch->unit;
1644 	if (ch->dir == PCMDIR_PLAY)
1645 		ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1646 	else
1647 		ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1648         /* set channel buffer information */
1649         /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1650         if (ch->dir == PCMDIR_PLAY)
1651                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1652         else
1653                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1654         bsize *= ch->unit;
1655         bcnt = ch->size / bsize;
1656         sndbuf_resize(ch->buffer, bcnt, bsize);
1657 	/* mtx_unlock(&sc->lock); */
1658 
1659 #if(0)
1660 	device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1661 #endif
1662 	return prev;
1663 }
1664 
1665 /* semantic note: must start at beginning of buffer */
1666 static int
1667 envy24htchan_trigger(kobj_t obj, void *data, int go)
1668 {
1669 	struct sc_chinfo *ch = data;
1670 	struct sc_info *sc = ch->parent;
1671 	u_int32_t ptr;
1672 	int slot;
1673 	int error = 0;
1674 #if 0
1675 	int i;
1676 
1677 	device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1678 #endif
1679 	mtx_lock(&sc->lock);
1680 	if (ch->dir == PCMDIR_PLAY)
1681 		slot = 0;
1682 	else
1683 		slot = 1;
1684 	switch (go) {
1685 	case PCMTRIG_START:
1686 #if(0)
1687 		device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1688 #endif
1689 		/* check or set channel speed */
1690 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1691 			sc->speed = envy24ht_setspeed(sc, ch->speed);
1692 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1693 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1694 		}
1695 		else if (ch->speed != 0 && ch->speed != sc->speed) {
1696 			error = -1;
1697 			goto fail;
1698 		}
1699 		if (ch->speed == 0)
1700 			ch->channel->speed = sc->speed;
1701 		/* start or enable channel */
1702 		sc->run[slot]++;
1703 		if (sc->run[slot] == 1) {
1704 			/* first channel */
1705 			ch->offset = 0;
1706 			sc->blk[slot] = ch->blk;
1707 		}
1708 		else {
1709 			ptr = envy24ht_gethwptr(sc, ch->dir);
1710 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1711 			    (ch->size / 4)) * 4 / ch->unit;
1712 			if (ch->blk < sc->blk[slot])
1713 				sc->blk[slot] = ch->blk;
1714 		}
1715 		if (ch->dir == PCMDIR_PLAY) {
1716 			ch->emldma(ch);
1717 			envy24ht_setvolume(sc, ch->num);
1718 		}
1719 		envy24ht_updintr(sc, ch->dir);
1720 		if (sc->run[slot] == 1)
1721 			envy24ht_start(sc, ch->dir);
1722 		ch->run = 1;
1723 		break;
1724 	case PCMTRIG_EMLDMAWR:
1725 #if(0)
1726 		device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1727 #endif
1728 		if (ch->run != 1) {
1729 			error = -1;
1730 			goto fail;
1731 		}
1732 		ch->emldma(ch);
1733 		break;
1734 	case PCMTRIG_EMLDMARD:
1735 #if(0)
1736 		device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1737 #endif
1738 		if (ch->run != 1) {
1739 			error = -1;
1740 			goto fail;
1741 		}
1742 		ch->emldma(ch);
1743 		break;
1744 	case PCMTRIG_ABORT:
1745 		if (ch->run) {
1746 #if(0)
1747 		device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1748 #endif
1749 		ch->run = 0;
1750 		sc->run[slot]--;
1751 		if (ch->dir == PCMDIR_PLAY)
1752 			envy24ht_mutevolume(sc, ch->num);
1753 		if (sc->run[slot] == 0) {
1754 			envy24ht_stop(sc, ch->dir);
1755 			sc->intr[slot] = 0;
1756 		}
1757 /*		else if (ch->blk == sc->blk[slot]) {
1758 			sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1759 			for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1760 				if (sc->chan[i].dir == ch->dir &&
1761 				    sc->chan[i].run == 1 &&
1762 				    sc->chan[i].blk < sc->blk[slot])
1763 					sc->blk[slot] = sc->chan[i].blk;
1764 			}
1765 			if (ch->blk != sc->blk[slot])
1766 				envy24ht_updintr(sc, ch->dir);
1767 		}*/
1768 		}
1769 		break;
1770 	}
1771 fail:
1772 	mtx_unlock(&sc->lock);
1773 	return (error);
1774 }
1775 
1776 static u_int32_t
1777 envy24htchan_getptr(kobj_t obj, void *data)
1778 {
1779 	struct sc_chinfo *ch = data;
1780 	struct sc_info *sc = ch->parent;
1781 	u_int32_t ptr, rtn;
1782 
1783 #if(0)
1784 	device_printf(sc->dev, "envy24htchan_getptr()\n");
1785 #endif
1786 	mtx_lock(&sc->lock);
1787 	ptr = envy24ht_gethwptr(sc, ch->dir);
1788 	rtn = ptr * ch->unit;
1789 	mtx_unlock(&sc->lock);
1790 
1791 #if(0)
1792 	device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1793 	    rtn);
1794 #endif
1795 	return rtn;
1796 }
1797 
1798 static struct pcmchan_caps *
1799 envy24htchan_getcaps(kobj_t obj, void *data)
1800 {
1801 	struct sc_chinfo *ch = data;
1802 	struct sc_info *sc = ch->parent;
1803 	struct pcmchan_caps *rtn;
1804 
1805 #if(0)
1806 	device_printf(sc->dev, "envy24htchan_getcaps()\n");
1807 #endif
1808 	mtx_lock(&sc->lock);
1809 	if (ch->dir == PCMDIR_PLAY) {
1810 		if (sc->run[0] == 0)
1811 			rtn = &envy24ht_playcaps;
1812 		else
1813 			rtn = &sc->caps[0];
1814 	}
1815 	else {
1816 		if (sc->run[1] == 0)
1817 			rtn = &envy24ht_reccaps;
1818 		else
1819 			rtn = &sc->caps[1];
1820 	}
1821 	mtx_unlock(&sc->lock);
1822 
1823 	return rtn;
1824 }
1825 
1826 static kobj_method_t envy24htchan_methods[] = {
1827 	KOBJMETHOD(channel_init,		envy24htchan_init),
1828 	KOBJMETHOD(channel_free,		envy24htchan_free),
1829 	KOBJMETHOD(channel_setformat,		envy24htchan_setformat),
1830 	KOBJMETHOD(channel_setspeed,		envy24htchan_setspeed),
1831 	KOBJMETHOD(channel_setblocksize,	envy24htchan_setblocksize),
1832 	KOBJMETHOD(channel_trigger,		envy24htchan_trigger),
1833 	KOBJMETHOD(channel_getptr,		envy24htchan_getptr),
1834 	KOBJMETHOD(channel_getcaps,		envy24htchan_getcaps),
1835 	KOBJMETHOD_END
1836 };
1837 CHANNEL_DECLARE(envy24htchan);
1838 
1839 /* -------------------------------------------------------------------- */
1840 
1841 /* mixer interface */
1842 
1843 static int
1844 envy24htmixer_init(struct snd_mixer *m)
1845 {
1846 	struct sc_info *sc = mix_getdevinfo(m);
1847 
1848 #if(0)
1849 	device_printf(sc->dev, "envy24htmixer_init()\n");
1850 #endif
1851 	if (sc == NULL)
1852 		return -1;
1853 
1854 	/* set volume control rate */
1855 	mtx_lock(&sc->lock);
1856 #if 0
1857 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1858 #endif
1859 
1860 	pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1861 
1862 	mix_setdevs(m, ENVY24HT_MIX_MASK);
1863 	mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1864 
1865 	mtx_unlock(&sc->lock);
1866 
1867 	return 0;
1868 }
1869 
1870 static int
1871 envy24htmixer_reinit(struct snd_mixer *m)
1872 {
1873 	struct sc_info *sc = mix_getdevinfo(m);
1874 
1875 	if (sc == NULL)
1876 		return -1;
1877 #if(0)
1878 	device_printf(sc->dev, "envy24htmixer_reinit()\n");
1879 #endif
1880 
1881 	return 0;
1882 }
1883 
1884 static int
1885 envy24htmixer_uninit(struct snd_mixer *m)
1886 {
1887 	struct sc_info *sc = mix_getdevinfo(m);
1888 
1889 	if (sc == NULL)
1890 		return -1;
1891 #if(0)
1892 	device_printf(sc->dev, "envy24htmixer_uninit()\n");
1893 #endif
1894 
1895 	return 0;
1896 }
1897 
1898 static int
1899 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1900 {
1901 	struct sc_info *sc = mix_getdevinfo(m);
1902 	int ch = envy24ht_mixmap[dev];
1903 	int hwch;
1904 	int i;
1905 
1906 	if (sc == NULL)
1907 		return -1;
1908 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1909 		return -1;
1910 	if (dev != 0 && ch == -1)
1911 		return -1;
1912 	hwch = envy24ht_chanmap[ch];
1913 #if(0)
1914 	device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1915 	    dev, left, right);
1916 #endif
1917 
1918 	mtx_lock(&sc->lock);
1919 	if (dev == 0) {
1920 		for (i = 0; i < sc->dacn; i++) {
1921 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1922 		}
1923 	}
1924 	else {
1925 		/* set volume value for hardware */
1926 		if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1927 			sc->left[hwch] = ENVY24HT_VOL_MUTE;
1928 		if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1929 			sc->right[hwch] = ENVY24HT_VOL_MUTE;
1930 
1931 		/* set volume for record channel and running play channel */
1932 		if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1933 			envy24ht_setvolume(sc, hwch);
1934 	}
1935 	mtx_unlock(&sc->lock);
1936 
1937 	return right << 8 | left;
1938 }
1939 
1940 static u_int32_t
1941 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1942 {
1943 	struct sc_info *sc = mix_getdevinfo(m);
1944 	int ch = envy24ht_mixmap[src];
1945 #if(0)
1946 	device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1947 #endif
1948 
1949 	if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1950 		sc->src = ch;
1951 	return src;
1952 }
1953 
1954 static kobj_method_t envy24htmixer_methods[] = {
1955 	KOBJMETHOD(mixer_init,		envy24htmixer_init),
1956 	KOBJMETHOD(mixer_reinit,	envy24htmixer_reinit),
1957 	KOBJMETHOD(mixer_uninit,	envy24htmixer_uninit),
1958 	KOBJMETHOD(mixer_set,		envy24htmixer_set),
1959 	KOBJMETHOD(mixer_setrecsrc,	envy24htmixer_setrecsrc),
1960 	KOBJMETHOD_END
1961 };
1962 MIXER_DECLARE(envy24htmixer);
1963 
1964 /* -------------------------------------------------------------------- */
1965 
1966 /* The interrupt handler */
1967 static void
1968 envy24ht_intr(void *p)
1969 {
1970 	struct sc_info *sc = (struct sc_info *)p;
1971 	struct sc_chinfo *ch;
1972 	u_int32_t ptr, dsize, feed;
1973 	int i;
1974 
1975 #if(0)
1976 	device_printf(sc->dev, "envy24ht_intr()\n");
1977 #endif
1978 	mtx_lock(&sc->lock);
1979 	if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1980 #if(0)
1981 		device_printf(sc->dev, "envy24ht_intr(): play\n");
1982 #endif
1983 		dsize = sc->psize / 4;
1984 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1985 #if(0)
1986 		device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1987 #endif
1988 		ptr -= ptr % sc->blk[0];
1989 		feed = (ptr + dsize - sc->intr[0]) % dsize;
1990 #if(0)
1991 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1992 #endif
1993 		for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
1994 			ch = &sc->chan[i];
1995 #if(0)
1996 			if (ch->run)
1997 				device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
1998 #endif
1999 			if (ch->run && ch->blk <= feed) {
2000 				mtx_unlock(&sc->lock);
2001 				chn_intr(ch->channel);
2002 				mtx_lock(&sc->lock);
2003 			}
2004 		}
2005 		sc->intr[0] = ptr;
2006 		envy24ht_updintr(sc, PCMDIR_PLAY);
2007 	}
2008 	if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2009 #if(0)
2010 		device_printf(sc->dev, "envy24ht_intr(): rec\n");
2011 #endif
2012 		dsize = sc->rsize / 4;
2013 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2014 		ptr -= ptr % sc->blk[1];
2015 		feed = (ptr + dsize - sc->intr[1]) % dsize;
2016 		for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2017 			ch = &sc->chan[i];
2018 			if (ch->run && ch->blk <= feed) {
2019 				mtx_unlock(&sc->lock);
2020 				chn_intr(ch->channel);
2021 				mtx_lock(&sc->lock);
2022 			}
2023 		}
2024 		sc->intr[1] = ptr;
2025 		envy24ht_updintr(sc, PCMDIR_REC);
2026 	}
2027 	mtx_unlock(&sc->lock);
2028 
2029 	return;
2030 }
2031 
2032 /*
2033  * Probe and attach the card
2034  */
2035 
2036 static int
2037 envy24ht_pci_probe(device_t dev)
2038 {
2039 	u_int16_t sv, sd;
2040 	int i;
2041 
2042 #if(0)
2043 	printf("envy24ht_pci_probe()\n");
2044 #endif
2045 	if (pci_get_device(dev) == PCID_ENVY24HT &&
2046 	    pci_get_vendor(dev) == PCIV_ENVY24) {
2047 		sv = pci_get_subvendor(dev);
2048 		sd = pci_get_subdevice(dev);
2049 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2050 			if (cfg_table[i].subvendor == sv &&
2051 			    cfg_table[i].subdevice == sd) {
2052 				break;
2053 			}
2054 		}
2055 		device_set_desc(dev, cfg_table[i].name);
2056 #if(0)
2057 		printf("envy24ht_pci_probe(): return 0\n");
2058 #endif
2059 		return 0;
2060 	}
2061 	else {
2062 #if(0)
2063 		printf("envy24ht_pci_probe(): return ENXIO\n");
2064 #endif
2065 		return ENXIO;
2066 	}
2067 }
2068 
2069 static void
2070 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2071 {
2072 	struct sc_info *sc = arg;
2073 
2074 	sc->paddr = segs->ds_addr;
2075 #if(0)
2076 	device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2077 	if (bootverbose) {
2078 		printf("envy24ht(play): setmap %lx, %lx; ",
2079 		    (unsigned long)segs->ds_addr,
2080 		    (unsigned long)segs->ds_len);
2081 	}
2082 #endif
2083 	envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2084 	envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2085 }
2086 
2087 static void
2088 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2089 {
2090 	struct sc_info *sc = arg;
2091 
2092 	sc->raddr = segs->ds_addr;
2093 #if(0)
2094 	device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2095 	if (bootverbose) {
2096 		printf("envy24ht(record): setmap %lx, %lx; ",
2097 		    (unsigned long)segs->ds_addr,
2098 		    (unsigned long)segs->ds_len);
2099 	}
2100 #endif
2101 	envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2102 	envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2103 }
2104 
2105 static void
2106 envy24ht_dmafree(struct sc_info *sc)
2107 {
2108 #if(0)
2109 	device_printf(sc->dev, "envy24ht_dmafree():");
2110 	printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2111 	printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2112 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2113 	else printf(" sc->rbuf(null)");
2114 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2115 	else printf(" sc->pbuf(null)\n");
2116 #endif
2117 #if(0)
2118 	if (sc->raddr)
2119 		bus_dmamap_unload(sc->dmat, sc->rmap);
2120 	if (sc->paddr)
2121 		bus_dmamap_unload(sc->dmat, sc->pmap);
2122 	if (sc->rbuf)
2123 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2124 	if (sc->pbuf)
2125 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2126 #else
2127 	bus_dmamap_unload(sc->dmat, sc->rmap);
2128 	bus_dmamap_unload(sc->dmat, sc->pmap);
2129 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2130 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2131 #endif
2132 
2133 	sc->raddr = sc->paddr = 0;
2134 	sc->pbuf = NULL;
2135 	sc->rbuf = NULL;
2136 
2137 	return;
2138 }
2139 
2140 static int
2141 envy24ht_dmainit(struct sc_info *sc)
2142 {
2143 
2144 #if(0)
2145 	device_printf(sc->dev, "envy24ht_dmainit()\n");
2146 #endif
2147 	/* init values */
2148 	sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2149 	sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2150 	sc->pbuf = NULL;
2151 	sc->rbuf = NULL;
2152 	sc->paddr = sc->raddr = 0;
2153 	sc->blk[0] = sc->blk[1] = 0;
2154 
2155 	/* allocate DMA buffer */
2156 #if(0)
2157 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2158 #endif
2159 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2160 		goto bad;
2161 #if(0)
2162 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2163 #endif
2164 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2165 		goto bad;
2166 #if(0)
2167 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2168 #endif
2169 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2170 		goto bad;
2171 #if(0)
2172 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2173 #endif
2174 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2175 		goto bad;
2176 	bzero(sc->pbuf, sc->psize);
2177 	bzero(sc->rbuf, sc->rsize);
2178 
2179 	return 0;
2180  bad:
2181 	envy24ht_dmafree(sc);
2182 	return ENOSPC;
2183 }
2184 
2185 static void
2186 envy24ht_putcfg(struct sc_info *sc)
2187 {
2188 	device_printf(sc->dev, "system configuration\n");
2189 	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2190 	    sc->cfg->subvendor, sc->cfg->subdevice);
2191 	printf("  XIN2 Clock Source: ");
2192 	switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2193 	case 0x00:
2194 		printf("24.576MHz(96kHz*256)\n");
2195 		break;
2196 	case 0x40:
2197 		printf("49.152MHz(192kHz*256)\n");
2198 		break;
2199 	case 0x80:
2200 		printf("reserved\n");
2201 		break;
2202 	default:
2203 		printf("illegal system setting\n");
2204 	}
2205 	printf("  MPU-401 UART(s) #: ");
2206 	if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2207 		printf("1\n");
2208 	else
2209 		printf("not implemented\n");
2210         switch (sc->adcn) {
2211         case 0x01:
2212 	case 0x02:
2213                 printf("  ADC #: ");
2214                 printf("%d\n", sc->adcn);
2215                 break;
2216         case 0x03:
2217                 printf("  ADC #: ");
2218                 printf("%d", 1);
2219                 printf(" and SPDIF receiver connected\n");
2220                 break;
2221         default:
2222                 printf("  no physical inputs\n");
2223         }
2224 	printf("  DAC #: ");
2225 	printf("%d\n", sc->dacn);
2226 	printf("  Multi-track converter type: ");
2227 	if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2228 		printf("AC'97(SDATA_OUT:");
2229 		if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2230 			printf("packed");
2231 		else
2232 			printf("split");
2233 		printf(")\n");
2234 	}
2235 	else {
2236 		printf("I2S(");
2237 		if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2238 			printf("with volume, ");
2239                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2240                         printf("192KHz support, ");
2241                 else
2242                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2243                         printf("192KHz support, ");
2244                 else
2245                         printf("48KHz support, ");
2246 		switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2247 		case ENVY24HT_CCSM_I2S_16BIT:
2248 			printf("16bit resolution, ");
2249 			break;
2250 		case ENVY24HT_CCSM_I2S_18BIT:
2251 			printf("18bit resolution, ");
2252 			break;
2253 		case ENVY24HT_CCSM_I2S_20BIT:
2254 			printf("20bit resolution, ");
2255 			break;
2256 		case ENVY24HT_CCSM_I2S_24BIT:
2257 			printf("24bit resolution, ");
2258 			break;
2259 		}
2260 		printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2261 	}
2262 	printf("  S/PDIF(IN/OUT): ");
2263 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2264 		printf("1/");
2265 	else
2266 		printf("0/");
2267 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2268 		printf("1 ");
2269 	else
2270 		printf("0 ");
2271 	if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2272 		printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2273 	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2274 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2275 }
2276 
2277 static int
2278 envy24ht_init(struct sc_info *sc)
2279 {
2280 	u_int32_t data;
2281 #if(0)
2282 	int rtn;
2283 #endif
2284 	int i;
2285 	u_int32_t sv, sd;
2286 
2287 #if(0)
2288 	device_printf(sc->dev, "envy24ht_init()\n");
2289 #endif
2290 
2291 	/* reset chip */
2292 #if 0
2293 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2294 	DELAY(200);
2295 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2296 	DELAY(200);
2297 
2298 	/* legacy hardware disable */
2299 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2300 	data |= PCIM_LAC_DISABLE;
2301 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2302 #endif
2303 
2304 	/* check system configuration */
2305 	sc->cfg = NULL;
2306 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2307 		/* 1st: search configuration from table */
2308 		sv = pci_get_subvendor(sc->dev);
2309 		sd = pci_get_subdevice(sc->dev);
2310 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2311 #if(0)
2312 			device_printf(sc->dev, "Set configuration from table\n");
2313 #endif
2314 			sc->cfg = &cfg_table[i];
2315 			break;
2316 		}
2317 	}
2318 	if (sc->cfg == NULL) {
2319 		/* 2nd: read configuration from table */
2320 		sc->cfg = envy24ht_rom2cfg(sc);
2321 	}
2322 	sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2323 	sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2324 
2325 	if (1 /* bootverbose */) {
2326 		envy24ht_putcfg(sc);
2327 	}
2328 
2329 	/* set system configuration */
2330 	envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2331 	envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2332 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2333 	envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2334 	envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2335 	envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2336 	envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2337 
2338 	if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2339 		envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2340 		envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2341 		envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2342 	}
2343 
2344 	for (i = 0; i < sc->adcn; i++) {
2345 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2346 		sc->cfg->codec->init(sc->adc[i]);
2347 	}
2348 	for (i = 0; i < sc->dacn; i++) {
2349 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2350 		sc->cfg->codec->init(sc->dac[i]);
2351 	}
2352 
2353 	/* initialize DMA buffer */
2354 #if(0)
2355 	device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2356 #endif
2357 	if (envy24ht_dmainit(sc))
2358 		return ENOSPC;
2359 
2360 	/* initialize status */
2361 	sc->run[0] = sc->run[1] = 0;
2362 	sc->intr[0] = sc->intr[1] = 0;
2363 	sc->speed = 0;
2364 	sc->caps[0].fmtlist = envy24ht_playfmt;
2365 	sc->caps[1].fmtlist = envy24ht_recfmt;
2366 
2367 	/* set channel router */
2368 #if 0
2369 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2370 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2371 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2372 #endif
2373 
2374 	/* set macro interrupt mask */
2375 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2376 	envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2377 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2378 #if(0)
2379 	device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2380 #endif
2381 
2382 	return 0;
2383 }
2384 
2385 static int
2386 envy24ht_alloc_resource(struct sc_info *sc)
2387 {
2388 	/* allocate I/O port resource */
2389 	sc->csid = PCIR_CCS;
2390 	sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2391 	    &sc->csid, RF_ACTIVE);
2392 	sc->mtid = ENVY24HT_PCIR_MT;
2393 	sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2394 	    &sc->mtid, RF_ACTIVE);
2395 	if (!sc->cs || !sc->mt) {
2396 		device_printf(sc->dev, "unable to map IO port space\n");
2397 		return ENXIO;
2398 	}
2399 	sc->cst = rman_get_bustag(sc->cs);
2400 	sc->csh = rman_get_bushandle(sc->cs);
2401 	sc->mtt = rman_get_bustag(sc->mt);
2402 	sc->mth = rman_get_bushandle(sc->mt);
2403 #if(0)
2404 	device_printf(sc->dev,
2405 	    "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2406 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2407 	    pci_read_config(sc->dev, PCIR_MT, 4));
2408 #endif
2409 
2410 	/* allocate interrupt resource */
2411 	sc->irqid = 0;
2412 	sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
2413 				 RF_ACTIVE | RF_SHAREABLE);
2414 	if (!sc->irq ||
2415 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2416 		device_printf(sc->dev, "unable to map interrupt\n");
2417 		return ENXIO;
2418 	}
2419 
2420 	/* allocate DMA resource */
2421 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2422 	    /*alignment*/4,
2423 	    /*boundary*/0,
2424 	    /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2425 	    /*highaddr*/BUS_SPACE_MAXADDR,
2426 	    /*filter*/NULL, /*filterarg*/NULL,
2427 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2428 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2429 	    /*flags*/0, /*lockfunc*/NULL,
2430 	    /*lockarg*/NULL, &sc->dmat) != 0) {
2431 		device_printf(sc->dev, "unable to create dma tag\n");
2432 		return ENXIO;
2433 	}
2434 
2435 	return 0;
2436 }
2437 
2438 static int
2439 envy24ht_pci_attach(device_t dev)
2440 {
2441 	struct sc_info 		*sc;
2442 	char 			status[SND_STATUSLEN];
2443 	int			err = 0;
2444 	int			i;
2445 
2446 #if(0)
2447 	device_printf(dev, "envy24ht_pci_attach()\n");
2448 #endif
2449 	/* get sc_info data area */
2450 	if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2451 		device_printf(dev, "cannot allocate softc\n");
2452 		return ENXIO;
2453 	}
2454 
2455 	bzero(sc, sizeof(*sc));
2456 	mtx_init(&sc->lock, device_get_nameunit(dev), "snd_eny24ht softc",
2457 	    MTX_DEF);
2458 	sc->dev = dev;
2459 
2460 	/* initialize PCI interface */
2461 	pci_enable_busmaster(dev);
2462 
2463 	/* allocate resources */
2464 	err = envy24ht_alloc_resource(sc);
2465 	if (err) {
2466 		device_printf(dev, "unable to allocate system resources\n");
2467 		goto bad;
2468 	}
2469 
2470 	/* initialize card */
2471 	err = envy24ht_init(sc);
2472 	if (err) {
2473 		device_printf(dev, "unable to initialize the card\n");
2474 		goto bad;
2475 	}
2476 
2477 	/* set multi track mixer */
2478 	mixer_init(dev, &envy24htmixer_class, sc);
2479 
2480 	/* set channel information */
2481 	pcm_init(dev, sc);
2482 	sc->chnum = 0;
2483 	/* for (i = 0; i < 5; i++) { */
2484 		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2485 		sc->chnum++;
2486 	/* } */
2487 	for (i = 0; i < 2 + sc->adcn; i++) {
2488 		pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2489 		sc->chnum++;
2490 	}
2491 
2492 	/* set status iformation */
2493 	snprintf(status, SND_STATUSLEN,
2494 	    "port 0x%jx:%jd,0x%jx:%jd irq %jd on %s",
2495 	    rman_get_start(sc->cs),
2496 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2497 	    rman_get_start(sc->mt),
2498 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2499 	    rman_get_start(sc->irq),
2500 	    device_get_nameunit(device_get_parent(dev)));
2501 	if (pcm_register(dev, status))
2502 		goto bad;
2503 
2504 	return 0;
2505 
2506 bad:
2507 	if (sc->ih)
2508 		bus_teardown_intr(dev, sc->irq, sc->ih);
2509 	if (sc->irq)
2510 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2511 	envy24ht_dmafree(sc);
2512 	if (sc->dmat)
2513 		bus_dma_tag_destroy(sc->dmat);
2514         if (sc->cfg->codec->destroy != NULL) {
2515                 for (i = 0; i < sc->adcn; i++)
2516                         sc->cfg->codec->destroy(sc->adc[i]);
2517                 for (i = 0; i < sc->dacn; i++)
2518                         sc->cfg->codec->destroy(sc->dac[i]);
2519         }
2520 	envy24ht_cfgfree(sc->cfg);
2521 	if (sc->cs)
2522 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2523 	if (sc->mt)
2524 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2525 	mtx_destroy(&sc->lock);
2526 	free(sc, M_ENVY24HT);
2527 	return err;
2528 }
2529 
2530 static int
2531 envy24ht_pci_detach(device_t dev)
2532 {
2533 	struct sc_info *sc;
2534 	int r;
2535 	int i;
2536 
2537 #if(0)
2538 	device_printf(dev, "envy24ht_pci_detach()\n");
2539 #endif
2540 	sc = pcm_getdevinfo(dev);
2541 	if (sc == NULL)
2542 		return 0;
2543 	r = pcm_unregister(dev);
2544 	if (r)
2545 		return r;
2546 
2547 	envy24ht_dmafree(sc);
2548 	if (sc->cfg->codec->destroy != NULL) {
2549 		for (i = 0; i < sc->adcn; i++)
2550 			sc->cfg->codec->destroy(sc->adc[i]);
2551 		for (i = 0; i < sc->dacn; i++)
2552 			sc->cfg->codec->destroy(sc->dac[i]);
2553 	}
2554 	envy24ht_cfgfree(sc->cfg);
2555 	bus_dma_tag_destroy(sc->dmat);
2556 	bus_teardown_intr(dev, sc->irq, sc->ih);
2557 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2558 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2559 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2560 	mtx_destroy(&sc->lock);
2561 	free(sc, M_ENVY24HT);
2562 	return 0;
2563 }
2564 
2565 static device_method_t envy24ht_methods[] = {
2566 	/* Device interface */
2567 	DEVMETHOD(device_probe,		envy24ht_pci_probe),
2568 	DEVMETHOD(device_attach,	envy24ht_pci_attach),
2569 	DEVMETHOD(device_detach,	envy24ht_pci_detach),
2570 	{ 0, 0 }
2571 };
2572 
2573 static driver_t envy24ht_driver = {
2574 	"pcm",
2575 	envy24ht_methods,
2576 	PCM_SOFTC_SIZE,
2577 };
2578 
2579 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, 0, 0);
2580 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2581 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2582 MODULE_VERSION(snd_envy24ht, 1);
2583