xref: /freebsd/sys/dev/sound/pci/envy24ht.c (revision b3aaa0cc21c63d388230c7ef2a80abd631ff20d5)
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 #if 0
1681 	int i;
1682 
1683 	device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
1684 #endif
1685 	snd_mtxlock(sc->lock);
1686 	if (ch->dir == PCMDIR_PLAY)
1687 		slot = 0;
1688 	else
1689 		slot = 1;
1690 	switch (go) {
1691 	case PCMTRIG_START:
1692 #if(0)
1693 		device_printf(sc->dev, "envy24htchan_trigger(): start\n");
1694 #endif
1695 		/* check or set channel speed */
1696 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1697 			sc->speed = envy24ht_setspeed(sc, ch->speed);
1698 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1699 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1700 		}
1701 		else if (ch->speed != 0 && ch->speed != sc->speed)
1702 			return -1;
1703 		if (ch->speed == 0)
1704 			ch->channel->speed = sc->speed;
1705 		/* start or enable channel */
1706 		sc->run[slot]++;
1707 		if (sc->run[slot] == 1) {
1708 			/* first channel */
1709 			ch->offset = 0;
1710 			sc->blk[slot] = ch->blk;
1711 		}
1712 		else {
1713 			ptr = envy24ht_gethwptr(sc, ch->dir);
1714 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1715 			    (ch->size / 4)) * 4 / ch->unit;
1716 			if (ch->blk < sc->blk[slot])
1717 				sc->blk[slot] = ch->blk;
1718 		}
1719 		if (ch->dir == PCMDIR_PLAY) {
1720 			ch->emldma(ch);
1721 			envy24ht_setvolume(sc, ch->num);
1722 		}
1723 		envy24ht_updintr(sc, ch->dir);
1724 		if (sc->run[slot] == 1)
1725 			envy24ht_start(sc, ch->dir);
1726 		ch->run = 1;
1727 		break;
1728 	case PCMTRIG_EMLDMAWR:
1729 #if(0)
1730 		device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
1731 #endif
1732 		if (ch->run != 1)
1733 			return -1;
1734 		ch->emldma(ch);
1735 		break;
1736 	case PCMTRIG_EMLDMARD:
1737 #if(0)
1738 		device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
1739 #endif
1740 		if (ch->run != 1)
1741 			return -1;
1742 		ch->emldma(ch);
1743 		break;
1744 	case PCMTRIG_ABORT:
1745 		if (ch->run) {
1746 #if(0)
1747 		device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
1748 #endif
1749 		ch->run = 0;
1750 		sc->run[slot]--;
1751 		if (ch->dir == PCMDIR_PLAY)
1752 			envy24ht_mutevolume(sc, ch->num);
1753 		if (sc->run[slot] == 0) {
1754 			envy24ht_stop(sc, ch->dir);
1755 			sc->intr[slot] = 0;
1756 		}
1757 /*		else if (ch->blk == sc->blk[slot]) {
1758 			sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
1759 			for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
1760 				if (sc->chan[i].dir == ch->dir &&
1761 				    sc->chan[i].run == 1 &&
1762 				    sc->chan[i].blk < sc->blk[slot])
1763 					sc->blk[slot] = sc->chan[i].blk;
1764 			}
1765 			if (ch->blk != sc->blk[slot])
1766 				envy24ht_updintr(sc, ch->dir);
1767 		}*/
1768 		}
1769 		break;
1770 	}
1771 	snd_mtxunlock(sc->lock);
1772 
1773 	return 0;
1774 }
1775 
1776 static int
1777 envy24htchan_getptr(kobj_t obj, void *data)
1778 {
1779 	struct sc_chinfo *ch = data;
1780 	struct sc_info *sc = ch->parent;
1781 	u_int32_t ptr;
1782 	int rtn;
1783 
1784 #if(0)
1785 	device_printf(sc->dev, "envy24htchan_getptr()\n");
1786 #endif
1787 	snd_mtxlock(sc->lock);
1788 	ptr = envy24ht_gethwptr(sc, ch->dir);
1789 	rtn = ptr * ch->unit;
1790 	snd_mtxunlock(sc->lock);
1791 
1792 #if(0)
1793 	device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
1794 	    rtn);
1795 #endif
1796 	return rtn;
1797 }
1798 
1799 static struct pcmchan_caps *
1800 envy24htchan_getcaps(kobj_t obj, void *data)
1801 {
1802 	struct sc_chinfo *ch = data;
1803 	struct sc_info *sc = ch->parent;
1804 	struct pcmchan_caps *rtn;
1805 
1806 #if(0)
1807 	device_printf(sc->dev, "envy24htchan_getcaps()\n");
1808 #endif
1809 	snd_mtxlock(sc->lock);
1810 	if (ch->dir == PCMDIR_PLAY) {
1811 		if (sc->run[0] == 0)
1812 			rtn = &envy24ht_playcaps;
1813 		else
1814 			rtn = &sc->caps[0];
1815 	}
1816 	else {
1817 		if (sc->run[1] == 0)
1818 			rtn = &envy24ht_reccaps;
1819 		else
1820 			rtn = &sc->caps[1];
1821 	}
1822 	snd_mtxunlock(sc->lock);
1823 
1824 	return rtn;
1825 }
1826 
1827 static kobj_method_t envy24htchan_methods[] = {
1828 	KOBJMETHOD(channel_init,		envy24htchan_init),
1829 	KOBJMETHOD(channel_free,		envy24htchan_free),
1830 	KOBJMETHOD(channel_setformat,		envy24htchan_setformat),
1831 	KOBJMETHOD(channel_setspeed,		envy24htchan_setspeed),
1832 	KOBJMETHOD(channel_setblocksize,	envy24htchan_setblocksize),
1833 	KOBJMETHOD(channel_trigger,		envy24htchan_trigger),
1834 	KOBJMETHOD(channel_getptr,		envy24htchan_getptr),
1835 	KOBJMETHOD(channel_getcaps,		envy24htchan_getcaps),
1836 	{ 0, 0 }
1837 };
1838 CHANNEL_DECLARE(envy24htchan);
1839 
1840 /* -------------------------------------------------------------------- */
1841 
1842 /* mixer interface */
1843 
1844 static int
1845 envy24htmixer_init(struct snd_mixer *m)
1846 {
1847 	struct sc_info *sc = mix_getdevinfo(m);
1848 
1849 #if(0)
1850 	device_printf(sc->dev, "envy24htmixer_init()\n");
1851 #endif
1852 	if (sc == NULL)
1853 		return -1;
1854 
1855 	/* set volume control rate */
1856 	snd_mtxlock(sc->lock);
1857 #if 0
1858 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1859 #endif
1860 
1861 	pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
1862 
1863 	mix_setdevs(m, ENVY24HT_MIX_MASK);
1864 	mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
1865 
1866 	snd_mtxunlock(sc->lock);
1867 
1868 	return 0;
1869 }
1870 
1871 static int
1872 envy24htmixer_reinit(struct snd_mixer *m)
1873 {
1874 	struct sc_info *sc = mix_getdevinfo(m);
1875 
1876 	if (sc == NULL)
1877 		return -1;
1878 #if(0)
1879 	device_printf(sc->dev, "envy24htmixer_reinit()\n");
1880 #endif
1881 
1882 	return 0;
1883 }
1884 
1885 static int
1886 envy24htmixer_uninit(struct snd_mixer *m)
1887 {
1888 	struct sc_info *sc = mix_getdevinfo(m);
1889 
1890 	if (sc == NULL)
1891 		return -1;
1892 #if(0)
1893 	device_printf(sc->dev, "envy24htmixer_uninit()\n");
1894 #endif
1895 
1896 	return 0;
1897 }
1898 
1899 static int
1900 envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1901 {
1902 	struct sc_info *sc = mix_getdevinfo(m);
1903 	int ch = envy24ht_mixmap[dev];
1904 	int hwch;
1905 	int i;
1906 
1907 	if (sc == NULL)
1908 		return -1;
1909 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1910 		return -1;
1911 	if (dev != 0 && ch == -1)
1912 		return -1;
1913 	hwch = envy24ht_chanmap[ch];
1914 #if(0)
1915 	device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
1916 	    dev, left, right);
1917 #endif
1918 
1919 	snd_mtxlock(sc->lock);
1920 	if (dev == 0) {
1921 		for (i = 0; i < sc->dacn; i++) {
1922 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1923 		}
1924 	}
1925 	else {
1926 		/* set volume value for hardware */
1927 		if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
1928 			sc->left[hwch] = ENVY24HT_VOL_MUTE;
1929 		if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
1930 			sc->right[hwch] = ENVY24HT_VOL_MUTE;
1931 
1932 		/* set volume for record channel and running play channel */
1933 		if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1934 			envy24ht_setvolume(sc, hwch);
1935 	}
1936 	snd_mtxunlock(sc->lock);
1937 
1938 	return right << 8 | left;
1939 }
1940 
1941 static u_int32_t
1942 envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1943 {
1944 	struct sc_info *sc = mix_getdevinfo(m);
1945 	int ch = envy24ht_mixmap[src];
1946 #if(0)
1947 	device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
1948 #endif
1949 
1950 	if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
1951 		sc->src = ch;
1952 	return src;
1953 }
1954 
1955 static kobj_method_t envy24htmixer_methods[] = {
1956 	KOBJMETHOD(mixer_init,		envy24htmixer_init),
1957 	KOBJMETHOD(mixer_reinit,	envy24htmixer_reinit),
1958 	KOBJMETHOD(mixer_uninit,	envy24htmixer_uninit),
1959 	KOBJMETHOD(mixer_set,		envy24htmixer_set),
1960 	KOBJMETHOD(mixer_setrecsrc,	envy24htmixer_setrecsrc),
1961 	{ 0, 0 }
1962 };
1963 MIXER_DECLARE(envy24htmixer);
1964 
1965 /* -------------------------------------------------------------------- */
1966 
1967 /* The interrupt handler */
1968 static void
1969 envy24ht_intr(void *p)
1970 {
1971 	struct sc_info *sc = (struct sc_info *)p;
1972 	struct sc_chinfo *ch;
1973 	u_int32_t ptr, dsize, feed;
1974 	int i;
1975 
1976 #if(0)
1977 	device_printf(sc->dev, "envy24ht_intr()\n");
1978 #endif
1979 	snd_mtxlock(sc->lock);
1980 	if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
1981 #if(0)
1982 		device_printf(sc->dev, "envy24ht_intr(): play\n");
1983 #endif
1984 		dsize = sc->psize / 4;
1985 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
1986 #if(0)
1987 		device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
1988 #endif
1989 		ptr -= ptr % sc->blk[0];
1990 		feed = (ptr + dsize - sc->intr[0]) % dsize;
1991 #if(0)
1992 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1993 #endif
1994 		for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
1995 			ch = &sc->chan[i];
1996 #if(0)
1997 			if (ch->run)
1998 				device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
1999 #endif
2000 			if (ch->run && ch->blk <= feed) {
2001 				snd_mtxunlock(sc->lock);
2002 				chn_intr(ch->channel);
2003 				snd_mtxlock(sc->lock);
2004 			}
2005 		}
2006 		sc->intr[0] = ptr;
2007 		envy24ht_updintr(sc, PCMDIR_PLAY);
2008 	}
2009 	if (envy24ht_checkintr(sc, PCMDIR_REC)) {
2010 #if(0)
2011 		device_printf(sc->dev, "envy24ht_intr(): rec\n");
2012 #endif
2013 		dsize = sc->rsize / 4;
2014 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
2015 		ptr -= ptr % sc->blk[1];
2016 		feed = (ptr + dsize - sc->intr[1]) % dsize;
2017 		for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
2018 			ch = &sc->chan[i];
2019 			if (ch->run && ch->blk <= feed) {
2020 				snd_mtxunlock(sc->lock);
2021 				chn_intr(ch->channel);
2022 				snd_mtxlock(sc->lock);
2023 			}
2024 		}
2025 		sc->intr[1] = ptr;
2026 		envy24ht_updintr(sc, PCMDIR_REC);
2027 	}
2028 	snd_mtxunlock(sc->lock);
2029 
2030 	return;
2031 }
2032 
2033 /*
2034  * Probe and attach the card
2035  */
2036 
2037 static int
2038 envy24ht_pci_probe(device_t dev)
2039 {
2040 	u_int16_t sv, sd;
2041 	int i;
2042 
2043 #if(0)
2044 	printf("envy24ht_pci_probe()\n");
2045 #endif
2046 	if (pci_get_device(dev) == PCID_ENVY24HT &&
2047 	    pci_get_vendor(dev) == PCIV_ENVY24) {
2048 		sv = pci_get_subvendor(dev);
2049 		sd = pci_get_subdevice(dev);
2050 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2051 			if (cfg_table[i].subvendor == sv &&
2052 			    cfg_table[i].subdevice == sd) {
2053 				break;
2054 			}
2055 		}
2056 		device_set_desc(dev, cfg_table[i].name);
2057 #if(0)
2058 		printf("envy24ht_pci_probe(): return 0\n");
2059 #endif
2060 		return 0;
2061 	}
2062 	else {
2063 #if(0)
2064 		printf("envy24ht_pci_probe(): return ENXIO\n");
2065 #endif
2066 		return ENXIO;
2067 	}
2068 }
2069 
2070 static void
2071 envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2072 {
2073 	/* struct sc_info *sc = (struct sc_info *)arg; */
2074 
2075 #if(0)
2076 	device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
2077 	if (bootverbose) {
2078 		printf("envy24ht(play): setmap %lx, %lx; ",
2079 		    (unsigned long)segs->ds_addr,
2080 		    (unsigned long)segs->ds_len);
2081 		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2082 	}
2083 #endif
2084 }
2085 
2086 static void
2087 envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2088 {
2089 	/* struct sc_info *sc = (struct sc_info *)arg; */
2090 
2091 #if(0)
2092 	device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2093 	if (bootverbose) {
2094 		printf("envy24ht(record): setmap %lx, %lx; ",
2095 		    (unsigned long)segs->ds_addr,
2096 		    (unsigned long)segs->ds_len);
2097 		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2098 	}
2099 #endif
2100 }
2101 
2102 static void
2103 envy24ht_dmafree(struct sc_info *sc)
2104 {
2105 #if(0)
2106 	device_printf(sc->dev, "envy24ht_dmafree():");
2107 	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2108 	else printf(" sc->rmap(null)");
2109 	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2110 	else printf(" sc->pmap(null)");
2111 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2112 	else printf(" sc->rbuf(null)");
2113 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2114 	else printf(" sc->pbuf(null)\n");
2115 #endif
2116 #if(0)
2117 	if (sc->rmap)
2118 		bus_dmamap_unload(sc->dmat, sc->rmap);
2119 	if (sc->pmap)
2120 		bus_dmamap_unload(sc->dmat, sc->pmap);
2121 	if (sc->rbuf)
2122 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2123 	if (sc->pbuf)
2124 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2125 #else
2126 	bus_dmamap_unload(sc->dmat, sc->rmap);
2127 	bus_dmamap_unload(sc->dmat, sc->pmap);
2128 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2129 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2130 #endif
2131 
2132 	sc->rmap = sc->pmap = NULL;
2133 	sc->pbuf = NULL;
2134 	sc->rbuf = NULL;
2135 
2136 	return;
2137 }
2138 
2139 static int
2140 envy24ht_dmainit(struct sc_info *sc)
2141 {
2142 	u_int32_t addr;
2143 
2144 #if(0)
2145 	device_printf(sc->dev, "envy24ht_dmainit()\n");
2146 #endif
2147 	/* init values */
2148 	sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2149 	sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2150 	sc->pbuf = NULL;
2151 	sc->rbuf = NULL;
2152 	sc->pmap = sc->rmap = NULL;
2153 	sc->blk[0] = sc->blk[1] = 0;
2154 
2155 	/* allocate DMA buffer */
2156 #if(0)
2157 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2158 #endif
2159 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2160 		goto bad;
2161 #if(0)
2162 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2163 #endif
2164 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2165 		goto bad;
2166 #if(0)
2167 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2168 #endif
2169 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2170 		goto bad;
2171 #if(0)
2172 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2173 #endif
2174 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2175 		goto bad;
2176 	bzero(sc->pbuf, sc->psize);
2177 	bzero(sc->rbuf, sc->rsize);
2178 
2179 	/* set values to register */
2180 	addr = vtophys(sc->pbuf);
2181 #if(0)
2182 	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2183 #endif
2184 	envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2185 #if(0)
2186 	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2187 	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2188 #endif
2189 	envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2190 #if(0)
2191 	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2192 #endif
2193 	addr = vtophys(sc->rbuf);
2194 	envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2195 	envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2196 
2197 	return 0;
2198  bad:
2199 	envy24ht_dmafree(sc);
2200 	return ENOSPC;
2201 }
2202 
2203 static void
2204 envy24ht_putcfg(struct sc_info *sc)
2205 {
2206 	device_printf(sc->dev, "system configuration\n");
2207 	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2208 	    sc->cfg->subvendor, sc->cfg->subdevice);
2209 	printf("  XIN2 Clock Source: ");
2210 	switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2211 	case 0x00:
2212 		printf("24.576MHz(96kHz*256)\n");
2213 		break;
2214 	case 0x40:
2215 		printf("49.152MHz(192kHz*256)\n");
2216 		break;
2217 	case 0x80:
2218 		printf("reserved\n");
2219 		break;
2220 	default:
2221 		printf("illeagal system setting\n");
2222 	}
2223 	printf("  MPU-401 UART(s) #: ");
2224 	if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2225 		printf("1\n");
2226 	else
2227 		printf("not implemented\n");
2228         switch (sc->adcn) {
2229         case 0x01 || 0x02:
2230                 printf("  ADC #: ");
2231                 printf("%d\n", sc->adcn);
2232                 break;
2233         case 0x03:
2234                 printf("  ADC #: ");
2235                 printf("%d", 1);
2236                 printf(" and SPDIF receiver connected\n");
2237                 break;
2238         default:
2239                 printf("  no physical inputs\n");
2240         }
2241 	printf("  DAC #: ");
2242 	printf("%d\n", sc->dacn);
2243 	printf("  Multi-track converter type: ");
2244 	if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2245 		printf("AC'97(SDATA_OUT:");
2246 		if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2247 			printf("packed");
2248 		else
2249 			printf("split");
2250 		printf(")\n");
2251 	}
2252 	else {
2253 		printf("I2S(");
2254 		if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2255 			printf("with volume, ");
2256                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2257                         printf("192KHz support, ");
2258                 else
2259                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2260                         printf("192KHz support, ");
2261                 else
2262                         printf("48KHz support, ");
2263 		switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2264 		case ENVY24HT_CCSM_I2S_16BIT:
2265 			printf("16bit resolution, ");
2266 			break;
2267 		case ENVY24HT_CCSM_I2S_18BIT:
2268 			printf("18bit resolution, ");
2269 			break;
2270 		case ENVY24HT_CCSM_I2S_20BIT:
2271 			printf("20bit resolution, ");
2272 			break;
2273 		case ENVY24HT_CCSM_I2S_24BIT:
2274 			printf("24bit resolution, ");
2275 			break;
2276 		}
2277 		printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2278 	}
2279 	printf("  S/PDIF(IN/OUT): ");
2280 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2281 		printf("1/");
2282 	else
2283 		printf("0/");
2284 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2285 		printf("1 ");
2286 	else
2287 		printf("0 ");
2288 	if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2289 		printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2290 	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2291 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2292 }
2293 
2294 static int
2295 envy24ht_init(struct sc_info *sc)
2296 {
2297 	u_int32_t data;
2298 #if(0)
2299 	int rtn;
2300 #endif
2301 	int i;
2302 	u_int32_t sv, sd;
2303 
2304 
2305 #if(0)
2306 	device_printf(sc->dev, "envy24ht_init()\n");
2307 #endif
2308 
2309 	/* reset chip */
2310 #if 0
2311 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2312 	DELAY(200);
2313 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2314 	DELAY(200);
2315 
2316 	/* legacy hardware disable */
2317 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2318 	data |= PCIM_LAC_DISABLE;
2319 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2320 #endif
2321 
2322 	/* check system configuration */
2323 	sc->cfg = NULL;
2324 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2325 		/* 1st: search configuration from table */
2326 		sv = pci_get_subvendor(sc->dev);
2327 		sd = pci_get_subdevice(sc->dev);
2328 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2329 #if(0)
2330 			device_printf(sc->dev, "Set configuration from table\n");
2331 #endif
2332 			sc->cfg = &cfg_table[i];
2333 			break;
2334 		}
2335 	}
2336 	if (sc->cfg == NULL) {
2337 		/* 2nd: read configuration from table */
2338 		sc->cfg = envy24ht_rom2cfg(sc);
2339 	}
2340 	sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2341 	sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2342 
2343 	if (1 /* bootverbose */) {
2344 		envy24ht_putcfg(sc);
2345 	}
2346 
2347 	/* set system configuration */
2348 	envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2349 	envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2350 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2351 	envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2352 	envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2353 	envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2354 	envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2355 
2356 	if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2357 		envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2358 		envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2359 		envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2360 	}
2361 
2362 	for (i = 0; i < sc->adcn; i++) {
2363 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2364 		sc->cfg->codec->init(sc->adc[i]);
2365 	}
2366 	for (i = 0; i < sc->dacn; i++) {
2367 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2368 		sc->cfg->codec->init(sc->dac[i]);
2369 	}
2370 
2371 	/* initialize DMA buffer */
2372 #if(0)
2373 	device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2374 #endif
2375 	if (envy24ht_dmainit(sc))
2376 		return ENOSPC;
2377 
2378 	/* initialize status */
2379 	sc->run[0] = sc->run[1] = 0;
2380 	sc->intr[0] = sc->intr[1] = 0;
2381 	sc->speed = 0;
2382 	sc->caps[0].fmtlist = envy24ht_playfmt;
2383 	sc->caps[1].fmtlist = envy24ht_recfmt;
2384 
2385 	/* set channel router */
2386 #if 0
2387 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2388 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2389 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2390 #endif
2391 
2392 	/* set macro interrupt mask */
2393 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2394 	envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2395 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2396 #if(0)
2397 	device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2398 #endif
2399 
2400 	return 0;
2401 }
2402 
2403 static int
2404 envy24ht_alloc_resource(struct sc_info *sc)
2405 {
2406 	/* allocate I/O port resource */
2407 	sc->csid = PCIR_CCS;
2408 	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2409 	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2410 	sc->mtid = ENVY24HT_PCIR_MT;
2411 	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2412 	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2413 	if (!sc->cs || !sc->mt) {
2414 		device_printf(sc->dev, "unable to map IO port space\n");
2415 		return ENXIO;
2416 	}
2417 	sc->cst = rman_get_bustag(sc->cs);
2418 	sc->csh = rman_get_bushandle(sc->cs);
2419 	sc->mtt = rman_get_bustag(sc->mt);
2420 	sc->mth = rman_get_bushandle(sc->mt);
2421 #if(0)
2422 	device_printf(sc->dev,
2423 	    "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2424 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2425 	    pci_read_config(sc->dev, PCIR_MT, 4));
2426 #endif
2427 
2428 	/* allocate interrupt resource */
2429 	sc->irqid = 0;
2430 	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2431 				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2432 	if (!sc->irq ||
2433 	    snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2434 		device_printf(sc->dev, "unable to map interrupt\n");
2435 		return ENXIO;
2436 	}
2437 
2438 	/* allocate DMA resource */
2439 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2440 	    /*alignment*/4,
2441 	    /*boundary*/0,
2442 	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2443 	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2444 	    /*filter*/NULL, /*filterarg*/NULL,
2445 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2446 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2447 	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2448 	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2449 		device_printf(sc->dev, "unable to create dma tag\n");
2450 		return ENXIO;
2451 	}
2452 
2453 	return 0;
2454 }
2455 
2456 static int
2457 envy24ht_pci_attach(device_t dev)
2458 {
2459 	u_int32_t		data;
2460 	struct sc_info 		*sc;
2461 	char 			status[SND_STATUSLEN];
2462 	int			err = 0;
2463 	int			i;
2464 
2465 #if(0)
2466 	device_printf(dev, "envy24ht_pci_attach()\n");
2467 #endif
2468 	/* get sc_info data area */
2469 	if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2470 		device_printf(dev, "cannot allocate softc\n");
2471 		return ENXIO;
2472 	}
2473 
2474 	bzero(sc, sizeof(*sc));
2475 	sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2476 	    "snd_envy24ht softc");
2477 	sc->dev = dev;
2478 
2479 	/* initialize PCI interface */
2480 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2481 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2482 	pci_write_config(dev, PCIR_COMMAND, data, 2);
2483 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2484 
2485 	/* allocate resources */
2486 	err = envy24ht_alloc_resource(sc);
2487 	if (err) {
2488 		device_printf(dev, "unable to allocate system resources\n");
2489 		goto bad;
2490 	}
2491 
2492 	/* initialize card */
2493 	err = envy24ht_init(sc);
2494 	if (err) {
2495 		device_printf(dev, "unable to initialize the card\n");
2496 		goto bad;
2497 	}
2498 
2499 	/* set multi track mixer */
2500 	mixer_init(dev, &envy24htmixer_class, sc);
2501 
2502 	/* set channel information */
2503 	/* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2504 	err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2505 	if (err)
2506 		goto bad;
2507 	sc->chnum = 0;
2508 	/* for (i = 0; i < 5; i++) { */
2509 		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2510 		sc->chnum++;
2511 	/* } */
2512 	for (i = 0; i < 2 + sc->adcn; i++) {
2513 		pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2514 		sc->chnum++;
2515 	}
2516 
2517 	/* set status iformation */
2518 	snprintf(status, SND_STATUSLEN,
2519 	    "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2520 	    rman_get_start(sc->cs),
2521 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2522 	    rman_get_start(sc->mt),
2523 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2524 	    rman_get_start(sc->irq));
2525 	pcm_setstatus(dev, status);
2526 
2527 	return 0;
2528 
2529 bad:
2530 	if (sc->ih)
2531 		bus_teardown_intr(dev, sc->irq, sc->ih);
2532 	if (sc->irq)
2533 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2534 	envy24ht_dmafree(sc);
2535 	if (sc->dmat)
2536 		bus_dma_tag_destroy(sc->dmat);
2537         if (sc->cfg->codec->destroy != NULL) {
2538                 for (i = 0; i < sc->adcn; i++)
2539                         sc->cfg->codec->destroy(sc->adc[i]);
2540                 for (i = 0; i < sc->dacn; i++)
2541                         sc->cfg->codec->destroy(sc->dac[i]);
2542         }
2543 	envy24ht_cfgfree(sc->cfg);
2544 	if (sc->cs)
2545 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2546 	if (sc->mt)
2547 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2548 	if (sc->lock)
2549 		snd_mtxfree(sc->lock);
2550 	free(sc, M_ENVY24HT);
2551 	return err;
2552 }
2553 
2554 static int
2555 envy24ht_pci_detach(device_t dev)
2556 {
2557 	struct sc_info *sc;
2558 	int r;
2559 	int i;
2560 
2561 #if(0)
2562 	device_printf(dev, "envy24ht_pci_detach()\n");
2563 #endif
2564 	sc = pcm_getdevinfo(dev);
2565 	if (sc == NULL)
2566 		return 0;
2567 	r = pcm_unregister(dev);
2568 	if (r)
2569 		return r;
2570 
2571 	envy24ht_dmafree(sc);
2572 	if (sc->cfg->codec->destroy != NULL) {
2573 		for (i = 0; i < sc->adcn; i++)
2574 			sc->cfg->codec->destroy(sc->adc[i]);
2575 		for (i = 0; i < sc->dacn; i++)
2576 			sc->cfg->codec->destroy(sc->dac[i]);
2577 	}
2578 	envy24ht_cfgfree(sc->cfg);
2579 	bus_dma_tag_destroy(sc->dmat);
2580 	bus_teardown_intr(dev, sc->irq, sc->ih);
2581 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2582 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2583 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2584 	snd_mtxfree(sc->lock);
2585 	free(sc, M_ENVY24HT);
2586 	return 0;
2587 }
2588 
2589 static device_method_t envy24ht_methods[] = {
2590 	/* Device interface */
2591 	DEVMETHOD(device_probe,		envy24ht_pci_probe),
2592 	DEVMETHOD(device_attach,	envy24ht_pci_attach),
2593 	DEVMETHOD(device_detach,	envy24ht_pci_detach),
2594 	{ 0, 0 }
2595 };
2596 
2597 static driver_t envy24ht_driver = {
2598 	"pcm",
2599 	envy24ht_methods,
2600 #if __FreeBSD_version > 500000
2601 	PCM_SOFTC_SIZE,
2602 #else
2603 	sizeof(struct snddev_info),
2604 #endif
2605 };
2606 
2607 DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2608 MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2609 MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2610 MODULE_VERSION(snd_envy24ht, 1);
2611