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