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