xref: /freebsd/sys/dev/sound/pci/envy24ht.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
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 	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 regptr, regintr;
1158 	u_int32_t mask, intr;
1159 	u_int32_t ptr, size, 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 		size = sc->psize / 4;
1168 		regptr = ENVY24HT_MT_PCNT;
1169 		regintr = ENVY24HT_MT_PTERM;
1170 		mask = ~ENVY24HT_MT_INT_PMASK;
1171 	}
1172 	else {
1173 		blk = sc->blk[1];
1174 		size = sc->rsize / 4;
1175 		regptr = ENVY24HT_MT_RCNT;
1176 		regintr = ENVY24HT_MT_RTERM;
1177 		mask = ~ENVY24HT_MT_INT_RMASK;
1178 	}
1179 
1180 	ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
1181 	/*
1182 	cnt = blk - ptr % blk - 1;
1183 	if (cnt == 0)
1184 		cnt = blk - 1;
1185 	*/
1186 	cnt = blk - 1;
1187 #if(0)
1188 	device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1189 #endif
1190 	envy24ht_wrmt(sc, regintr, cnt, 2);
1191 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1192 #if(0)
1193 	device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1194 #endif
1195 	envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
1196 #if(0)
1197 	device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
1198 		      envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
1199 #endif
1200 
1201 	return;
1202 }
1203 
1204 #if 0
1205 static void
1206 envy24ht_maskintr(struct sc_info *sc, int dir)
1207 {
1208 	u_int32_t mask, intr;
1209 
1210 #if(0)
1211 	device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
1212 #endif
1213 	if (dir == PCMDIR_PLAY)
1214 		mask = ENVY24HT_MT_INT_PMASK;
1215 	else
1216 		mask = ENVY24HT_MT_INT_RMASK;
1217 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
1218 	envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
1219 
1220 	return;
1221 }
1222 #endif
1223 
1224 static int
1225 envy24ht_checkintr(struct sc_info *sc, int dir)
1226 {
1227 	u_int32_t mask, stat, intr, rtn;
1228 
1229 #if(0)
1230 	device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
1231 #endif
1232 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
1233 	if (dir == PCMDIR_PLAY) {
1234 		if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
1235 			mask = ~ENVY24HT_MT_INT_RSTAT;
1236 			envy24ht_wrmt(sc, 0x1a, 0x01, 1);
1237 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
1238 			stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1239 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
1240 		}
1241 	}
1242 	else {
1243 		if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
1244 			mask = ~ENVY24HT_MT_INT_PSTAT;
1245 #if 0
1246 			stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
1247 #endif
1248 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
1249 			stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
1250 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
1251 		}
1252 	}
1253 
1254 	return rtn;
1255 }
1256 
1257 static void
1258 envy24ht_start(struct sc_info *sc, int dir)
1259 {
1260 	u_int32_t stat, sw;
1261 
1262 #if(0)
1263 	device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
1264 #endif
1265 	if (dir == PCMDIR_PLAY)
1266 		sw = ENVY24HT_MT_PCTL_PSTART;
1267 	else
1268 		sw = ENVY24HT_MT_PCTL_RSTART;
1269 
1270 	stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1271 	envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
1272 #if(0)
1273 	DELAY(100);
1274 	device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
1275 	device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
1276 #endif
1277 
1278 	return;
1279 }
1280 
1281 static void
1282 envy24ht_stop(struct sc_info *sc, int dir)
1283 {
1284 	u_int32_t stat, sw;
1285 
1286 #if(0)
1287 	device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
1288 #endif
1289 	if (dir == PCMDIR_PLAY)
1290 		sw = ~ENVY24HT_MT_PCTL_PSTART;
1291 	else
1292 		sw = ~ENVY24HT_MT_PCTL_RSTART;
1293 
1294 	stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
1295 	envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
1296 
1297 	return;
1298 }
1299 
1300 #if 0
1301 static int
1302 envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1303 {
1304 	return 0;
1305 }
1306 #endif
1307 
1308 /* -------------------------------------------------------------------- */
1309 
1310 /* buffer copy routines */
1311 static void
1312 envy24ht_p32sl(struct sc_chinfo *ch)
1313 {
1314 	int length;
1315 	sample32_t *dmabuf;
1316 	u_int32_t *data;
1317 	int src, dst, ssize, dsize, slot;
1318 	int i;
1319 
1320 	length = sndbuf_getready(ch->buffer) / 8;
1321 	dmabuf = ch->parent->pbuf;
1322 	data = (u_int32_t *)ch->data;
1323 	src = sndbuf_getreadyptr(ch->buffer) / 4;
1324 	dst = src / 2 + ch->offset;
1325 	ssize = ch->size / 4;
1326 	dsize = ch->size / 8;
1327 	slot = ch->num * 2;
1328 
1329 	for (i = 0; i < length; i++) {
1330 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
1331 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1332 		dst++;
1333 		dst %= dsize;
1334 		src += 2;
1335 		src %= ssize;
1336 	}
1337 
1338 	return;
1339 }
1340 
1341 static void
1342 envy24ht_p16sl(struct sc_chinfo *ch)
1343 {
1344 	int length;
1345 	sample32_t *dmabuf;
1346 	u_int16_t *data;
1347 	int src, dst, ssize, dsize, slot;
1348 	int i;
1349 
1350 #if(0)
1351 	device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
1352 #endif
1353 	length = sndbuf_getready(ch->buffer) / 4;
1354 	dmabuf = ch->parent->pbuf;
1355 	data = (u_int16_t *)ch->data;
1356 	src = sndbuf_getreadyptr(ch->buffer) / 2;
1357 	dst = src / 2 + ch->offset;
1358 	ssize = ch->size / 2;
1359 	dsize = ch->size / 4;
1360 	slot = ch->num * 2;
1361 #if(0)
1362 	device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1363 #endif
1364 
1365 	for (i = 0; i < length; i++) {
1366 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1367 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1368 #if(0)
1369 		if (i < 16) {
1370 			printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
1371 			printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
1372 		}
1373 #endif
1374 		dst++;
1375 		dst %= dsize;
1376 		src += 2;
1377 		src %= ssize;
1378 	}
1379 #if(0)
1380 	printf("\n");
1381 #endif
1382 
1383 	return;
1384 }
1385 
1386 static void
1387 envy24ht_p8u(struct sc_chinfo *ch)
1388 {
1389 	int length;
1390 	sample32_t *dmabuf;
1391 	u_int8_t *data;
1392 	int src, dst, ssize, dsize, slot;
1393 	int i;
1394 
1395 	length = sndbuf_getready(ch->buffer) / 2;
1396 	dmabuf = ch->parent->pbuf;
1397 	data = (u_int8_t *)ch->data;
1398 	src = sndbuf_getreadyptr(ch->buffer);
1399 	dst = src / 2 + ch->offset;
1400 	ssize = ch->size;
1401 	dsize = ch->size / 4;
1402 	slot = ch->num * 2;
1403 
1404 	for (i = 0; i < length; i++) {
1405 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1406 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1407 		dst++;
1408 		dst %= dsize;
1409 		src += 2;
1410 		src %= ssize;
1411 	}
1412 
1413 	return;
1414 }
1415 
1416 static void
1417 envy24ht_r32sl(struct sc_chinfo *ch)
1418 {
1419 	int length;
1420 	sample32_t *dmabuf;
1421 	u_int32_t *data;
1422 	int src, dst, ssize, dsize, slot;
1423 	int i;
1424 
1425 	length = sndbuf_getfree(ch->buffer) / 8;
1426 	dmabuf = ch->parent->rbuf;
1427 	data = (u_int32_t *)ch->data;
1428 	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1429 	src = dst / 2 + ch->offset;
1430 	dsize = ch->size / 4;
1431 	ssize = ch->size / 8;
1432 	slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1433 
1434 	for (i = 0; i < length; i++) {
1435 		data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1436 		data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1437 		dst += 2;
1438 		dst %= dsize;
1439 		src++;
1440 		src %= ssize;
1441 	}
1442 
1443 	return;
1444 }
1445 
1446 static void
1447 envy24ht_r16sl(struct sc_chinfo *ch)
1448 {
1449 	int length;
1450 	sample32_t *dmabuf;
1451 	u_int16_t *data;
1452 	int src, dst, ssize, dsize, slot;
1453 	int i;
1454 
1455 	length = sndbuf_getfree(ch->buffer) / 4;
1456 	dmabuf = ch->parent->rbuf;
1457 	data = (u_int16_t *)ch->data;
1458 	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1459 	src = dst / 2 + ch->offset;
1460 	dsize = ch->size / 2;
1461 	ssize = ch->size / 8;
1462 	slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
1463 
1464 	for (i = 0; i < length; i++) {
1465 		data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
1466 		data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
1467 		dst += 2;
1468 		dst %= dsize;
1469 		src++;
1470 		src %= ssize;
1471 	}
1472 
1473 	return;
1474 }
1475 
1476 /* -------------------------------------------------------------------- */
1477 
1478 /* channel interface */
1479 static void *
1480 envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1481 {
1482 	struct sc_info	*sc = (struct sc_info *)devinfo;
1483 	struct sc_chinfo *ch;
1484 	unsigned num;
1485 
1486 #if(0)
1487 	device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
1488 #endif
1489 	snd_mtxlock(sc->lock);
1490 #if 0
1491 	if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1492 	    (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1493 		snd_mtxunlock(sc->lock);
1494 		return NULL;
1495 	}
1496 #endif
1497 	num = sc->chnum;
1498 
1499 	ch = &sc->chan[num];
1500 	ch->size = 8 * ENVY24HT_SAMPLE_NUM;
1501 	ch->data = malloc(ch->size, M_ENVY24HT, M_NOWAIT);
1502 	if (ch->data == NULL) {
1503 		ch->size = 0;
1504 		ch = NULL;
1505 	}
1506 	else {
1507 		ch->buffer = b;
1508 		ch->channel = c;
1509 		ch->parent = sc;
1510 		ch->dir = dir;
1511 		/* set channel map */
1512 		ch->num = envy24ht_chanmap[num];
1513 		snd_mtxunlock(sc->lock);
1514 		sndbuf_setup(ch->buffer, ch->data, ch->size);
1515 		snd_mtxlock(sc->lock);
1516 		/* these 2 values are dummy */
1517 		ch->unit = 4;
1518 		ch->blk = 10240;
1519 	}
1520 	snd_mtxunlock(sc->lock);
1521 
1522 	return ch;
1523 }
1524 
1525 static int
1526 envy24htchan_free(kobj_t obj, void *data)
1527 {
1528 	struct sc_chinfo *ch = data;
1529 	struct sc_info *sc = ch->parent;
1530 
1531 #if(0)
1532 	device_printf(sc->dev, "envy24htchan_free()\n");
1533 #endif
1534 	snd_mtxlock(sc->lock);
1535 	if (ch->data != NULL) {
1536 		free(ch->data, M_ENVY24HT);
1537 		ch->data = NULL;
1538 	}
1539 	snd_mtxunlock(sc->lock);
1540 
1541 	return 0;
1542 }
1543 
1544 static int
1545 envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
1546 {
1547 	struct sc_chinfo *ch = data;
1548 	struct sc_info *sc = ch->parent;
1549 	struct envy24ht_emldma *emltab;
1550 	/* unsigned int bcnt, bsize; */
1551 	int i;
1552 
1553 #if(0)
1554 	device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
1555 #endif
1556 	snd_mtxlock(sc->lock);
1557 	/* check and get format related information */
1558 	if (ch->dir == PCMDIR_PLAY)
1559 		emltab = envy24ht_pemltab;
1560 	else
1561 		emltab = envy24ht_remltab;
1562 	if (emltab == NULL) {
1563 		snd_mtxunlock(sc->lock);
1564 		return -1;
1565 	}
1566 	for (i = 0; emltab[i].format != 0; i++)
1567 		if (emltab[i].format == format)
1568 			break;
1569 	if (emltab[i].format == 0) {
1570 		snd_mtxunlock(sc->lock);
1571 		return -1;
1572 	}
1573 
1574 	/* set format information */
1575 	ch->format = format;
1576 	ch->emldma = emltab[i].emldma;
1577 	if (ch->unit > emltab[i].unit)
1578 		ch->blk *= ch->unit / emltab[i].unit;
1579 	else
1580 		ch->blk /= emltab[i].unit / ch->unit;
1581 	ch->unit = emltab[i].unit;
1582 
1583 	/* set channel buffer information */
1584 	ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
1585 #if 0
1586 	if (ch->dir == PCMDIR_PLAY)
1587 		bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1588 	else
1589 		bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1590 	bsize *= ch->unit;
1591 	bcnt = ch->size / bsize;
1592 	sndbuf_resize(ch->buffer, bcnt, bsize);
1593 #endif
1594 	snd_mtxunlock(sc->lock);
1595 
1596 #if(0)
1597 	device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
1598 #endif
1599 	return 0;
1600 }
1601 
1602 /*
1603   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1604   of speed information value. And real hardware speed setting is done
1605   at start triggered(see envy24htchan_trigger()). So, at this function
1606   is called, any value that ENVY24 can use is able to set. But, at
1607   start triggerd, some other channel is running, and that channel's
1608   speed isn't same with, then trigger function will fail.
1609 */
1610 static u_int32_t
1611 envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1612 {
1613 	struct sc_chinfo *ch = data;
1614 	u_int32_t val, prev;
1615 	int i;
1616 
1617 #if(0)
1618 	device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
1619 #endif
1620 	prev = 0x7fffffff;
1621 	for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
1622 		if (abs(val - speed) < abs(prev - speed))
1623 			prev = val;
1624 		else
1625 			break;
1626 	}
1627 	ch->speed = prev;
1628 
1629 #if(0)
1630 	device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
1631 #endif
1632 	return ch->speed;
1633 }
1634 
1635 static u_int32_t
1636 envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1637 {
1638 	struct sc_chinfo *ch = data;
1639 	/* struct sc_info *sc = ch->parent; */
1640 	u_int32_t size, prev;
1641 	unsigned int bcnt, bsize;
1642 
1643 #if(0)
1644 	device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
1645 #endif
1646 	prev = 0x7fffffff;
1647 	/* snd_mtxlock(sc->lock); */
1648 	for (size = ch->size / 2; size > 0; size /= 2) {
1649 		if (abs(size - blocksize) < abs(prev - blocksize))
1650 			prev = size;
1651 		else
1652 			break;
1653 	}
1654 
1655 	ch->blk = prev / ch->unit;
1656 	if (ch->dir == PCMDIR_PLAY)
1657 		ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
1658 	else
1659 		ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
1660         /* set channel buffer information */
1661         /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
1662         if (ch->dir == PCMDIR_PLAY)
1663                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
1664         else
1665                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
1666         bsize *= ch->unit;
1667         bcnt = ch->size / bsize;
1668         sndbuf_resize(ch->buffer, bcnt, bsize);
1669 	/* snd_mtxunlock(sc->lock); */
1670 
1671 #if(0)
1672 	device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
1673 #endif
1674 	return prev;
1675 }
1676 
1677 /* semantic note: must start at beginning of buffer */
1678 static int
1679 envy24htchan_trigger(kobj_t obj, void *data, int go)
1680 {
1681 	struct sc_chinfo *ch = data;
1682 	struct sc_info *sc = ch->parent;
1683 	u_int32_t ptr;
1684 	int slot;
1685 	int error = 0;
1686 #if 0
1687 	int i;
1688 
1689 	device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1690 #endif
1691 	snd_mtxlock(sc->lock);
1692 	if (ch->dir == PCMDIR_PLAY)
1693 		slot = 0;
1694 	else
1695 		slot = 1;
1696 	switch (go) {
1697 	case PCMTRIG_START:
1698 #if(0)
1699 		device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1700 #endif
1701 		/* check or set channel speed */
1702 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1703 			sc->speed = envy24ht_setspeed(sc, ch->speed);
1704 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1705 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1706 		}
1707 		else if (ch->speed != 0 && ch->speed != sc->speed) {
1708 			error = -1;
1709 			goto fail;
1710 		}
1711 		if (ch->speed == 0)
1712 			ch->channel->speed = sc->speed;
1713 		/* start or enable channel */
1714 		sc->run[slot]++;
1715 		if (sc->run[slot] == 1) {
1716 			/* first channel */
1717 			ch->offset = 0;
1718 			sc->blk[slot] = ch->blk;
1719 		}
1720 		else {
1721 			ptr = envy24ht_gethwptr(sc, ch->dir);
1722 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1723 			    (ch->size / 4)) * 4 / ch->unit;
1724 			if (ch->blk < sc->blk[slot])
1725 				sc->blk[slot] = ch->blk;
1726 		}
1727 		if (ch->dir == PCMDIR_PLAY) {
1728 			ch->emldma(ch);
1729 			envy24ht_setvolume(sc, ch->num);
1730 		}
1731 		envy24ht_updintr(sc, ch->dir);
1732 		if (sc->run[slot] == 1)
1733 			envy24ht_start(sc, ch->dir);
1734 		ch->run = 1;
1735 		break;
1736 	case PCMTRIG_EMLDMAWR:
1737 #if(0)
1738 		device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1739 #endif
1740 		if (ch->run != 1) {
1741 			error = -1;
1742 			goto fail;
1743 		}
1744 		ch->emldma(ch);
1745 		break;
1746 	case PCMTRIG_EMLDMARD:
1747 #if(0)
1748 		device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1749 #endif
1750 		if (ch->run != 1) {
1751 			error = -1;
1752 			goto fail;
1753 		}
1754 		ch->emldma(ch);
1755 		break;
1756 	case PCMTRIG_ABORT:
1757 		if (ch->run) {
1758 #if(0)
1759 		device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1760 #endif
1761 		ch->run = 0;
1762 		sc->run[slot]--;
1763 		if (ch->dir == PCMDIR_PLAY)
1764 			envy24ht_mutevolume(sc, ch->num);
1765 		if (sc->run[slot] == 0) {
1766 			envy24ht_stop(sc, ch->dir);
1767 			sc->intr[slot] = 0;
1768 		}
1769 /*		else if (ch->blk == sc->blk[slot]) {
1770 			sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1771 			for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1772 				if (sc->chan[i].dir == ch->dir &&
1773 				    sc->chan[i].run == 1 &&
1774 				    sc->chan[i].blk < sc->blk[slot])
1775 					sc->blk[slot] = sc->chan[i].blk;
1776 			}
1777 			if (ch->blk != sc->blk[slot])
1778 				envy24ht_updintr(sc, ch->dir);
1779 		}*/
1780 		}
1781 		break;
1782 	}
1783 fail:
1784 	snd_mtxunlock(sc->lock);
1785 	return (error);
1786 }
1787 
1788 static u_int32_t
1789 envy24htchan_getptr(kobj_t obj, void *data)
1790 {
1791 	struct sc_chinfo *ch = data;
1792 	struct sc_info *sc = ch->parent;
1793 	u_int32_t ptr, rtn;
1794 
1795 #if(0)
1796 	device_printf(sc->dev, "envy24htchan_getptr()\n");
1797 #endif
1798 	snd_mtxlock(sc->lock);
1799 	ptr = envy24ht_gethwptr(sc, ch->dir);
1800 	rtn = ptr * ch->unit;
1801 	snd_mtxunlock(sc->lock);
1802 
1803 #if(0)
1804 	device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1805 	    rtn);
1806 #endif
1807 	return rtn;
1808 }
1809 
1810 static struct pcmchan_caps *
1811 envy24htchan_getcaps(kobj_t obj, void *data)
1812 {
1813 	struct sc_chinfo *ch = data;
1814 	struct sc_info *sc = ch->parent;
1815 	struct pcmchan_caps *rtn;
1816 
1817 #if(0)
1818 	device_printf(sc->dev, "envy24htchan_getcaps()\n");
1819 #endif
1820 	snd_mtxlock(sc->lock);
1821 	if (ch->dir == PCMDIR_PLAY) {
1822 		if (sc->run[0] == 0)
1823 			rtn = &envy24ht_playcaps;
1824 		else
1825 			rtn = &sc->caps[0];
1826 	}
1827 	else {
1828 		if (sc->run[1] == 0)
1829 			rtn = &envy24ht_reccaps;
1830 		else
1831 			rtn = &sc->caps[1];
1832 	}
1833 	snd_mtxunlock(sc->lock);
1834 
1835 	return rtn;
1836 }
1837 
1838 static kobj_method_t envy24htchan_methods[] = {
1839 	KOBJMETHOD(channel_init,		envy24htchan_init),
1840 	KOBJMETHOD(channel_free,		envy24htchan_free),
1841 	KOBJMETHOD(channel_setformat,		envy24htchan_setformat),
1842 	KOBJMETHOD(channel_setspeed,		envy24htchan_setspeed),
1843 	KOBJMETHOD(channel_setblocksize,	envy24htchan_setblocksize),
1844 	KOBJMETHOD(channel_trigger,		envy24htchan_trigger),
1845 	KOBJMETHOD(channel_getptr,		envy24htchan_getptr),
1846 	KOBJMETHOD(channel_getcaps,		envy24htchan_getcaps),
1847 	KOBJMETHOD_END
1848 };
1849 CHANNEL_DECLARE(envy24htchan);
1850 
1851 /* -------------------------------------------------------------------- */
1852 
1853 /* mixer interface */
1854 
1855 static int
1856 envy24htmixer_init(struct snd_mixer *m)
1857 {
1858 	struct sc_info *sc = mix_getdevinfo(m);
1859 
1860 #if(0)
1861 	device_printf(sc->dev, "envy24htmixer_init()\n");
1862 #endif
1863 	if (sc == NULL)
1864 		return -1;
1865 
1866 	/* set volume control rate */
1867 	snd_mtxlock(sc->lock);
1868 #if 0
1869 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1870 #endif
1871 
1872 	pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1873 
1874 	mix_setdevs(m, ENVY24HT_MIX_MASK);
1875 	mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1876 
1877 	snd_mtxunlock(sc->lock);
1878 
1879 	return 0;
1880 }
1881 
1882 static int
1883 envy24htmixer_reinit(struct snd_mixer *m)
1884 {
1885 	struct sc_info *sc = mix_getdevinfo(m);
1886 
1887 	if (sc == NULL)
1888 		return -1;
1889 #if(0)
1890 	device_printf(sc->dev, "envy24htmixer_reinit()\n");
1891 #endif
1892 
1893 	return 0;
1894 }
1895 
1896 static int
1897 envy24htmixer_uninit(struct snd_mixer *m)
1898 {
1899 	struct sc_info *sc = mix_getdevinfo(m);
1900 
1901 	if (sc == NULL)
1902 		return -1;
1903 #if(0)
1904 	device_printf(sc->dev, "envy24htmixer_uninit()\n");
1905 #endif
1906 
1907 	return 0;
1908 }
1909 
1910 static int
1911 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1912 {
1913 	struct sc_info *sc = mix_getdevinfo(m);
1914 	int ch = envy24ht_mixmap[dev];
1915 	int hwch;
1916 	int i;
1917 
1918 	if (sc == NULL)
1919 		return -1;
1920 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1921 		return -1;
1922 	if (dev != 0 && ch == -1)
1923 		return -1;
1924 	hwch = envy24ht_chanmap[ch];
1925 #if(0)
1926 	device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1927 	    dev, left, right);
1928 #endif
1929 
1930 	snd_mtxlock(sc->lock);
1931 	if (dev == 0) {
1932 		for (i = 0; i < sc->dacn; i++) {
1933 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1934 		}
1935 	}
1936 	else {
1937 		/* set volume value for hardware */
1938 		if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1939 			sc->left[hwch] = ENVY24HT_VOL_MUTE;
1940 		if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1941 			sc->right[hwch] = ENVY24HT_VOL_MUTE;
1942 
1943 		/* set volume for record channel and running play channel */
1944 		if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1945 			envy24ht_setvolume(sc, hwch);
1946 	}
1947 	snd_mtxunlock(sc->lock);
1948 
1949 	return right << 8 | left;
1950 }
1951 
1952 static u_int32_t
1953 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1954 {
1955 	struct sc_info *sc = mix_getdevinfo(m);
1956 	int ch = envy24ht_mixmap[src];
1957 #if(0)
1958 	device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1959 #endif
1960 
1961 	if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1962 		sc->src = ch;
1963 	return src;
1964 }
1965 
1966 static kobj_method_t envy24htmixer_methods[] = {
1967 	KOBJMETHOD(mixer_init,		envy24htmixer_init),
1968 	KOBJMETHOD(mixer_reinit,	envy24htmixer_reinit),
1969 	KOBJMETHOD(mixer_uninit,	envy24htmixer_uninit),
1970 	KOBJMETHOD(mixer_set,		envy24htmixer_set),
1971 	KOBJMETHOD(mixer_setrecsrc,	envy24htmixer_setrecsrc),
1972 	KOBJMETHOD_END
1973 };
1974 MIXER_DECLARE(envy24htmixer);
1975 
1976 /* -------------------------------------------------------------------- */
1977 
1978 /* The interrupt handler */
1979 static void
1980 envy24ht_intr(void *p)
1981 {
1982 	struct sc_info *sc = (struct sc_info *)p;
1983 	struct sc_chinfo *ch;
1984 	u_int32_t ptr, dsize, feed;
1985 	int i;
1986 
1987 #if(0)
1988 	device_printf(sc->dev, "envy24ht_intr()\n");
1989 #endif
1990 	snd_mtxlock(sc->lock);
1991 	if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1992 #if(0)
1993 		device_printf(sc->dev, "envy24ht_intr(): play\n");
1994 #endif
1995 		dsize = sc->psize / 4;
1996 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1997 #if(0)
1998 		device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1999 #endif
2000 		ptr -= ptr % sc->blk[0];
2001 		feed = (ptr + dsize - sc->intr[0]) % dsize;
2002 #if(0)
2003 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2004 #endif
2005 		for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
2006 			ch = &sc->chan[i];
2007 #if(0)
2008 			if (ch->run)
2009 				device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
2010 #endif
2011 			if (ch->run && ch->blk <= feed) {
2012 				snd_mtxunlock(sc->lock);
2013 				chn_intr(ch->channel);
2014 				snd_mtxlock(sc->lock);
2015 			}
2016 		}
2017 		sc->intr[0] = ptr;
2018 		envy24ht_updintr(sc, PCMDIR_PLAY);
2019 	}
2020 	if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2021 #if(0)
2022 		device_printf(sc->dev, "envy24ht_intr(): rec\n");
2023 #endif
2024 		dsize = sc->rsize / 4;
2025 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2026 		ptr -= ptr % sc->blk[1];
2027 		feed = (ptr + dsize - sc->intr[1]) % dsize;
2028 		for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2029 			ch = &sc->chan[i];
2030 			if (ch->run && ch->blk <= feed) {
2031 				snd_mtxunlock(sc->lock);
2032 				chn_intr(ch->channel);
2033 				snd_mtxlock(sc->lock);
2034 			}
2035 		}
2036 		sc->intr[1] = ptr;
2037 		envy24ht_updintr(sc, PCMDIR_REC);
2038 	}
2039 	snd_mtxunlock(sc->lock);
2040 
2041 	return;
2042 }
2043 
2044 /*
2045  * Probe and attach the card
2046  */
2047 
2048 static int
2049 envy24ht_pci_probe(device_t dev)
2050 {
2051 	u_int16_t sv, sd;
2052 	int i;
2053 
2054 #if(0)
2055 	printf("envy24ht_pci_probe()\n");
2056 #endif
2057 	if (pci_get_device(dev) == PCID_ENVY24HT &&
2058 	    pci_get_vendor(dev) == PCIV_ENVY24) {
2059 		sv = pci_get_subvendor(dev);
2060 		sd = pci_get_subdevice(dev);
2061 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2062 			if (cfg_table[i].subvendor == sv &&
2063 			    cfg_table[i].subdevice == sd) {
2064 				break;
2065 			}
2066 		}
2067 		device_set_desc(dev, cfg_table[i].name);
2068 #if(0)
2069 		printf("envy24ht_pci_probe(): return 0\n");
2070 #endif
2071 		return 0;
2072 	}
2073 	else {
2074 #if(0)
2075 		printf("envy24ht_pci_probe(): return ENXIO\n");
2076 #endif
2077 		return ENXIO;
2078 	}
2079 }
2080 
2081 static void
2082 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2083 {
2084 	struct sc_info *sc = arg;
2085 
2086 	sc->paddr = segs->ds_addr;
2087 #if(0)
2088 	device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2089 	if (bootverbose) {
2090 		printf("envy24ht(play): setmap %lx, %lx; ",
2091 		    (unsigned long)segs->ds_addr,
2092 		    (unsigned long)segs->ds_len);
2093 	}
2094 #endif
2095 	envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
2096 	envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2097 }
2098 
2099 static void
2100 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2101 {
2102 	struct sc_info *sc = arg;
2103 
2104 	sc->raddr = segs->ds_addr;
2105 #if(0)
2106 	device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2107 	if (bootverbose) {
2108 		printf("envy24ht(record): setmap %lx, %lx; ",
2109 		    (unsigned long)segs->ds_addr,
2110 		    (unsigned long)segs->ds_len);
2111 	}
2112 #endif
2113 	envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
2114 	envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
2115 }
2116 
2117 static void
2118 envy24ht_dmafree(struct sc_info *sc)
2119 {
2120 #if(0)
2121 	device_printf(sc->dev, "envy24ht_dmafree():");
2122 	printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2123 	printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2124 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2125 	else printf(" sc->rbuf(null)");
2126 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2127 	else printf(" sc->pbuf(null)\n");
2128 #endif
2129 #if(0)
2130 	if (sc->raddr)
2131 		bus_dmamap_unload(sc->dmat, sc->rmap);
2132 	if (sc->paddr)
2133 		bus_dmamap_unload(sc->dmat, sc->pmap);
2134 	if (sc->rbuf)
2135 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2136 	if (sc->pbuf)
2137 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2138 #else
2139 	bus_dmamap_unload(sc->dmat, sc->rmap);
2140 	bus_dmamap_unload(sc->dmat, sc->pmap);
2141 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2142 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2143 #endif
2144 
2145 	sc->raddr = sc->paddr = 0;
2146 	sc->pbuf = NULL;
2147 	sc->rbuf = NULL;
2148 
2149 	return;
2150 }
2151 
2152 static int
2153 envy24ht_dmainit(struct sc_info *sc)
2154 {
2155 
2156 #if(0)
2157 	device_printf(sc->dev, "envy24ht_dmainit()\n");
2158 #endif
2159 	/* init values */
2160 	sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2161 	sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2162 	sc->pbuf = NULL;
2163 	sc->rbuf = NULL;
2164 	sc->paddr = sc->raddr = 0;
2165 	sc->blk[0] = sc->blk[1] = 0;
2166 
2167 	/* allocate DMA buffer */
2168 #if(0)
2169 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2170 #endif
2171 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2172 		goto bad;
2173 #if(0)
2174 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2175 #endif
2176 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2177 		goto bad;
2178 #if(0)
2179 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2180 #endif
2181 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
2182 		goto bad;
2183 #if(0)
2184 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2185 #endif
2186 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
2187 		goto bad;
2188 	bzero(sc->pbuf, sc->psize);
2189 	bzero(sc->rbuf, sc->rsize);
2190 
2191 	return 0;
2192  bad:
2193 	envy24ht_dmafree(sc);
2194 	return ENOSPC;
2195 }
2196 
2197 static void
2198 envy24ht_putcfg(struct sc_info *sc)
2199 {
2200 	device_printf(sc->dev, "system configuration\n");
2201 	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2202 	    sc->cfg->subvendor, sc->cfg->subdevice);
2203 	printf("  XIN2 Clock Source: ");
2204 	switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2205 	case 0x00:
2206 		printf("24.576MHz(96kHz*256)\n");
2207 		break;
2208 	case 0x40:
2209 		printf("49.152MHz(192kHz*256)\n");
2210 		break;
2211 	case 0x80:
2212 		printf("reserved\n");
2213 		break;
2214 	default:
2215 		printf("illegal system setting\n");
2216 	}
2217 	printf("  MPU-401 UART(s) #: ");
2218 	if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2219 		printf("1\n");
2220 	else
2221 		printf("not implemented\n");
2222         switch (sc->adcn) {
2223         case 0x01:
2224 	case 0x02:
2225                 printf("  ADC #: ");
2226                 printf("%d\n", sc->adcn);
2227                 break;
2228         case 0x03:
2229                 printf("  ADC #: ");
2230                 printf("%d", 1);
2231                 printf(" and SPDIF receiver connected\n");
2232                 break;
2233         default:
2234                 printf("  no physical inputs\n");
2235         }
2236 	printf("  DAC #: ");
2237 	printf("%d\n", sc->dacn);
2238 	printf("  Multi-track converter type: ");
2239 	if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2240 		printf("AC'97(SDATA_OUT:");
2241 		if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2242 			printf("packed");
2243 		else
2244 			printf("split");
2245 		printf(")\n");
2246 	}
2247 	else {
2248 		printf("I2S(");
2249 		if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2250 			printf("with volume, ");
2251                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2252                         printf("192KHz support, ");
2253                 else
2254                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2255                         printf("192KHz support, ");
2256                 else
2257                         printf("48KHz support, ");
2258 		switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2259 		case ENVY24HT_CCSM_I2S_16BIT:
2260 			printf("16bit resolution, ");
2261 			break;
2262 		case ENVY24HT_CCSM_I2S_18BIT:
2263 			printf("18bit resolution, ");
2264 			break;
2265 		case ENVY24HT_CCSM_I2S_20BIT:
2266 			printf("20bit resolution, ");
2267 			break;
2268 		case ENVY24HT_CCSM_I2S_24BIT:
2269 			printf("24bit resolution, ");
2270 			break;
2271 		}
2272 		printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2273 	}
2274 	printf("  S/PDIF(IN/OUT): ");
2275 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2276 		printf("1/");
2277 	else
2278 		printf("0/");
2279 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2280 		printf("1 ");
2281 	else
2282 		printf("0 ");
2283 	if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2284 		printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2285 	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2286 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2287 }
2288 
2289 static int
2290 envy24ht_init(struct sc_info *sc)
2291 {
2292 	u_int32_t data;
2293 #if(0)
2294 	int rtn;
2295 #endif
2296 	int i;
2297 	u_int32_t sv, sd;
2298 
2299 
2300 #if(0)
2301 	device_printf(sc->dev, "envy24ht_init()\n");
2302 #endif
2303 
2304 	/* reset chip */
2305 #if 0
2306 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2307 	DELAY(200);
2308 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2309 	DELAY(200);
2310 
2311 	/* legacy hardware disable */
2312 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2313 	data |= PCIM_LAC_DISABLE;
2314 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2315 #endif
2316 
2317 	/* check system configuration */
2318 	sc->cfg = NULL;
2319 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2320 		/* 1st: search configuration from table */
2321 		sv = pci_get_subvendor(sc->dev);
2322 		sd = pci_get_subdevice(sc->dev);
2323 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2324 #if(0)
2325 			device_printf(sc->dev, "Set configuration from table\n");
2326 #endif
2327 			sc->cfg = &cfg_table[i];
2328 			break;
2329 		}
2330 	}
2331 	if (sc->cfg == NULL) {
2332 		/* 2nd: read configuration from table */
2333 		sc->cfg = envy24ht_rom2cfg(sc);
2334 	}
2335 	sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2336 	sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2337 
2338 	if (1 /* bootverbose */) {
2339 		envy24ht_putcfg(sc);
2340 	}
2341 
2342 	/* set system configuration */
2343 	envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2344 	envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2345 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2346 	envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2347 	envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2348 	envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2349 	envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2350 
2351 	if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2352 		envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2353 		envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2354 		envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2355 	}
2356 
2357 	for (i = 0; i < sc->adcn; i++) {
2358 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2359 		sc->cfg->codec->init(sc->adc[i]);
2360 	}
2361 	for (i = 0; i < sc->dacn; i++) {
2362 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2363 		sc->cfg->codec->init(sc->dac[i]);
2364 	}
2365 
2366 	/* initialize DMA buffer */
2367 #if(0)
2368 	device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2369 #endif
2370 	if (envy24ht_dmainit(sc))
2371 		return ENOSPC;
2372 
2373 	/* initialize status */
2374 	sc->run[0] = sc->run[1] = 0;
2375 	sc->intr[0] = sc->intr[1] = 0;
2376 	sc->speed = 0;
2377 	sc->caps[0].fmtlist = envy24ht_playfmt;
2378 	sc->caps[1].fmtlist = envy24ht_recfmt;
2379 
2380 	/* set channel router */
2381 #if 0
2382 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2383 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2384 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2385 #endif
2386 
2387 	/* set macro interrupt mask */
2388 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2389 	envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2390 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2391 #if(0)
2392 	device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2393 #endif
2394 
2395 	return 0;
2396 }
2397 
2398 static int
2399 envy24ht_alloc_resource(struct sc_info *sc)
2400 {
2401 	/* allocate I/O port resource */
2402 	sc->csid = PCIR_CCS;
2403 	sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2404 	    &sc->csid, RF_ACTIVE);
2405 	sc->mtid = ENVY24HT_PCIR_MT;
2406 	sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2407 	    &sc->mtid, RF_ACTIVE);
2408 	if (!sc->cs || !sc->mt) {
2409 		device_printf(sc->dev, "unable to map IO port space\n");
2410 		return ENXIO;
2411 	}
2412 	sc->cst = rman_get_bustag(sc->cs);
2413 	sc->csh = rman_get_bushandle(sc->cs);
2414 	sc->mtt = rman_get_bustag(sc->mt);
2415 	sc->mth = rman_get_bushandle(sc->mt);
2416 #if(0)
2417 	device_printf(sc->dev,
2418 	    "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2419 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2420 	    pci_read_config(sc->dev, PCIR_MT, 4));
2421 #endif
2422 
2423 	/* allocate interrupt resource */
2424 	sc->irqid = 0;
2425 	sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
2426 				 RF_ACTIVE | RF_SHAREABLE);
2427 	if (!sc->irq ||
2428 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
2429 		device_printf(sc->dev, "unable to map interrupt\n");
2430 		return ENXIO;
2431 	}
2432 
2433 	/* allocate DMA resource */
2434 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2435 	    /*alignment*/4,
2436 	    /*boundary*/0,
2437 	    /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
2438 	    /*highaddr*/BUS_SPACE_MAXADDR,
2439 	    /*filter*/NULL, /*filterarg*/NULL,
2440 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2441 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2442 	    /*flags*/0, /*lockfunc*/NULL,
2443 	    /*lockarg*/NULL, &sc->dmat) != 0) {
2444 		device_printf(sc->dev, "unable to create dma tag\n");
2445 		return ENXIO;
2446 	}
2447 
2448 	return 0;
2449 }
2450 
2451 static int
2452 envy24ht_pci_attach(device_t dev)
2453 {
2454 	struct sc_info 		*sc;
2455 	char 			status[SND_STATUSLEN];
2456 	int			err = 0;
2457 	int			i;
2458 
2459 #if(0)
2460 	device_printf(dev, "envy24ht_pci_attach()\n");
2461 #endif
2462 	/* get sc_info data area */
2463 	if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2464 		device_printf(dev, "cannot allocate softc\n");
2465 		return ENXIO;
2466 	}
2467 
2468 	bzero(sc, sizeof(*sc));
2469 	sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2470 	    "snd_envy24ht softc");
2471 	sc->dev = dev;
2472 
2473 	/* initialize PCI interface */
2474 	pci_enable_busmaster(dev);
2475 
2476 	/* allocate resources */
2477 	err = envy24ht_alloc_resource(sc);
2478 	if (err) {
2479 		device_printf(dev, "unable to allocate system resources\n");
2480 		goto bad;
2481 	}
2482 
2483 	/* initialize card */
2484 	err = envy24ht_init(sc);
2485 	if (err) {
2486 		device_printf(dev, "unable to initialize the card\n");
2487 		goto bad;
2488 	}
2489 
2490 	/* set multi track mixer */
2491 	mixer_init(dev, &envy24htmixer_class, sc);
2492 
2493 	/* set channel information */
2494 	/* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2495 	err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2496 	if (err)
2497 		goto bad;
2498 	sc->chnum = 0;
2499 	/* for (i = 0; i < 5; i++) { */
2500 		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2501 		sc->chnum++;
2502 	/* } */
2503 	for (i = 0; i < 2 + sc->adcn; i++) {
2504 		pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2505 		sc->chnum++;
2506 	}
2507 
2508 	/* set status iformation */
2509 	snprintf(status, SND_STATUSLEN,
2510 	    "at io 0x%jx:%jd,0x%jx:%jd irq %jd",
2511 	    rman_get_start(sc->cs),
2512 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2513 	    rman_get_start(sc->mt),
2514 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2515 	    rman_get_start(sc->irq));
2516 	pcm_setstatus(dev, status);
2517 
2518 	return 0;
2519 
2520 bad:
2521 	if (sc->ih)
2522 		bus_teardown_intr(dev, sc->irq, sc->ih);
2523 	if (sc->irq)
2524 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2525 	envy24ht_dmafree(sc);
2526 	if (sc->dmat)
2527 		bus_dma_tag_destroy(sc->dmat);
2528         if (sc->cfg->codec->destroy != NULL) {
2529                 for (i = 0; i < sc->adcn; i++)
2530                         sc->cfg->codec->destroy(sc->adc[i]);
2531                 for (i = 0; i < sc->dacn; i++)
2532                         sc->cfg->codec->destroy(sc->dac[i]);
2533         }
2534 	envy24ht_cfgfree(sc->cfg);
2535 	if (sc->cs)
2536 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2537 	if (sc->mt)
2538 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2539 	if (sc->lock)
2540 		snd_mtxfree(sc->lock);
2541 	free(sc, M_ENVY24HT);
2542 	return err;
2543 }
2544 
2545 static int
2546 envy24ht_pci_detach(device_t dev)
2547 {
2548 	struct sc_info *sc;
2549 	int r;
2550 	int i;
2551 
2552 #if(0)
2553 	device_printf(dev, "envy24ht_pci_detach()\n");
2554 #endif
2555 	sc = pcm_getdevinfo(dev);
2556 	if (sc == NULL)
2557 		return 0;
2558 	r = pcm_unregister(dev);
2559 	if (r)
2560 		return r;
2561 
2562 	envy24ht_dmafree(sc);
2563 	if (sc->cfg->codec->destroy != NULL) {
2564 		for (i = 0; i < sc->adcn; i++)
2565 			sc->cfg->codec->destroy(sc->adc[i]);
2566 		for (i = 0; i < sc->dacn; i++)
2567 			sc->cfg->codec->destroy(sc->dac[i]);
2568 	}
2569 	envy24ht_cfgfree(sc->cfg);
2570 	bus_dma_tag_destroy(sc->dmat);
2571 	bus_teardown_intr(dev, sc->irq, sc->ih);
2572 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2573 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2574 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2575 	snd_mtxfree(sc->lock);
2576 	free(sc, M_ENVY24HT);
2577 	return 0;
2578 }
2579 
2580 static device_method_t envy24ht_methods[] = {
2581 	/* Device interface */
2582 	DEVMETHOD(device_probe,		envy24ht_pci_probe),
2583 	DEVMETHOD(device_attach,	envy24ht_pci_attach),
2584 	DEVMETHOD(device_detach,	envy24ht_pci_detach),
2585 	{ 0, 0 }
2586 };
2587 
2588 static driver_t envy24ht_driver = {
2589 	"pcm",
2590 	envy24ht_methods,
2591 	PCM_SOFTC_SIZE,
2592 };
2593 
2594 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2595 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2596 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2597 MODULE_VERSION(snd_envy24ht, 1);
2598