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