xref: /freebsd/sys/dev/sound/pci/envy24.c (revision 57c4583f70ab9d25b3aed17f20ec7843f9673539)
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/spicds.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 spicds_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_REC && sc->adc[num] != NULL)
785 		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
786 	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
787 		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
788 	else
789 		buff->info = spicds_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->dac[ptr->num] != NULL)
814 			spicds_destroy(ptr->info);
815 	}
816 	else {
817 		if (ptr->parent->adc[ptr->num] != NULL)
818 			spicds_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 	ptr->cdti = ptr->parent->cfg->cdti;
857 	spicds_settype(ptr->info,  ptr->parent->cfg->type);
858 	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
859 	spicds_setformat(ptr->info,
860 	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
861 	spicds_setdvc(ptr->info, 0);
862 	/* for the time being, init only first codec */
863 	if (ptr->num == 0)
864 		spicds_init(ptr->info);
865 }
866 
867 static void
868 envy24_delta_ak4524_reinit(void *codec)
869 {
870 	struct envy24_delta_ak4524_codec *ptr = codec;
871 	if (ptr == NULL)
872 		return;
873 #if(0)
874 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
875 #endif
876 
877 	spicds_reinit(ptr->info);
878 }
879 
880 static void
881 envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
882 {
883 	struct envy24_delta_ak4524_codec *ptr = codec;
884 	if (ptr == NULL)
885 		return;
886 #if(0)
887 	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
888 #endif
889 
890 	spicds_set(ptr->info, dir, left, right);
891 }
892 
893 /*
894   There is no need for AK452[48] codec to set sample rate
895   static void
896   envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
897   {
898   }
899 */
900 
901 /* -------------------------------------------------------------------- */
902 
903 /* hardware access routeines */
904 
905 static struct {
906 	u_int32_t speed;
907 	u_int32_t code;
908 } envy24_speedtab[] = {
909 	{48000, ENVY24_MT_RATE_48000},
910 	{24000, ENVY24_MT_RATE_24000},
911 	{12000, ENVY24_MT_RATE_12000},
912 	{9600, ENVY24_MT_RATE_9600},
913 	{32000, ENVY24_MT_RATE_32000},
914 	{16000, ENVY24_MT_RATE_16000},
915 	{8000, ENVY24_MT_RATE_8000},
916 	{96000, ENVY24_MT_RATE_96000},
917 	{64000, ENVY24_MT_RATE_64000},
918 	{44100, ENVY24_MT_RATE_44100},
919 	{22050, ENVY24_MT_RATE_22050},
920 	{11025, ENVY24_MT_RATE_11025},
921 	{88200, ENVY24_MT_RATE_88200},
922 	{0, 0x10}
923 };
924 
925 static int
926 envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
927 	u_int32_t code;
928 	int i = 0;
929 
930 #if(0)
931 	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
932 #endif
933 	if (speed == 0) {
934 		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
935 		envy24_slavecd(sc);
936 	}
937 	else {
938 		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
939 			if (envy24_speedtab[i].speed == speed)
940 				break;
941 		}
942 		code = envy24_speedtab[i].code;
943 	}
944 #if(0)
945 	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
946 #endif
947 	if (code < 0x10) {
948 		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
949 		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
950 		code &= ENVY24_MT_RATE_MASK;
951 		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
952 			if (envy24_speedtab[i].code == code)
953 				break;
954 		}
955 		speed = envy24_speedtab[i].speed;
956 	}
957 	else
958 		speed = 0;
959 
960 #if(0)
961 	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
962 #endif
963 	return speed;
964 }
965 
966 static void
967 envy24_setvolume(struct sc_info *sc, unsigned ch)
968 {
969 #if(0)
970 	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
971 #endif
972 if (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
973         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
974         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
975         envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
976         envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
977 	}
978 
979 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
980 	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
981 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
982 	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
983 }
984 
985 static void
986 envy24_mutevolume(struct sc_info *sc, unsigned ch)
987 {
988 	u_int32_t vol;
989 
990 #if(0)
991 	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
992 #endif
993 	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
994 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
995 	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
996 	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
997 	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
998 }
999 
1000 static u_int32_t
1001 envy24_gethwptr(struct sc_info *sc, int dir)
1002 {
1003 	int unit, regno;
1004 	u_int32_t ptr, rtn;
1005 
1006 #if(0)
1007 	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1008 #endif
1009 	if (dir == PCMDIR_PLAY) {
1010 		rtn = sc->psize / 4;
1011 		unit = ENVY24_PLAY_BUFUNIT / 4;
1012 		regno = ENVY24_MT_PCNT;
1013 	}
1014 	else {
1015 		rtn = sc->rsize / 4;
1016 		unit = ENVY24_REC_BUFUNIT / 4;
1017 		regno = ENVY24_MT_RCNT;
1018 	}
1019 
1020 	ptr = envy24_rdmt(sc, regno, 2);
1021 	rtn -= (ptr + 1);
1022 	rtn /= unit;
1023 
1024 #if(0)
1025 	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1026 #endif
1027 	return rtn;
1028 }
1029 
1030 static void
1031 envy24_updintr(struct sc_info *sc, int dir)
1032 {
1033 	int regptr, regintr;
1034 	u_int32_t mask, intr;
1035 	u_int32_t ptr, size, cnt;
1036 	u_int16_t blk;
1037 
1038 #if(0)
1039 	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1040 #endif
1041 	if (dir == PCMDIR_PLAY) {
1042 		blk = sc->blk[0];
1043 		size = sc->psize / 4;
1044 		regptr = ENVY24_MT_PCNT;
1045 		regintr = ENVY24_MT_PTERM;
1046 		mask = ~ENVY24_MT_INT_PMASK;
1047 	}
1048 	else {
1049 		blk = sc->blk[1];
1050 		size = sc->rsize / 4;
1051 		regptr = ENVY24_MT_RCNT;
1052 		regintr = ENVY24_MT_RTERM;
1053 		mask = ~ENVY24_MT_INT_RMASK;
1054 	}
1055 
1056 	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1057 	/*
1058 	cnt = blk - ptr % blk - 1;
1059 	if (cnt == 0)
1060 		cnt = blk - 1;
1061 	*/
1062 	cnt = blk - 1;
1063 #if(0)
1064 	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1065 #endif
1066 	envy24_wrmt(sc, regintr, cnt, 2);
1067 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1068 #if(0)
1069 	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1070 #endif
1071 	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1072 #if(0)
1073 	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1074 		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1075 #endif
1076 
1077 	return;
1078 }
1079 
1080 #if 0
1081 static void
1082 envy24_maskintr(struct sc_info *sc, int dir)
1083 {
1084 	u_int32_t mask, intr;
1085 
1086 #if(0)
1087 	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1088 #endif
1089 	if (dir == PCMDIR_PLAY)
1090 		mask = ENVY24_MT_INT_PMASK;
1091 	else
1092 		mask = ENVY24_MT_INT_RMASK;
1093 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1094 	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1095 
1096 	return;
1097 }
1098 #endif
1099 
1100 static int
1101 envy24_checkintr(struct sc_info *sc, int dir)
1102 {
1103 	u_int32_t mask, stat, intr, rtn;
1104 
1105 #if(0)
1106 	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1107 #endif
1108 	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1109 	if (dir == PCMDIR_PLAY) {
1110 		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1111 			mask = ~ENVY24_MT_INT_RSTAT;
1112 			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1113 			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1114 		}
1115 	}
1116 	else {
1117 		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1118 			mask = ~ENVY24_MT_INT_PSTAT;
1119 			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1120 			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1121 		}
1122 	}
1123 
1124 	return rtn;
1125 }
1126 
1127 static void
1128 envy24_start(struct sc_info *sc, int dir)
1129 {
1130 	u_int32_t stat, sw;
1131 
1132 #if(0)
1133 	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1134 #endif
1135 	if (dir == PCMDIR_PLAY)
1136 		sw = ENVY24_MT_PCTL_PSTART;
1137 	else
1138 		sw = ENVY24_MT_PCTL_RSTART;
1139 
1140 	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1141 	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1142 #if(0)
1143 	DELAY(100);
1144 	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1145 	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1146 #endif
1147 
1148 	return;
1149 }
1150 
1151 static void
1152 envy24_stop(struct sc_info *sc, int dir)
1153 {
1154 	u_int32_t stat, sw;
1155 
1156 #if(0)
1157 	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1158 #endif
1159 	if (dir == PCMDIR_PLAY)
1160 		sw = ~ENVY24_MT_PCTL_PSTART;
1161 	else
1162 		sw = ~ENVY24_MT_PCTL_RSTART;
1163 
1164 	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1165 	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1166 
1167 	return;
1168 }
1169 
1170 static int
1171 envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1172 {
1173 	u_int32_t reg, mask;
1174 	u_int32_t left, right;
1175 
1176 #if(0)
1177 	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1178 	    dac, class, adc, rev);
1179 #endif
1180 	/* parameter pattern check */
1181 	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1182 		return -1;
1183 	if (class == ENVY24_ROUTE_CLASS_MIX &&
1184 	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1185 		return -1;
1186 	if (rev) {
1187 		left = ENVY24_ROUTE_RIGHT;
1188 		right = ENVY24_ROUTE_LEFT;
1189 	}
1190 	else {
1191 		left = ENVY24_ROUTE_LEFT;
1192 		right = ENVY24_ROUTE_RIGHT;
1193 	}
1194 
1195 	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1196 		reg = class | class << 2 |
1197 			((adc << 1 | left) | left << 3) << 8 |
1198 			((adc << 1 | right) | right << 3) << 12;
1199 #if(0)
1200 		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1201 #endif
1202 		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1203 	}
1204 	else {
1205 		mask = ~(0x0303 << dac * 2);
1206 		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1207 		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1208 #if(0)
1209 		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1210 #endif
1211 		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1212 		mask = ~(0xff << dac * 8);
1213 		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1214 		reg = (reg & mask) |
1215 			(((adc << 1 | left) | left << 3) |
1216 			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1217 #if(0)
1218 		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1219 #endif
1220 		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1221 	}
1222 
1223 	return 0;
1224 }
1225 
1226 /* -------------------------------------------------------------------- */
1227 
1228 /* buffer copy routines */
1229 static void
1230 envy24_p32sl(struct sc_chinfo *ch)
1231 {
1232 	int length;
1233 	sample32_t *dmabuf;
1234 	u_int32_t *data;
1235 	int src, dst, ssize, dsize, slot;
1236 	int i;
1237 
1238 	length = sndbuf_getready(ch->buffer) / 8;
1239 	dmabuf = ch->parent->pbuf;
1240 	data = (u_int32_t *)ch->data;
1241 	src = sndbuf_getreadyptr(ch->buffer) / 4;
1242 	dst = src / 2 + ch->offset;
1243 	ssize = ch->size / 4;
1244 	dsize = ch->size / 8;
1245 	slot = ch->num * 2;
1246 
1247 	for (i = 0; i < length; i++) {
1248 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1249 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1250 		dst++;
1251 		dst %= dsize;
1252 		src += 2;
1253 		src %= ssize;
1254 	}
1255 
1256 	return;
1257 }
1258 
1259 static void
1260 envy24_p16sl(struct sc_chinfo *ch)
1261 {
1262 	int length;
1263 	sample32_t *dmabuf;
1264 	u_int16_t *data;
1265 	int src, dst, ssize, dsize, slot;
1266 	int i;
1267 
1268 #if(0)
1269 	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1270 #endif
1271 	length = sndbuf_getready(ch->buffer) / 4;
1272 	dmabuf = ch->parent->pbuf;
1273 	data = (u_int16_t *)ch->data;
1274 	src = sndbuf_getreadyptr(ch->buffer) / 2;
1275 	dst = src / 2 + ch->offset;
1276 	ssize = ch->size / 2;
1277 	dsize = ch->size / 4;
1278 	slot = ch->num * 2;
1279 #if(0)
1280 	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1281 #endif
1282 
1283 	for (i = 0; i < length; i++) {
1284 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1285 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1286 #if(0)
1287 		if (i < 16) {
1288 			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1289 			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1290 		}
1291 #endif
1292 		dst++;
1293 		dst %= dsize;
1294 		src += 2;
1295 		src %= ssize;
1296 	}
1297 #if(0)
1298 	printf("\n");
1299 #endif
1300 
1301 	return;
1302 }
1303 
1304 static void
1305 envy24_p8u(struct sc_chinfo *ch)
1306 {
1307 	int length;
1308 	sample32_t *dmabuf;
1309 	u_int8_t *data;
1310 	int src, dst, ssize, dsize, slot;
1311 	int i;
1312 
1313 	length = sndbuf_getready(ch->buffer) / 2;
1314 	dmabuf = ch->parent->pbuf;
1315 	data = (u_int8_t *)ch->data;
1316 	src = sndbuf_getreadyptr(ch->buffer);
1317 	dst = src / 2 + ch->offset;
1318 	ssize = ch->size;
1319 	dsize = ch->size / 4;
1320 	slot = ch->num * 2;
1321 
1322 	for (i = 0; i < length; i++) {
1323 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1324 		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1325 		dst++;
1326 		dst %= dsize;
1327 		src += 2;
1328 		src %= ssize;
1329 	}
1330 
1331 	return;
1332 }
1333 
1334 static void
1335 envy24_r32sl(struct sc_chinfo *ch)
1336 {
1337 	int length;
1338 	sample32_t *dmabuf;
1339 	u_int32_t *data;
1340 	int src, dst, ssize, dsize, slot;
1341 	int i;
1342 
1343 	length = sndbuf_getfree(ch->buffer) / 8;
1344 	dmabuf = ch->parent->rbuf;
1345 	data = (u_int32_t *)ch->data;
1346 	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1347 	src = dst / 2 + ch->offset;
1348 	dsize = ch->size / 4;
1349 	ssize = ch->size / 8;
1350 	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1351 
1352 	for (i = 0; i < length; i++) {
1353 		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1354 		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1355 		dst += 2;
1356 		dst %= dsize;
1357 		src++;
1358 		src %= ssize;
1359 	}
1360 
1361 	return;
1362 }
1363 
1364 static void
1365 envy24_r16sl(struct sc_chinfo *ch)
1366 {
1367 	int length;
1368 	sample32_t *dmabuf;
1369 	u_int16_t *data;
1370 	int src, dst, ssize, dsize, slot;
1371 	int i;
1372 
1373 	length = sndbuf_getfree(ch->buffer) / 4;
1374 	dmabuf = ch->parent->rbuf;
1375 	data = (u_int16_t *)ch->data;
1376 	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1377 	src = dst / 2 + ch->offset;
1378 	dsize = ch->size / 2;
1379 	ssize = ch->size / 8;
1380 	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1381 
1382 	for (i = 0; i < length; i++) {
1383 		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1384 		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1385 		dst += 2;
1386 		dst %= dsize;
1387 		src++;
1388 		src %= ssize;
1389 	}
1390 
1391 	return;
1392 }
1393 
1394 /* -------------------------------------------------------------------- */
1395 
1396 /* channel interface */
1397 static void *
1398 envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1399 {
1400 	struct sc_info	*sc = (struct sc_info *)devinfo;
1401 	struct sc_chinfo *ch;
1402 	unsigned num;
1403 
1404 #if(0)
1405 	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1406 #endif
1407 	snd_mtxlock(sc->lock);
1408 	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1409 	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1410 		snd_mtxunlock(sc->lock);
1411 		return NULL;
1412 	}
1413 	num = sc->chnum;
1414 
1415 	ch = &sc->chan[num];
1416 	ch->size = 8 * ENVY24_SAMPLE_NUM;
1417 	ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1418 	if (ch->data == NULL) {
1419 		ch->size = 0;
1420 		ch = NULL;
1421 	}
1422 	else {
1423 		ch->buffer = b;
1424 		ch->channel = c;
1425 		ch->parent = sc;
1426 		ch->dir = dir;
1427 		/* set channel map */
1428 		ch->num = envy24_chanmap[num];
1429 		sndbuf_setup(ch->buffer, ch->data, ch->size);
1430 		/* these 2 values are dummy */
1431 		ch->unit = 4;
1432 		ch->blk = 10240;
1433 	}
1434 	snd_mtxunlock(sc->lock);
1435 
1436 	return ch;
1437 }
1438 
1439 static int
1440 envy24chan_free(kobj_t obj, void *data)
1441 {
1442 	struct sc_chinfo *ch = data;
1443 	struct sc_info *sc = ch->parent;
1444 
1445 #if(0)
1446 	device_printf(sc->dev, "envy24chan_free()\n");
1447 #endif
1448 	snd_mtxlock(sc->lock);
1449 	if (ch->data != NULL) {
1450 		free(ch->data, M_ENVY24);
1451 		ch->data = NULL;
1452 	}
1453 	snd_mtxunlock(sc->lock);
1454 
1455 	return 0;
1456 }
1457 
1458 static int
1459 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1460 {
1461 	struct sc_chinfo *ch = data;
1462 	struct sc_info *sc = ch->parent;
1463 	struct envy24_emldma *emltab;
1464 	unsigned int bcnt, bsize;
1465 	int i;
1466 
1467 #if(0)
1468 	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1469 #endif
1470 	snd_mtxlock(sc->lock);
1471 	/* check and get format related information */
1472 	if (ch->dir == PCMDIR_PLAY)
1473 		emltab = envy24_pemltab;
1474 	else
1475 		emltab = envy24_remltab;
1476 	if (emltab == NULL) {
1477 		snd_mtxunlock(sc->lock);
1478 		return -1;
1479 	}
1480 	for (i = 0; emltab[i].format != 0; i++)
1481 		if (emltab[i].format == format)
1482 			break;
1483 	if (emltab[i].format == 0) {
1484 		snd_mtxunlock(sc->lock);
1485 		return -1;
1486 	}
1487 
1488 	/* set format information */
1489 	ch->format = format;
1490 	ch->emldma = emltab[i].emldma;
1491 	if (ch->unit > emltab[i].unit)
1492 		ch->blk *= ch->unit / emltab[i].unit;
1493 	else
1494 		ch->blk /= emltab[i].unit / ch->unit;
1495 	ch->unit = emltab[i].unit;
1496 
1497 	/* set channel buffer information */
1498 	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1499 	if (ch->dir == PCMDIR_PLAY)
1500 		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1501 	else
1502 		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1503 	bsize *= ch->unit;
1504 	bcnt = ch->size / bsize;
1505 	sndbuf_resize(ch->buffer, bcnt, bsize);
1506 	snd_mtxunlock(sc->lock);
1507 
1508 #if(0)
1509 	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1510 #endif
1511 	return 0;
1512 }
1513 
1514 /*
1515   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1516   of speed information value. And real hardware speed setting is done
1517   at start triggered(see envy24chan_trigger()). So, at this function
1518   is called, any value that ENVY24 can use is able to set. But, at
1519   start triggerd, some other channel is running, and that channel's
1520   speed isn't same with, then trigger function will fail.
1521 */
1522 static int
1523 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1524 {
1525 	struct sc_chinfo *ch = data;
1526 	u_int32_t val, prev;
1527 	int i;
1528 
1529 #if(0)
1530 	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1531 #endif
1532 	prev = 0x7fffffff;
1533 	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1534 		if (abs(val - speed) < abs(prev - speed))
1535 			prev = val;
1536 		else
1537 			break;
1538 	}
1539 	ch->speed = prev;
1540 
1541 #if(0)
1542 	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1543 #endif
1544 	return ch->speed;
1545 }
1546 
1547 static int
1548 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1549 {
1550 	struct sc_chinfo *ch = data;
1551 	struct sc_info *sc = ch->parent;
1552 	u_int32_t size, prev;
1553 
1554 #if(0)
1555 	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1556 #endif
1557 	prev = 0x7fffffff;
1558 	snd_mtxlock(sc->lock);
1559 	for (size = ch->size / 2; size > 0; size /= 2) {
1560 		if (abs(size - blocksize) < abs(prev - blocksize))
1561 			prev = size;
1562 		else
1563 			break;
1564 	}
1565 
1566 	ch->blk = prev / ch->unit;
1567 	if (ch->dir == PCMDIR_PLAY)
1568 		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1569 	else
1570 		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1571 	snd_mtxunlock(sc->lock);
1572 
1573 #if(0)
1574 	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1575 #endif
1576 	return prev;
1577 }
1578 
1579 /* semantic note: must start at beginning of buffer */
1580 static int
1581 envy24chan_trigger(kobj_t obj, void *data, int go)
1582 {
1583 	struct sc_chinfo *ch = data;
1584 	struct sc_info *sc = ch->parent;
1585 	u_int32_t ptr;
1586 	int slot;
1587 #if 0
1588 	int i;
1589 
1590 	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1591 #endif
1592 	snd_mtxlock(sc->lock);
1593 	if (ch->dir == PCMDIR_PLAY)
1594 		slot = 0;
1595 	else
1596 		slot = 1;
1597 	switch (go) {
1598 	case PCMTRIG_START:
1599 #if(0)
1600 		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1601 #endif
1602 		/* check or set channel speed */
1603 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1604 			sc->speed = envy24_setspeed(sc, ch->speed);
1605 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1606 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1607 		}
1608 		else if (ch->speed != 0 && ch->speed != sc->speed)
1609 			return -1;
1610 		if (ch->speed == 0)
1611 			ch->channel->speed = sc->speed;
1612 		/* start or enable channel */
1613 		sc->run[slot]++;
1614 		if (sc->run[slot] == 1) {
1615 			/* first channel */
1616 			ch->offset = 0;
1617 			sc->blk[slot] = ch->blk;
1618 		}
1619 		else {
1620 			ptr = envy24_gethwptr(sc, ch->dir);
1621 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1622 			    (ch->size / 4)) * 4 / ch->unit;
1623 			if (ch->blk < sc->blk[slot])
1624 				sc->blk[slot] = ch->blk;
1625 		}
1626 		if (ch->dir == PCMDIR_PLAY) {
1627 			ch->emldma(ch);
1628 			envy24_setvolume(sc, ch->num);
1629 		}
1630 		envy24_updintr(sc, ch->dir);
1631 		if (sc->run[slot] == 1)
1632 			envy24_start(sc, ch->dir);
1633 		ch->run = 1;
1634 		break;
1635 	case PCMTRIG_EMLDMAWR:
1636 #if(0)
1637 		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1638 #endif
1639 		if (ch->run != 1)
1640 			return -1;
1641 		ch->emldma(ch);
1642 		break;
1643 	case PCMTRIG_EMLDMARD:
1644 #if(0)
1645 		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1646 #endif
1647 		if (ch->run != 1)
1648 			return -1;
1649 		ch->emldma(ch);
1650 		break;
1651 	case PCMTRIG_ABORT:
1652 #if(0)
1653 		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1654 #endif
1655 		ch->run = 0;
1656 		sc->run[slot]--;
1657 		if (ch->dir == PCMDIR_PLAY)
1658 			envy24_mutevolume(sc, ch->num);
1659 		if (sc->run[slot] == 0) {
1660 			envy24_stop(sc, ch->dir);
1661 			sc->intr[slot] = 0;
1662 		}
1663 #if 0
1664 		else if (ch->blk == sc->blk[slot]) {
1665 			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1666 			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1667 				if (sc->chan[i].dir == ch->dir &&
1668 				    sc->chan[i].run == 1 &&
1669 				    sc->chan[i].blk < sc->blk[slot])
1670 					sc->blk[slot] = sc->chan[i].blk;
1671 			}
1672 			if (ch->blk != sc->blk[slot])
1673 				envy24_updintr(sc, ch->dir);
1674 		}
1675 #endif
1676 		break;
1677 	}
1678 	snd_mtxunlock(sc->lock);
1679 
1680 	return 0;
1681 }
1682 
1683 static int
1684 envy24chan_getptr(kobj_t obj, void *data)
1685 {
1686 	struct sc_chinfo *ch = data;
1687 	struct sc_info *sc = ch->parent;
1688 	u_int32_t ptr;
1689 	int rtn;
1690 
1691 #if(0)
1692 	device_printf(sc->dev, "envy24chan_getptr()\n");
1693 #endif
1694 	snd_mtxlock(sc->lock);
1695 	ptr = envy24_gethwptr(sc, ch->dir);
1696 	rtn = ptr * ch->unit;
1697 	snd_mtxunlock(sc->lock);
1698 
1699 #if(0)
1700 	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1701 	    rtn);
1702 #endif
1703 	return rtn;
1704 }
1705 
1706 static struct pcmchan_caps *
1707 envy24chan_getcaps(kobj_t obj, void *data)
1708 {
1709 	struct sc_chinfo *ch = data;
1710 	struct sc_info *sc = ch->parent;
1711 	struct pcmchan_caps *rtn;
1712 
1713 #if(0)
1714 	device_printf(sc->dev, "envy24chan_getcaps()\n");
1715 #endif
1716 	snd_mtxlock(sc->lock);
1717 	if (ch->dir == PCMDIR_PLAY) {
1718 		if (sc->run[0] == 0)
1719 			rtn = &envy24_playcaps;
1720 		else
1721 			rtn = &sc->caps[0];
1722 	}
1723 	else {
1724 		if (sc->run[1] == 0)
1725 			rtn = &envy24_reccaps;
1726 		else
1727 			rtn = &sc->caps[1];
1728 	}
1729 	snd_mtxunlock(sc->lock);
1730 
1731 	return rtn;
1732 }
1733 
1734 static kobj_method_t envy24chan_methods[] = {
1735 	KOBJMETHOD(channel_init,		envy24chan_init),
1736 	KOBJMETHOD(channel_free,		envy24chan_free),
1737 	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1738 	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1739 	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1740 	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1741 	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1742 	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1743 	{ 0, 0 }
1744 };
1745 CHANNEL_DECLARE(envy24chan);
1746 
1747 /* -------------------------------------------------------------------- */
1748 
1749 /* mixer interface */
1750 
1751 static int
1752 envy24mixer_init(struct snd_mixer *m)
1753 {
1754 	struct sc_info *sc = mix_getdevinfo(m);
1755 
1756 #if(0)
1757 	device_printf(sc->dev, "envy24mixer_init()\n");
1758 #endif
1759 	if (sc == NULL)
1760 		return -1;
1761 
1762 	/* set volume control rate */
1763 	snd_mtxlock(sc->lock);
1764 	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1765 
1766 	mix_setdevs(m, ENVY24_MIX_MASK);
1767 	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1768 	snd_mtxunlock(sc->lock);
1769 
1770 	return 0;
1771 }
1772 
1773 static int
1774 envy24mixer_reinit(struct snd_mixer *m)
1775 {
1776 	struct sc_info *sc = mix_getdevinfo(m);
1777 
1778 	if (sc == NULL)
1779 		return -1;
1780 #if(0)
1781 	device_printf(sc->dev, "envy24mixer_reinit()\n");
1782 #endif
1783 
1784 	return 0;
1785 }
1786 
1787 static int
1788 envy24mixer_uninit(struct snd_mixer *m)
1789 {
1790 	struct sc_info *sc = mix_getdevinfo(m);
1791 
1792 	if (sc == NULL)
1793 		return -1;
1794 #if(0)
1795 	device_printf(sc->dev, "envy24mixer_uninit()\n");
1796 #endif
1797 
1798 	return 0;
1799 }
1800 
1801 static int
1802 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1803 {
1804 	struct sc_info *sc = mix_getdevinfo(m);
1805 	int ch = envy24_mixmap[dev];
1806 	int hwch;
1807 	int i;
1808 
1809 	if (sc == NULL)
1810 		return -1;
1811 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1812 		return -1;
1813 	if (dev != 0 && ch == -1)
1814 		return -1;
1815 	hwch = envy24_chanmap[ch];
1816 #if(0)
1817 	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1818 	    dev, left, right);
1819 #endif
1820 
1821 	snd_mtxlock(sc->lock);
1822 	if (dev == 0) {
1823 		for (i = 0; i < sc->dacn; i++) {
1824 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1825 		}
1826 	}
1827 	else {
1828 		/* set volume value for hardware */
1829 		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1830 			sc->left[hwch] = ENVY24_VOL_MUTE;
1831 		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1832 			sc->right[hwch] = ENVY24_VOL_MUTE;
1833 
1834 		/* set volume for record channel and running play channel */
1835 		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1836 			envy24_setvolume(sc, hwch);
1837 	}
1838 	snd_mtxunlock(sc->lock);
1839 
1840 	return right << 8 | left;
1841 }
1842 
1843 static u_int32_t
1844 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1845 {
1846 	struct sc_info *sc = mix_getdevinfo(m);
1847 	int ch = envy24_mixmap[src];
1848 #if(0)
1849 	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1850 #endif
1851 
1852 	if (ch > ENVY24_CHAN_PLAY_SPDIF)
1853 		sc->src = ch;
1854 	return src;
1855 }
1856 
1857 static kobj_method_t envy24mixer_methods[] = {
1858 	KOBJMETHOD(mixer_init,		envy24mixer_init),
1859 	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
1860 	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
1861 	KOBJMETHOD(mixer_set,		envy24mixer_set),
1862 	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
1863 	{ 0, 0 }
1864 };
1865 MIXER_DECLARE(envy24mixer);
1866 
1867 /* -------------------------------------------------------------------- */
1868 
1869 /* The interrupt handler */
1870 static void
1871 envy24_intr(void *p)
1872 {
1873 	struct sc_info *sc = (struct sc_info *)p;
1874 	struct sc_chinfo *ch;
1875 	u_int32_t ptr, dsize, feed;
1876 	int i;
1877 
1878 #if(0)
1879 	device_printf(sc->dev, "envy24_intr()\n");
1880 #endif
1881 	snd_mtxlock(sc->lock);
1882 	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
1883 #if(0)
1884 		device_printf(sc->dev, "envy24_intr(): play\n");
1885 #endif
1886 		dsize = sc->psize / 4;
1887 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
1888 #if(0)
1889 		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
1890 #endif
1891 		ptr -= ptr % sc->blk[0];
1892 		feed = (ptr + dsize - sc->intr[0]) % dsize;
1893 #if(0)
1894 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1895 #endif
1896 		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
1897 			ch = &sc->chan[i];
1898 #if(0)
1899 			if (ch->run)
1900 				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
1901 #endif
1902 			if (ch->run && ch->blk <= feed)
1903 				chn_intr(ch->channel);
1904 		}
1905 		sc->intr[0] = ptr;
1906 		envy24_updintr(sc, PCMDIR_PLAY);
1907 	}
1908 	if (envy24_checkintr(sc, PCMDIR_REC)) {
1909 #if(0)
1910 		device_printf(sc->dev, "envy24_intr(): rec\n");
1911 #endif
1912 		dsize = sc->rsize / 4;
1913 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
1914 		ptr -= ptr % sc->blk[1];
1915 		feed = (ptr + dsize - sc->intr[1]) % dsize;
1916 		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
1917 			ch = &sc->chan[i];
1918 			if (ch->run && ch->blk <= feed)
1919 				chn_intr(ch->channel);
1920 		}
1921 		sc->intr[1] = ptr;
1922 		envy24_updintr(sc, PCMDIR_REC);
1923 	}
1924 	snd_mtxunlock(sc->lock);
1925 
1926 	return;
1927 }
1928 
1929 /*
1930  * Probe and attach the card
1931  */
1932 
1933 static int
1934 envy24_pci_probe(device_t dev)
1935 {
1936 	u_int16_t sv, sd;
1937 	int i;
1938 
1939 #if(0)
1940 	printf("envy24_pci_probe()\n");
1941 #endif
1942 	if (pci_get_device(dev) == PCID_ENVY24 &&
1943 	    pci_get_vendor(dev) == PCIV_ENVY24) {
1944 		sv = pci_get_subvendor(dev);
1945 		sd = pci_get_subdevice(dev);
1946 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
1947 			if (cfg_table[i].subvendor == sv &&
1948 			    cfg_table[i].subdevice == sd) {
1949 				break;
1950 			}
1951 		}
1952 		device_set_desc(dev, cfg_table[i].name);
1953 #if(0)
1954 		printf("envy24_pci_probe(): return 0\n");
1955 #endif
1956 		return 0;
1957 	}
1958 	else {
1959 #if(0)
1960 		printf("envy24_pci_probe(): return ENXIO\n");
1961 #endif
1962 		return ENXIO;
1963 	}
1964 }
1965 
1966 static void
1967 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1968 {
1969 	struct sc_info *sc = (struct sc_info *)arg;
1970 
1971 #if(0)
1972 	device_printf(sc->dev, "envy24_dmapsetmap()\n");
1973 #endif
1974 	if (bootverbose) {
1975 		printf("envy24(play): setmap %lx, %lx; ",
1976 		    (unsigned long)segs->ds_addr,
1977 		    (unsigned long)segs->ds_len);
1978 		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
1979 	}
1980 }
1981 
1982 static void
1983 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1984 {
1985 	struct sc_info *sc = (struct sc_info *)arg;
1986 
1987 #if(0)
1988 	device_printf(sc->dev, "envy24_dmarsetmap()\n");
1989 #endif
1990 	if (bootverbose) {
1991 		printf("envy24(record): setmap %lx, %lx; ",
1992 		    (unsigned long)segs->ds_addr,
1993 		    (unsigned long)segs->ds_len);
1994 		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
1995 	}
1996 }
1997 
1998 static void
1999 envy24_dmafree(struct sc_info *sc)
2000 {
2001 #if(0)
2002 	device_printf(sc->dev, "envy24_dmafree():");
2003 	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2004 	else printf(" sc->rmap(null)");
2005 	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2006 	else printf(" sc->pmap(null)");
2007 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2008 	else printf(" sc->rbuf(null)");
2009 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2010 	else printf(" sc->pbuf(null)\n");
2011 #endif
2012 #if(0)
2013 	if (sc->rmap)
2014 		bus_dmamap_unload(sc->dmat, sc->rmap);
2015 	if (sc->pmap)
2016 		bus_dmamap_unload(sc->dmat, sc->pmap);
2017 	if (sc->rbuf)
2018 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2019 	if (sc->pbuf)
2020 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2021 #else
2022 	bus_dmamap_unload(sc->dmat, sc->rmap);
2023 	bus_dmamap_unload(sc->dmat, sc->pmap);
2024 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2025 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2026 #endif
2027 
2028 	sc->rmap = sc->pmap = NULL;
2029 	sc->pbuf = NULL;
2030 	sc->rbuf = NULL;
2031 
2032 	return;
2033 }
2034 
2035 static int
2036 envy24_dmainit(struct sc_info *sc)
2037 {
2038 	u_int32_t addr;
2039 
2040 #if(0)
2041 	device_printf(sc->dev, "envy24_dmainit()\n");
2042 #endif
2043 	/* init values */
2044 	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2045 	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2046 	sc->pbuf = NULL;
2047 	sc->rbuf = NULL;
2048 	sc->pmap = sc->rmap = NULL;
2049 	sc->blk[0] = sc->blk[1] = 0;
2050 
2051 	/* allocate DMA buffer */
2052 #if(0)
2053 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2054 #endif
2055 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2056 		goto bad;
2057 #if(0)
2058 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2059 #endif
2060 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2061 		goto bad;
2062 #if(0)
2063 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2064 #endif
2065 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2066 		goto bad;
2067 #if(0)
2068 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2069 #endif
2070 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2071 		goto bad;
2072 	bzero(sc->pbuf, sc->psize);
2073 	bzero(sc->rbuf, sc->rsize);
2074 
2075 	/* set values to register */
2076 	addr = vtophys(sc->pbuf);
2077 #if(0)
2078 	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2079 #endif
2080 	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2081 #if(0)
2082 	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2083 	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2084 #endif
2085 	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2086 #if(0)
2087 	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2088 #endif
2089 	addr = vtophys(sc->rbuf);
2090 	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2091 	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2092 
2093 	return 0;
2094  bad:
2095 	envy24_dmafree(sc);
2096 	return ENOSPC;
2097 }
2098 
2099 static void
2100 envy24_putcfg(struct sc_info *sc)
2101 {
2102 	device_printf(sc->dev, "system configuration\n");
2103 	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2104 	    sc->cfg->subvendor, sc->cfg->subdevice);
2105 	printf("  XIN2 Clock Source: ");
2106 	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2107 	case 0x00:
2108 		printf("22.5792MHz(44.1kHz*512)\n");
2109 		break;
2110 	case 0x40:
2111 		printf("16.9344MHz(44.1kHz*384)\n");
2112 		break;
2113 	case 0x80:
2114 		printf("from external clock synthesizer chip\n");
2115 		break;
2116 	default:
2117 		printf("illeagal system setting\n");
2118 	}
2119 	printf("  MPU-401 UART(s) #: ");
2120 	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2121 		printf("2\n");
2122 	else
2123 		printf("1\n");
2124 	printf("  AC'97 codec: ");
2125 	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2126 		printf("not exist\n");
2127 	else
2128 		printf("exist\n");
2129 	printf("  ADC #: ");
2130 	printf("%d\n", sc->adcn);
2131 	printf("  DAC #: ");
2132 	printf("%d\n", sc->dacn);
2133 	printf("  Multi-track converter type: ");
2134 	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2135 		printf("AC'97(SDATA_OUT:");
2136 		if (sc->cfg->acl & PCIM_ACL_OMODE)
2137 			printf("packed");
2138 		else
2139 			printf("split");
2140 		printf("|SDATA_IN:");
2141 		if (sc->cfg->acl & PCIM_ACL_IMODE)
2142 			printf("packed");
2143 		else
2144 			printf("split");
2145 		printf(")\n");
2146 	}
2147 	else {
2148 		printf("I2S(");
2149 		if (sc->cfg->i2s & PCIM_I2S_VOL)
2150 			printf("with volume, ");
2151 		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2152 			printf("96KHz support, ");
2153 		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2154 		case PCIM_I2S_16BIT:
2155 			printf("16bit resolution, ");
2156 			break;
2157 		case PCIM_I2S_18BIT:
2158 			printf("18bit resolution, ");
2159 			break;
2160 		case PCIM_I2S_20BIT:
2161 			printf("20bit resolution, ");
2162 			break;
2163 		case PCIM_I2S_24BIT:
2164 			printf("24bit resolution, ");
2165 			break;
2166 		}
2167 		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2168 	}
2169 	printf("  S/PDIF(IN/OUT): ");
2170 	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2171 		printf("1/");
2172 	else
2173 		printf("0/");
2174 	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2175 		printf("1 ");
2176 	else
2177 		printf("0 ");
2178 	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2179 		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2180 	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2181 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2182 }
2183 
2184 static int
2185 envy24_init(struct sc_info *sc)
2186 {
2187 	u_int32_t data;
2188 #if(0)
2189 	int rtn;
2190 #endif
2191 	int i;
2192 	u_int32_t sv, sd;
2193 
2194 
2195 #if(0)
2196 	device_printf(sc->dev, "envy24_init()\n");
2197 #endif
2198 
2199 	/* reset chip */
2200 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2201 	DELAY(200);
2202 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2203 	DELAY(200);
2204 
2205 	/* legacy hardware disable */
2206 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2207 	data |= PCIM_LAC_DISABLE;
2208 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2209 
2210 	/* check system configuration */
2211 	sc->cfg = NULL;
2212 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2213 		/* 1st: search configuration from table */
2214 		sv = pci_get_subvendor(sc->dev);
2215 		sd = pci_get_subdevice(sc->dev);
2216 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2217 #if(0)
2218 			device_printf(sc->dev, "Set configuration from table\n");
2219 #endif
2220 			sc->cfg = &cfg_table[i];
2221 			break;
2222 		}
2223 	}
2224 	if (sc->cfg == NULL) {
2225 		/* 2nd: read configuration from table */
2226 		sc->cfg = envy24_rom2cfg(sc);
2227 	}
2228 	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2229 	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2230 
2231 	if (1 /* bootverbose */) {
2232 		envy24_putcfg(sc);
2233 	}
2234 
2235 	/* set system configuration */
2236 	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2237 	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2238 	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2239 	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2240 	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2241 	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2242 	envy24_gpiowr(sc, sc->cfg->gpiostate);
2243 	for (i = 0; i < sc->adcn; i++) {
2244 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2245 		sc->cfg->codec->init(sc->adc[i]);
2246 	}
2247 	for (i = 0; i < sc->dacn; i++) {
2248 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2249 		sc->cfg->codec->init(sc->dac[i]);
2250 	}
2251 
2252 	/* initialize DMA buffer */
2253 #if(0)
2254 	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2255 #endif
2256 	if (envy24_dmainit(sc))
2257 		return ENOSPC;
2258 
2259 	/* initialize status */
2260 	sc->run[0] = sc->run[1] = 0;
2261 	sc->intr[0] = sc->intr[1] = 0;
2262 	sc->speed = 0;
2263 	sc->caps[0].fmtlist = envy24_playfmt;
2264 	sc->caps[1].fmtlist = envy24_recfmt;
2265 
2266 	/* set channel router */
2267 	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2268 	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2269 	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2270 
2271 	/* set macro interrupt mask */
2272 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2273 	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2274 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2275 #if(0)
2276 	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2277 #endif
2278 
2279 	return 0;
2280 }
2281 
2282 static int
2283 envy24_alloc_resource(struct sc_info *sc)
2284 {
2285 	/* allocate I/O port resource */
2286 	sc->csid = PCIR_CCS;
2287 	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2288 	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2289 	sc->ddmaid = PCIR_DDMA;
2290 	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2291 	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2292 	sc->dsid = PCIR_DS;
2293 	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2294 	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2295 	sc->mtid = PCIR_MT;
2296 	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2297 	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2298 	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2299 		device_printf(sc->dev, "unable to map IO port space\n");
2300 		return ENXIO;
2301 	}
2302 	sc->cst = rman_get_bustag(sc->cs);
2303 	sc->csh = rman_get_bushandle(sc->cs);
2304 	sc->ddmat = rman_get_bustag(sc->ddma);
2305 	sc->ddmah = rman_get_bushandle(sc->ddma);
2306 	sc->dst = rman_get_bustag(sc->ds);
2307 	sc->dsh = rman_get_bushandle(sc->ds);
2308 	sc->mtt = rman_get_bustag(sc->mt);
2309 	sc->mth = rman_get_bushandle(sc->mt);
2310 #if(0)
2311 	device_printf(sc->dev,
2312 	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2313 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2314 	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2315 	    pci_read_config(sc->dev, PCIR_DS, 4),
2316 	    pci_read_config(sc->dev, PCIR_MT, 4));
2317 #endif
2318 
2319 	/* allocate interupt resource */
2320 	sc->irqid = 0;
2321 	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2322 				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2323 	if (!sc->irq ||
2324 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2325 		device_printf(sc->dev, "unable to map interrupt\n");
2326 		return ENXIO;
2327 	}
2328 
2329 	/* allocate DMA resource */
2330 	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/4, /*boundary*/0,
2331 	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2332 	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2333 	    /*filter*/NULL, /*filterarg*/NULL,
2334 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2335 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2336 	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2337 	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2338 		device_printf(sc->dev, "unable to create dma tag\n");
2339 		return ENXIO;
2340 	}
2341 
2342 	return 0;
2343 }
2344 
2345 static int
2346 envy24_pci_attach(device_t dev)
2347 {
2348 	u_int32_t		data;
2349 	struct sc_info 		*sc;
2350 	char 			status[SND_STATUSLEN];
2351 	char			name[ENVY24_NAMELEN];
2352 	int			err = 0;
2353 	int			i;
2354 
2355 #if(0)
2356 	device_printf(dev, "envy24_pci_attach()\n");
2357 #endif
2358 	/* get sc_info data area */
2359 	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2360 		device_printf(dev, "cannot allocate softc\n");
2361 		return ENXIO;
2362 	}
2363 
2364 	bzero(sc, sizeof(*sc));
2365 	snprintf(name, ENVY24_NAMELEN, "%s:envy24", device_get_nameunit(dev));
2366 	sc->lock = snd_mtxcreate(name, name);
2367 	sc->dev = dev;
2368 
2369 	/* initialize PCI interface */
2370 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2371 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2372 	pci_write_config(dev, PCIR_COMMAND, data, 2);
2373 	data = pci_read_config(dev, PCIR_COMMAND, 2);
2374 
2375 	/* allocate resources */
2376 	err = envy24_alloc_resource(sc);
2377 	if (err) {
2378 		device_printf(dev, "unable to allocate system resources\n");
2379 		goto bad;
2380 	}
2381 
2382 	/* initialize card */
2383 	err = envy24_init(sc);
2384 	if (err) {
2385 		device_printf(dev, "unable to initialize the card\n");
2386 		goto bad;
2387 	}
2388 
2389 	/* set multi track mixer */
2390 	mixer_init(dev, &envy24mixer_class, sc);
2391 
2392 	/* set channel information */
2393 	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2394 	if (err)
2395 		goto bad;
2396 	sc->chnum = 0;
2397 	for (i = 0; i < 5; i++) {
2398 		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2399 		sc->chnum++;
2400 	}
2401 	for (i = 0; i < 2 + sc->adcn; i++) {
2402 		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2403 		sc->chnum++;
2404 	}
2405 
2406 	/* set status iformation */
2407 	snprintf(status, SND_STATUSLEN,
2408 	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2409 	    rman_get_start(sc->cs),
2410 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2411 	    rman_get_start(sc->ddma),
2412 	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2413 	    rman_get_start(sc->ds),
2414 	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2415 	    rman_get_start(sc->mt),
2416 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2417 	    rman_get_start(sc->irq));
2418 	pcm_setstatus(dev, status);
2419 
2420 	return 0;
2421 
2422 bad:
2423 	if (sc->ih)
2424 		bus_teardown_intr(dev, sc->irq, sc->ih);
2425 	if (sc->irq)
2426 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2427 	envy24_dmafree(sc);
2428 	if (sc->dmat)
2429 		bus_dma_tag_destroy(sc->dmat);
2430 	if (sc->cfg->codec->destroy != NULL) {
2431                 for (i = 0; i < sc->adcn; i++)
2432                         sc->cfg->codec->destroy(sc->adc[i]);
2433                 for (i = 0; i < sc->dacn; i++)
2434                         sc->cfg->codec->destroy(sc->dac[i]);
2435         }
2436 	envy24_cfgfree(sc->cfg);
2437 	if (sc->cs)
2438 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2439 	if (sc->ddma)
2440 		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2441 	if (sc->ds)
2442 		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2443 	if (sc->mt)
2444 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2445 	if (sc->lock)
2446 		snd_mtxfree(sc->lock);
2447 	free(sc, M_ENVY24);
2448 	return err;
2449 }
2450 
2451 static int
2452 envy24_pci_detach(device_t dev)
2453 {
2454 	struct sc_info *sc;
2455 	int r;
2456 	int i;
2457 
2458 #if(0)
2459 	device_printf(dev, "envy24_pci_detach()\n");
2460 #endif
2461 	sc = pcm_getdevinfo(dev);
2462 	if (sc == NULL)
2463 		return 0;
2464 	r = pcm_unregister(dev);
2465 	if (r)
2466 		return r;
2467 
2468 	envy24_dmafree(sc);
2469 	if (sc->cfg->codec->destroy != NULL) {
2470 		for (i = 0; i < sc->adcn; i++)
2471 			sc->cfg->codec->destroy(sc->adc[i]);
2472 		for (i = 0; i < sc->dacn; i++)
2473 			sc->cfg->codec->destroy(sc->dac[i]);
2474 	}
2475 	envy24_cfgfree(sc->cfg);
2476 	bus_dma_tag_destroy(sc->dmat);
2477 	bus_teardown_intr(dev, sc->irq, sc->ih);
2478 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2479 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2480 	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2481 	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2482 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2483 	snd_mtxfree(sc->lock);
2484 	free(sc, M_ENVY24);
2485 	return 0;
2486 }
2487 
2488 static device_method_t envy24_methods[] = {
2489 	/* Device interface */
2490 	DEVMETHOD(device_probe,		envy24_pci_probe),
2491 	DEVMETHOD(device_attach,	envy24_pci_attach),
2492 	DEVMETHOD(device_detach,	envy24_pci_detach),
2493 	{ 0, 0 }
2494 };
2495 
2496 static driver_t envy24_driver = {
2497 	"pcm",
2498 	envy24_methods,
2499 #if __FreeBSD_version > 500000
2500 	PCM_SOFTC_SIZE,
2501 #else
2502 	sizeof(struct snddev_info),
2503 #endif
2504 };
2505 
2506 DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2507 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2508 MODULE_DEPEND(snd_envy24, snd_spicds, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2509 MODULE_VERSION(snd_envy24, 1);
2510