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