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