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