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