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