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