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