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