xref: /freebsd/sys/dev/sound/pci/envy24.c (revision 792251295cdf6c3e1cbb1aa6291434539632912f)
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 	mtx_lock(&sc->lock);
1571 	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1572 	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1573 		mtx_unlock(&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 		mtx_unlock(&sc->lock);
1593 		sndbuf_setup(ch->buffer, ch->data, ch->size);
1594 		mtx_lock(&sc->lock);
1595 		/* these 2 values are dummy */
1596 		ch->unit = 4;
1597 		ch->blk = 10240;
1598 	}
1599 	mtx_unlock(&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 	mtx_lock(&sc->lock);
1614 	free(ch->data, M_ENVY24);
1615 	ch->data = NULL;
1616 	mtx_unlock(&sc->lock);
1617 
1618 	return 0;
1619 }
1620 
1621 static int
envy24chan_setformat(kobj_t obj,void * data,u_int32_t format)1622 envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1623 {
1624 	struct sc_chinfo *ch = data;
1625 	struct sc_info *sc = ch->parent;
1626 	struct envy24_emldma *emltab;
1627 	/* unsigned int bcnt, bsize; */
1628 	int i;
1629 
1630 #if(0)
1631 	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1632 #endif
1633 	mtx_lock(&sc->lock);
1634 	/* check and get format related information */
1635 	if (ch->dir == PCMDIR_PLAY)
1636 		emltab = envy24_pemltab;
1637 	else
1638 		emltab = envy24_remltab;
1639 	if (emltab == NULL) {
1640 		mtx_unlock(&sc->lock);
1641 		return -1;
1642 	}
1643 	for (i = 0; emltab[i].format != 0; i++)
1644 		if (emltab[i].format == format)
1645 			break;
1646 	if (emltab[i].format == 0) {
1647 		mtx_unlock(&sc->lock);
1648 		return -1;
1649 	}
1650 
1651 	/* set format information */
1652 	ch->format = format;
1653 	ch->emldma = emltab[i].emldma;
1654 	if (ch->unit > emltab[i].unit)
1655 		ch->blk *= ch->unit / emltab[i].unit;
1656 	else
1657 		ch->blk /= emltab[i].unit / ch->unit;
1658 	ch->unit = emltab[i].unit;
1659 
1660 	/* set channel buffer information */
1661 	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1662 #if 0
1663 	if (ch->dir == PCMDIR_PLAY)
1664 		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1665 	else
1666 		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1667 	bsize *= ch->unit;
1668 	bcnt = ch->size / bsize;
1669 	sndbuf_resize(ch->buffer, bcnt, bsize);
1670 #endif
1671 	mtx_unlock(&sc->lock);
1672 
1673 #if(0)
1674 	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1675 #endif
1676 	return 0;
1677 }
1678 
1679 /*
1680   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1681   of speed information value. And real hardware speed setting is done
1682   at start triggered(see envy24chan_trigger()). So, at this function
1683   is called, any value that ENVY24 can use is able to set. But, at
1684   start triggerd, some other channel is running, and that channel's
1685   speed isn't same with, then trigger function will fail.
1686 */
1687 static u_int32_t
envy24chan_setspeed(kobj_t obj,void * data,u_int32_t speed)1688 envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1689 {
1690 	struct sc_chinfo *ch = data;
1691 	u_int32_t val, prev;
1692 	int i;
1693 
1694 #if(0)
1695 	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1696 #endif
1697 	prev = 0x7fffffff;
1698 	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1699 		if (abs(val - speed) < abs(prev - speed))
1700 			prev = val;
1701 		else
1702 			break;
1703 	}
1704 	ch->speed = prev;
1705 
1706 #if(0)
1707 	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1708 #endif
1709 	return ch->speed;
1710 }
1711 
1712 static u_int32_t
envy24chan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)1713 envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1714 {
1715 	struct sc_chinfo *ch = data;
1716 	/* struct sc_info *sc = ch->parent; */
1717 	u_int32_t size, prev;
1718         unsigned int bcnt, bsize;
1719 
1720 #if(0)
1721 	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1722 #endif
1723 	prev = 0x7fffffff;
1724 	/* mtx_lock(&sc->lock); */
1725 	for (size = ch->size / 2; size > 0; size /= 2) {
1726 		if (abs(size - blocksize) < abs(prev - blocksize))
1727 			prev = size;
1728 		else
1729 			break;
1730 	}
1731 
1732 	ch->blk = prev / ch->unit;
1733 	if (ch->dir == PCMDIR_PLAY)
1734 		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1735 	else
1736 		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1737 	/* set channel buffer information */
1738 	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1739         if (ch->dir == PCMDIR_PLAY)
1740                 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1741         else
1742                 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1743         bsize *= ch->unit;
1744         bcnt = ch->size / bsize;
1745         sndbuf_resize(ch->buffer, bcnt, bsize);
1746 	/* mtx_unlock(&sc->lock); */
1747 
1748 #if(0)
1749 	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1750 #endif
1751 	return prev;
1752 }
1753 
1754 /* semantic note: must start at beginning of buffer */
1755 static int
envy24chan_trigger(kobj_t obj,void * data,int go)1756 envy24chan_trigger(kobj_t obj, void *data, int go)
1757 {
1758 	struct sc_chinfo *ch = data;
1759 	struct sc_info *sc = ch->parent;
1760 	u_int32_t ptr;
1761 	int slot;
1762 	int error = 0;
1763 #if 0
1764 	int i;
1765 
1766 	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1767 #endif
1768 	mtx_lock(&sc->lock);
1769 	if (ch->dir == PCMDIR_PLAY)
1770 		slot = 0;
1771 	else
1772 		slot = 1;
1773 	switch (go) {
1774 	case PCMTRIG_START:
1775 #if(0)
1776 		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1777 #endif
1778 		/* check or set channel speed */
1779 		if (sc->run[0] == 0 && sc->run[1] == 0) {
1780 			sc->speed = envy24_setspeed(sc, ch->speed);
1781 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1782 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1783 		}
1784 		else if (ch->speed != 0 && ch->speed != sc->speed) {
1785 			error = -1;
1786 			goto fail;
1787 		}
1788 		if (ch->speed == 0)
1789 			ch->channel->speed = sc->speed;
1790 		/* start or enable channel */
1791 		sc->run[slot]++;
1792 		if (sc->run[slot] == 1) {
1793 			/* first channel */
1794 			ch->offset = 0;
1795 			sc->blk[slot] = ch->blk;
1796 		}
1797 		else {
1798 			ptr = envy24_gethwptr(sc, ch->dir);
1799 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1800 			    (ch->size / 4)) * 4 / ch->unit;
1801 			if (ch->blk < sc->blk[slot])
1802 				sc->blk[slot] = ch->blk;
1803 		}
1804 		if (ch->dir == PCMDIR_PLAY) {
1805 			ch->emldma(ch);
1806 			envy24_setvolume(sc, ch->num);
1807 		}
1808 		envy24_updintr(sc, ch->dir);
1809 		if (sc->run[slot] == 1)
1810 			envy24_start(sc, ch->dir);
1811 		ch->run = 1;
1812 		break;
1813 	case PCMTRIG_EMLDMAWR:
1814 #if(0)
1815 		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1816 #endif
1817 		if (ch->run != 1) {
1818 			error = -1;
1819 			goto fail;
1820 		}
1821 		ch->emldma(ch);
1822 		break;
1823 	case PCMTRIG_EMLDMARD:
1824 #if(0)
1825 		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1826 #endif
1827 		if (ch->run != 1) {
1828 			error = -1;
1829 			goto fail;
1830 		}
1831 		ch->emldma(ch);
1832 		break;
1833 	case PCMTRIG_ABORT:
1834 		if (ch->run) {
1835 #if(0)
1836 		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1837 #endif
1838 		ch->run = 0;
1839 		sc->run[slot]--;
1840 		if (ch->dir == PCMDIR_PLAY)
1841 			envy24_mutevolume(sc, ch->num);
1842 		if (sc->run[slot] == 0) {
1843 			envy24_stop(sc, ch->dir);
1844 			sc->intr[slot] = 0;
1845 		}
1846 #if 0
1847 		else if (ch->blk == sc->blk[slot]) {
1848 			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1849 			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1850 				if (sc->chan[i].dir == ch->dir &&
1851 				    sc->chan[i].run == 1 &&
1852 				    sc->chan[i].blk < sc->blk[slot])
1853 					sc->blk[slot] = sc->chan[i].blk;
1854 			}
1855 			if (ch->blk != sc->blk[slot])
1856 				envy24_updintr(sc, ch->dir);
1857 		}
1858 #endif
1859 		}
1860 		break;
1861 	}
1862 fail:
1863 	mtx_unlock(&sc->lock);
1864 	return (error);
1865 }
1866 
1867 static u_int32_t
envy24chan_getptr(kobj_t obj,void * data)1868 envy24chan_getptr(kobj_t obj, void *data)
1869 {
1870 	struct sc_chinfo *ch = data;
1871 	struct sc_info *sc = ch->parent;
1872 	u_int32_t ptr, rtn;
1873 
1874 #if(0)
1875 	device_printf(sc->dev, "envy24chan_getptr()\n");
1876 #endif
1877 	mtx_lock(&sc->lock);
1878 	ptr = envy24_gethwptr(sc, ch->dir);
1879 	rtn = ptr * ch->unit;
1880 	mtx_unlock(&sc->lock);
1881 
1882 #if(0)
1883 	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1884 	    rtn);
1885 #endif
1886 	return rtn;
1887 }
1888 
1889 static struct pcmchan_caps *
envy24chan_getcaps(kobj_t obj,void * data)1890 envy24chan_getcaps(kobj_t obj, void *data)
1891 {
1892 	struct sc_chinfo *ch = data;
1893 	struct sc_info *sc = ch->parent;
1894 	struct pcmchan_caps *rtn;
1895 
1896 #if(0)
1897 	device_printf(sc->dev, "envy24chan_getcaps()\n");
1898 #endif
1899 	mtx_lock(&sc->lock);
1900 	if (ch->dir == PCMDIR_PLAY) {
1901 		if (sc->run[0] == 0)
1902 			rtn = &envy24_playcaps;
1903 		else
1904 			rtn = &sc->caps[0];
1905 	}
1906 	else {
1907 		if (sc->run[1] == 0)
1908 			rtn = &envy24_reccaps;
1909 		else
1910 			rtn = &sc->caps[1];
1911 	}
1912 	mtx_unlock(&sc->lock);
1913 
1914 	return rtn;
1915 }
1916 
1917 static kobj_method_t envy24chan_methods[] = {
1918 	KOBJMETHOD(channel_init,		envy24chan_init),
1919 	KOBJMETHOD(channel_free,		envy24chan_free),
1920 	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1921 	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1922 	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1923 	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1924 	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1925 	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1926 	KOBJMETHOD_END
1927 };
1928 CHANNEL_DECLARE(envy24chan);
1929 
1930 /* -------------------------------------------------------------------- */
1931 
1932 /* mixer interface */
1933 
1934 static int
envy24mixer_init(struct snd_mixer * m)1935 envy24mixer_init(struct snd_mixer *m)
1936 {
1937 	struct sc_info *sc = mix_getdevinfo(m);
1938 
1939 #if(0)
1940 	device_printf(sc->dev, "envy24mixer_init()\n");
1941 #endif
1942 	if (sc == NULL)
1943 		return -1;
1944 
1945 	/* set volume control rate */
1946 	mtx_lock(&sc->lock);
1947 	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1948 
1949 	mix_setdevs(m, ENVY24_MIX_MASK);
1950 	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1951 	mtx_unlock(&sc->lock);
1952 
1953 	return 0;
1954 }
1955 
1956 static int
envy24mixer_reinit(struct snd_mixer * m)1957 envy24mixer_reinit(struct snd_mixer *m)
1958 {
1959 	struct sc_info *sc = mix_getdevinfo(m);
1960 
1961 	if (sc == NULL)
1962 		return -1;
1963 #if(0)
1964 	device_printf(sc->dev, "envy24mixer_reinit()\n");
1965 #endif
1966 
1967 	return 0;
1968 }
1969 
1970 static int
envy24mixer_uninit(struct snd_mixer * m)1971 envy24mixer_uninit(struct snd_mixer *m)
1972 {
1973 	struct sc_info *sc = mix_getdevinfo(m);
1974 
1975 	if (sc == NULL)
1976 		return -1;
1977 #if(0)
1978 	device_printf(sc->dev, "envy24mixer_uninit()\n");
1979 #endif
1980 
1981 	return 0;
1982 }
1983 
1984 static int
envy24mixer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)1985 envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1986 {
1987 	struct sc_info *sc = mix_getdevinfo(m);
1988 	int ch = envy24_mixmap[dev];
1989 	int hwch;
1990 	int i;
1991 
1992 	if (sc == NULL)
1993 		return -1;
1994 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1995 		return -1;
1996 	if (dev != 0 && ch == -1)
1997 		return -1;
1998 	hwch = envy24_chanmap[ch];
1999 #if(0)
2000 	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
2001 	    dev, left, right);
2002 #endif
2003 
2004 	mtx_lock(&sc->lock);
2005 	if (dev == 0) {
2006 		for (i = 0; i < sc->dacn; i++) {
2007 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
2008 		}
2009 	}
2010 	else {
2011 		/* set volume value for hardware */
2012 		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
2013 			sc->left[hwch] = ENVY24_VOL_MUTE;
2014 		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
2015 			sc->right[hwch] = ENVY24_VOL_MUTE;
2016 
2017 		/* set volume for record channel and running play channel */
2018 		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
2019 			envy24_setvolume(sc, hwch);
2020 	}
2021 	mtx_unlock(&sc->lock);
2022 
2023 	return right << 8 | left;
2024 }
2025 
2026 static u_int32_t
envy24mixer_setrecsrc(struct snd_mixer * m,u_int32_t src)2027 envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
2028 {
2029 	struct sc_info *sc = mix_getdevinfo(m);
2030 	int ch = envy24_mixmap[src];
2031 #if(0)
2032 	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
2033 #endif
2034 
2035 	if (ch > ENVY24_CHAN_PLAY_SPDIF)
2036 		sc->src = ch;
2037 	return src;
2038 }
2039 
2040 static kobj_method_t envy24mixer_methods[] = {
2041 	KOBJMETHOD(mixer_init,		envy24mixer_init),
2042 	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
2043 	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
2044 	KOBJMETHOD(mixer_set,		envy24mixer_set),
2045 	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
2046 	KOBJMETHOD_END
2047 };
2048 MIXER_DECLARE(envy24mixer);
2049 
2050 /* -------------------------------------------------------------------- */
2051 
2052 /* The interrupt handler */
2053 static void
envy24_intr(void * p)2054 envy24_intr(void *p)
2055 {
2056 	struct sc_info *sc = (struct sc_info *)p;
2057 	struct sc_chinfo *ch;
2058 	u_int32_t ptr, dsize, feed;
2059 	int i;
2060 
2061 #if(0)
2062 	device_printf(sc->dev, "envy24_intr()\n");
2063 #endif
2064 	mtx_lock(&sc->lock);
2065 	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2066 #if(0)
2067 		device_printf(sc->dev, "envy24_intr(): play\n");
2068 #endif
2069 		dsize = sc->psize / 4;
2070 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2071 #if(0)
2072 		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2073 #endif
2074 		ptr -= ptr % sc->blk[0];
2075 		feed = (ptr + dsize - sc->intr[0]) % dsize;
2076 #if(0)
2077 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2078 #endif
2079 		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2080 			ch = &sc->chan[i];
2081 #if(0)
2082 			if (ch->run)
2083 				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2084 #endif
2085 			if (ch->run && ch->blk <= feed) {
2086 				mtx_unlock(&sc->lock);
2087 				chn_intr(ch->channel);
2088 				mtx_lock(&sc->lock);
2089 			}
2090 		}
2091 		sc->intr[0] = ptr;
2092 		envy24_updintr(sc, PCMDIR_PLAY);
2093 	}
2094 	if (envy24_checkintr(sc, PCMDIR_REC)) {
2095 #if(0)
2096 		device_printf(sc->dev, "envy24_intr(): rec\n");
2097 #endif
2098 		dsize = sc->rsize / 4;
2099 		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2100 		ptr -= ptr % sc->blk[1];
2101 		feed = (ptr + dsize - sc->intr[1]) % dsize;
2102 		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2103 			ch = &sc->chan[i];
2104 			if (ch->run && ch->blk <= feed) {
2105 				mtx_unlock(&sc->lock);
2106 				chn_intr(ch->channel);
2107 				mtx_lock(&sc->lock);
2108 			}
2109 		}
2110 		sc->intr[1] = ptr;
2111 		envy24_updintr(sc, PCMDIR_REC);
2112 	}
2113 	mtx_unlock(&sc->lock);
2114 
2115 	return;
2116 }
2117 
2118 /*
2119  * Probe and attach the card
2120  */
2121 
2122 static int
envy24_pci_probe(device_t dev)2123 envy24_pci_probe(device_t dev)
2124 {
2125 	u_int16_t sv, sd;
2126 	int i;
2127 
2128 #if(0)
2129 	printf("envy24_pci_probe()\n");
2130 #endif
2131 	if (pci_get_device(dev) == PCID_ENVY24 &&
2132 	    pci_get_vendor(dev) == PCIV_ENVY24) {
2133 		sv = pci_get_subvendor(dev);
2134 		sd = pci_get_subdevice(dev);
2135 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2136 			if (cfg_table[i].subvendor == sv &&
2137 			    cfg_table[i].subdevice == sd) {
2138 				break;
2139 			}
2140 		}
2141 		device_set_desc(dev, cfg_table[i].name);
2142 #if(0)
2143 		printf("envy24_pci_probe(): return 0\n");
2144 #endif
2145 		return 0;
2146 	}
2147 	else {
2148 #if(0)
2149 		printf("envy24_pci_probe(): return ENXIO\n");
2150 #endif
2151 		return ENXIO;
2152 	}
2153 }
2154 
2155 static void
envy24_dmapsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2156 envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2157 {
2158 	struct sc_info *sc = (struct sc_info *)arg;
2159 
2160 	sc->paddr = segs->ds_addr;
2161 #if(0)
2162 	device_printf(sc->dev, "envy24_dmapsetmap()\n");
2163 	if (bootverbose) {
2164 		printf("envy24(play): setmap %lx, %lx; ",
2165 		    (unsigned long)segs->ds_addr,
2166 		    (unsigned long)segs->ds_len);
2167 		printf("%p -> %lx\n", sc->pmap, sc->paddr);
2168 	}
2169 #endif
2170 }
2171 
2172 static void
envy24_dmarsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)2173 envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2174 {
2175 	struct sc_info *sc = (struct sc_info *)arg;
2176 
2177 	sc->raddr = segs->ds_addr;
2178 #if(0)
2179 	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2180 	if (bootverbose) {
2181 		printf("envy24(record): setmap %lx, %lx; ",
2182 		    (unsigned long)segs->ds_addr,
2183 		    (unsigned long)segs->ds_len);
2184 		printf("%p -> %lx\n", sc->rmap, sc->raddr);
2185 	}
2186 #endif
2187 }
2188 
2189 static void
envy24_dmafree(struct sc_info * sc)2190 envy24_dmafree(struct sc_info *sc)
2191 {
2192 #if(0)
2193 	device_printf(sc->dev, "envy24_dmafree():");
2194 	printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
2195 	printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
2196 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2197 	else printf(" sc->rbuf(null)");
2198 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2199 	else printf(" sc->pbuf(null)\n");
2200 #endif
2201 #if(0)
2202 	if (sc->raddr)
2203 		bus_dmamap_unload(sc->dmat, sc->rmap);
2204 	if (sc->paddr)
2205 		bus_dmamap_unload(sc->dmat, sc->pmap);
2206 	if (sc->rbuf)
2207 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2208 	if (sc->pbuf)
2209 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2210 #else
2211 	bus_dmamap_unload(sc->dmat, sc->rmap);
2212 	bus_dmamap_unload(sc->dmat, sc->pmap);
2213 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2214 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2215 #endif
2216 
2217 	sc->raddr = sc->paddr = 0;
2218 	sc->pbuf = NULL;
2219 	sc->rbuf = NULL;
2220 
2221 	return;
2222 }
2223 
2224 static int
envy24_dmainit(struct sc_info * sc)2225 envy24_dmainit(struct sc_info *sc)
2226 {
2227 
2228 #if(0)
2229 	device_printf(sc->dev, "envy24_dmainit()\n");
2230 #endif
2231 	/* init values */
2232 	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2233 	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2234 	sc->pbuf = NULL;
2235 	sc->rbuf = NULL;
2236 	sc->paddr = sc->raddr = 0;
2237 	sc->blk[0] = sc->blk[1] = 0;
2238 
2239 	/* allocate DMA buffer */
2240 #if(0)
2241 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2242 #endif
2243 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2244 		goto bad;
2245 #if(0)
2246 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2247 #endif
2248 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2249 		goto bad;
2250 #if(0)
2251 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2252 #endif
2253 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize,
2254 	    envy24_dmapsetmap, sc, BUS_DMA_NOWAIT))
2255 		goto bad;
2256 #if(0)
2257 	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2258 #endif
2259 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize,
2260 	    envy24_dmarsetmap, sc, BUS_DMA_NOWAIT))
2261 		goto bad;
2262 	bzero(sc->pbuf, sc->psize);
2263 	bzero(sc->rbuf, sc->rsize);
2264 
2265 	/* set values to register */
2266 #if(0)
2267 	device_printf(sc->dev, "paddr(0x%08x)\n", sc->paddr);
2268 #endif
2269 	envy24_wrmt(sc, ENVY24_MT_PADDR, sc->paddr, 4);
2270 #if(0)
2271 	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2272 	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2273 #endif
2274 	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2275 #if(0)
2276 	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2277 #endif
2278 	envy24_wrmt(sc, ENVY24_MT_RADDR, sc->raddr, 4);
2279 	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2280 
2281 	return 0;
2282  bad:
2283 	envy24_dmafree(sc);
2284 	return ENOSPC;
2285 }
2286 
2287 static void
envy24_putcfg(struct sc_info * sc)2288 envy24_putcfg(struct sc_info *sc)
2289 {
2290 	device_printf(sc->dev, "system configuration\n");
2291 	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2292 	    sc->cfg->subvendor, sc->cfg->subdevice);
2293 	printf("  XIN2 Clock Source: ");
2294 	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2295 	case 0x00:
2296 		printf("22.5792MHz(44.1kHz*512)\n");
2297 		break;
2298 	case 0x40:
2299 		printf("16.9344MHz(44.1kHz*384)\n");
2300 		break;
2301 	case 0x80:
2302 		printf("from external clock synthesizer chip\n");
2303 		break;
2304 	default:
2305 		printf("illegal system setting\n");
2306 	}
2307 	printf("  MPU-401 UART(s) #: ");
2308 	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2309 		printf("2\n");
2310 	else
2311 		printf("1\n");
2312 	printf("  AC'97 codec: ");
2313 	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2314 		printf("not exist\n");
2315 	else
2316 		printf("exist\n");
2317 	printf("  ADC #: ");
2318 	printf("%d\n", sc->adcn);
2319 	printf("  DAC #: ");
2320 	printf("%d\n", sc->dacn);
2321 	printf("  Multi-track converter type: ");
2322 	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2323 		printf("AC'97(SDATA_OUT:");
2324 		if (sc->cfg->acl & PCIM_ACL_OMODE)
2325 			printf("packed");
2326 		else
2327 			printf("split");
2328 		printf("|SDATA_IN:");
2329 		if (sc->cfg->acl & PCIM_ACL_IMODE)
2330 			printf("packed");
2331 		else
2332 			printf("split");
2333 		printf(")\n");
2334 	}
2335 	else {
2336 		printf("I2S(");
2337 		if (sc->cfg->i2s & PCIM_I2S_VOL)
2338 			printf("with volume, ");
2339 		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2340 			printf("96KHz support, ");
2341 		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2342 		case PCIM_I2S_16BIT:
2343 			printf("16bit resolution, ");
2344 			break;
2345 		case PCIM_I2S_18BIT:
2346 			printf("18bit resolution, ");
2347 			break;
2348 		case PCIM_I2S_20BIT:
2349 			printf("20bit resolution, ");
2350 			break;
2351 		case PCIM_I2S_24BIT:
2352 			printf("24bit resolution, ");
2353 			break;
2354 		}
2355 		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2356 	}
2357 	printf("  S/PDIF(IN/OUT): ");
2358 	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2359 		printf("1/");
2360 	else
2361 		printf("0/");
2362 	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2363 		printf("1 ");
2364 	else
2365 		printf("0 ");
2366 	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2367 		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2368 	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2369 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2370 }
2371 
2372 static int
envy24_init(struct sc_info * sc)2373 envy24_init(struct sc_info *sc)
2374 {
2375 	u_int32_t data;
2376 #if(0)
2377 	int rtn;
2378 #endif
2379 	int i;
2380 	u_int32_t sv, sd;
2381 
2382 #if(0)
2383 	device_printf(sc->dev, "envy24_init()\n");
2384 #endif
2385 
2386 	/* reset chip */
2387 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2388 	DELAY(200);
2389 	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2390 	DELAY(200);
2391 
2392 	/* legacy hardware disable */
2393 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2394 	data |= PCIM_LAC_DISABLE;
2395 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2396 
2397 	/* check system configuration */
2398 	sc->cfg = NULL;
2399 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2400 		/* 1st: search configuration from table */
2401 		sv = pci_get_subvendor(sc->dev);
2402 		sd = pci_get_subdevice(sc->dev);
2403 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2404 #if(0)
2405 			device_printf(sc->dev, "Set configuration from table\n");
2406 #endif
2407 			sc->cfg = &cfg_table[i];
2408 			break;
2409 		}
2410 	}
2411 	if (sc->cfg == NULL) {
2412 		/* 2nd: read configuration from table */
2413 		sc->cfg = envy24_rom2cfg(sc);
2414 	}
2415 	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2416 	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2417 
2418 	if (1 /* bootverbose */) {
2419 		envy24_putcfg(sc);
2420 	}
2421 
2422 	/* set system configuration */
2423 	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2424 	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2425 	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2426 	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2427 	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2428 	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2429 	envy24_gpiowr(sc, sc->cfg->gpiostate);
2430 	for (i = 0; i < sc->adcn; i++) {
2431 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2432 		sc->cfg->codec->init(sc->adc[i]);
2433 	}
2434 	for (i = 0; i < sc->dacn; i++) {
2435 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2436 		sc->cfg->codec->init(sc->dac[i]);
2437 	}
2438 
2439 	/* initialize DMA buffer */
2440 #if(0)
2441 	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2442 #endif
2443 	if (envy24_dmainit(sc))
2444 		return ENOSPC;
2445 
2446 	/* initialize status */
2447 	sc->run[0] = sc->run[1] = 0;
2448 	sc->intr[0] = sc->intr[1] = 0;
2449 	sc->speed = 0;
2450 	sc->caps[0].fmtlist = envy24_playfmt;
2451 	sc->caps[1].fmtlist = envy24_recfmt;
2452 
2453 	/* set channel router */
2454 	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2455 	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2456 	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2457 
2458 	/* set macro interrupt mask */
2459 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2460 	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2461 	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2462 #if(0)
2463 	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2464 #endif
2465 
2466 	return 0;
2467 }
2468 
2469 static int
envy24_alloc_resource(struct sc_info * sc)2470 envy24_alloc_resource(struct sc_info *sc)
2471 {
2472 	/* allocate I/O port resource */
2473 	sc->csid = PCIR_CCS;
2474 	sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2475 	    &sc->csid, RF_ACTIVE);
2476 	sc->ddmaid = PCIR_DDMA;
2477 	sc->ddma = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2478 	    &sc->ddmaid, RF_ACTIVE);
2479 	sc->dsid = PCIR_DS;
2480 	sc->ds = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2481 	    &sc->dsid, RF_ACTIVE);
2482 	sc->mtid = PCIR_MT;
2483 	sc->mt = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT,
2484 	    &sc->mtid, RF_ACTIVE);
2485 	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2486 		device_printf(sc->dev, "unable to map IO port space\n");
2487 		return ENXIO;
2488 	}
2489 	sc->cst = rman_get_bustag(sc->cs);
2490 	sc->csh = rman_get_bushandle(sc->cs);
2491 	sc->ddmat = rman_get_bustag(sc->ddma);
2492 	sc->ddmah = rman_get_bushandle(sc->ddma);
2493 	sc->dst = rman_get_bustag(sc->ds);
2494 	sc->dsh = rman_get_bushandle(sc->ds);
2495 	sc->mtt = rman_get_bustag(sc->mt);
2496 	sc->mth = rman_get_bushandle(sc->mt);
2497 #if(0)
2498 	device_printf(sc->dev,
2499 	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2500 	    pci_read_config(sc->dev, PCIR_CCS, 4),
2501 	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2502 	    pci_read_config(sc->dev, PCIR_DS, 4),
2503 	    pci_read_config(sc->dev, PCIR_MT, 4));
2504 #endif
2505 
2506 	/* allocate interrupt resource */
2507 	sc->irqid = 0;
2508 	sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid,
2509 				 RF_ACTIVE | RF_SHAREABLE);
2510 	if (!sc->irq ||
2511 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2512 		device_printf(sc->dev, "unable to map interrupt\n");
2513 		return ENXIO;
2514 	}
2515 
2516 	/* allocate DMA resource */
2517 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2518 	    /*alignment*/4,
2519 	    /*boundary*/0,
2520 	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2521 	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2522 	    /*filter*/NULL, /*filterarg*/NULL,
2523 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2524 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2525 	    /*flags*/0, /*lockfunc*/NULL, /*lockarg*/NULL,
2526 	    &sc->dmat) != 0) {
2527 		device_printf(sc->dev, "unable to create dma tag\n");
2528 		return ENXIO;
2529 	}
2530 
2531 	return 0;
2532 }
2533 
2534 static int
envy24_pci_attach(device_t dev)2535 envy24_pci_attach(device_t dev)
2536 {
2537 	struct sc_info 		*sc;
2538 	char 			status[SND_STATUSLEN];
2539 	int			err = 0;
2540 	int			i;
2541 
2542 #if(0)
2543 	device_printf(dev, "envy24_pci_attach()\n");
2544 #endif
2545 	/* get sc_info data area */
2546 	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2547 		device_printf(dev, "cannot allocate softc\n");
2548 		return ENXIO;
2549 	}
2550 
2551 	bzero(sc, sizeof(*sc));
2552 	mtx_init(&sc->lock, device_get_nameunit(dev), "snd_envy24 softc",
2553 	    MTX_DEF);
2554 	sc->dev = dev;
2555 
2556 	/* initialize PCI interface */
2557 	pci_enable_busmaster(dev);
2558 
2559 	/* allocate resources */
2560 	err = envy24_alloc_resource(sc);
2561 	if (err) {
2562 		device_printf(dev, "unable to allocate system resources\n");
2563 		goto bad;
2564 	}
2565 
2566 	/* initialize card */
2567 	err = envy24_init(sc);
2568 	if (err) {
2569 		device_printf(dev, "unable to initialize the card\n");
2570 		goto bad;
2571 	}
2572 
2573 	/* set multi track mixer */
2574 	mixer_init(dev, &envy24mixer_class, sc);
2575 
2576 	/* set channel information */
2577 	pcm_init(dev, sc);
2578 	sc->chnum = 0;
2579 	for (i = 0; i < 5; i++) {
2580 		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2581 		sc->chnum++;
2582 	}
2583 	for (i = 0; i < 2 + sc->adcn; i++) {
2584 		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2585 		sc->chnum++;
2586 	}
2587 
2588 	/* set status iformation */
2589 	snprintf(status, SND_STATUSLEN,
2590 	    "port 0x%jx:%jd,0x%jx:%jd,0x%jx:%jd,0x%jx:%jd irq %jd on %s",
2591 	    rman_get_start(sc->cs),
2592 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2593 	    rman_get_start(sc->ddma),
2594 	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2595 	    rman_get_start(sc->ds),
2596 	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2597 	    rman_get_start(sc->mt),
2598 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2599 	    rman_get_start(sc->irq),
2600 	    device_get_nameunit(device_get_parent(dev)));
2601 	if (pcm_register(dev, status))
2602 		goto bad;
2603 
2604 	return 0;
2605 
2606 bad:
2607 	if (sc->ih)
2608 		bus_teardown_intr(dev, sc->irq, sc->ih);
2609 	if (sc->irq)
2610 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2611 	envy24_dmafree(sc);
2612 	if (sc->dmat)
2613 		bus_dma_tag_destroy(sc->dmat);
2614 	if (sc->cfg->codec->destroy != NULL) {
2615                 for (i = 0; i < sc->adcn; i++)
2616                         sc->cfg->codec->destroy(sc->adc[i]);
2617                 for (i = 0; i < sc->dacn; i++)
2618                         sc->cfg->codec->destroy(sc->dac[i]);
2619         }
2620 	envy24_cfgfree(sc->cfg);
2621 	if (sc->cs)
2622 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2623 	if (sc->ddma)
2624 		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2625 	if (sc->ds)
2626 		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2627 	if (sc->mt)
2628 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2629 	mtx_destroy(&sc->lock);
2630 	free(sc, M_ENVY24);
2631 	return err;
2632 }
2633 
2634 static int
envy24_pci_detach(device_t dev)2635 envy24_pci_detach(device_t dev)
2636 {
2637 	struct sc_info *sc;
2638 	int r;
2639 	int i;
2640 
2641 #if(0)
2642 	device_printf(dev, "envy24_pci_detach()\n");
2643 #endif
2644 	sc = pcm_getdevinfo(dev);
2645 	if (sc == NULL)
2646 		return 0;
2647 	r = pcm_unregister(dev);
2648 	if (r)
2649 		return r;
2650 
2651 	envy24_dmafree(sc);
2652 	if (sc->cfg->codec->destroy != NULL) {
2653 		for (i = 0; i < sc->adcn; i++)
2654 			sc->cfg->codec->destroy(sc->adc[i]);
2655 		for (i = 0; i < sc->dacn; i++)
2656 			sc->cfg->codec->destroy(sc->dac[i]);
2657 	}
2658 	envy24_cfgfree(sc->cfg);
2659 	bus_dma_tag_destroy(sc->dmat);
2660 	bus_teardown_intr(dev, sc->irq, sc->ih);
2661 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2662 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2663 	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2664 	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2665 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2666 	mtx_destroy(&sc->lock);
2667 	free(sc, M_ENVY24);
2668 	return 0;
2669 }
2670 
2671 static device_method_t envy24_methods[] = {
2672 	/* Device interface */
2673 	DEVMETHOD(device_probe,		envy24_pci_probe),
2674 	DEVMETHOD(device_attach,	envy24_pci_attach),
2675 	DEVMETHOD(device_detach,	envy24_pci_detach),
2676 	{ 0, 0 }
2677 };
2678 
2679 static driver_t envy24_driver = {
2680 	"pcm",
2681 	envy24_methods,
2682 	PCM_SOFTC_SIZE,
2683 };
2684 
2685 DRIVER_MODULE(snd_envy24, pci, envy24_driver, 0, 0);
2686 MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2687 MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2688 MODULE_VERSION(snd_envy24, 1);
2689