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