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