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