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