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