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