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