xref: /openbsd-src/sys/dev/pci/envy.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: envy.c,v 1.31 2009/11/02 05:54:16 ratchov Exp $	*/
2 /*
3  * Copyright (c) 2007 Alexandre Ratchov <alex@caoua.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * TODO:
20  *
21  * - add nspdin, nspdout, to struct envy_card
22  *
23  * - use eeprom version rather isht flag
24  *
25  * - implement HT mixer, midi uart, spdif, init ADC/DACs for >48kHz modes
26  *
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/ioctl.h>
33 #include <sys/audioio.h>
34 #include <sys/malloc.h>
35 #include <dev/pci/pcivar.h>
36 #include <dev/pci/pcidevs.h>
37 #include <dev/pci/envyvar.h>
38 #include <dev/pci/envyreg.h>
39 #include <dev/audio_if.h>
40 #include <machine/bus.h>
41 
42 #ifdef ENVY_DEBUG
43 #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0)
44 #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0)
45 int envydebug = 1;
46 #else
47 #define DPRINTF(...) do {} while(0)
48 #define DPRINTFN(n, ...) do {} while(0)
49 #endif
50 #define DEVNAME(sc) ((sc)->dev.dv_xname)
51 
52 int  envymatch(struct device *, void *, void *);
53 void envyattach(struct device *, struct device *, void *);
54 int  envydetach(struct device *, int);
55 
56 int  envy_ccs_read(struct envy_softc *, int);
57 void envy_ccs_write(struct envy_softc *, int, int);
58 int  envy_cci_read(struct envy_softc *, int);
59 void envy_cci_write(struct envy_softc *, int, int);
60 void envy_i2c_wait(struct envy_softc *);
61 int  envy_i2c_read(struct envy_softc *, int, int);
62 void envy_i2c_write(struct envy_softc *, int, int, int);
63 int  envy_gpio_getstate(struct envy_softc *);
64 void envy_gpio_setstate(struct envy_softc *, int);
65 int  envy_gpio_getmask(struct envy_softc *);
66 void envy_gpio_setmask(struct envy_softc *, int);
67 int  envy_gpio_getdir(struct envy_softc *);
68 void envy_gpio_setdir(struct envy_softc *, int);
69 void envy_gpio_i2c_start_bit(struct envy_softc *, int, int);
70 void envy_gpio_i2c_stop_bit(struct envy_softc *, int, int);
71 void envy_gpio_i2c_byte_out(struct envy_softc *, int, int, int);
72 int  envy_eeprom_gpioxxx(struct envy_softc *, int);
73 void envy_reset(struct envy_softc *);
74 int  envy_codec_read(struct envy_softc *, int, int);
75 void envy_codec_write(struct envy_softc *, int, int, int);
76 int  envy_intr(void *);
77 
78 int envy_lineout_getsrc(struct envy_softc *, int);
79 void envy_lineout_setsrc(struct envy_softc *, int, int);
80 int envy_spdout_getsrc(struct envy_softc *, int);
81 void envy_spdout_setsrc(struct envy_softc *, int, int);
82 void envy_mon_getvol(struct envy_softc *, int, int, int *);
83 void envy_mon_setvol(struct envy_softc *, int, int, int);
84 
85 int envy_open(void *, int);
86 void envy_close(void *);
87 void *envy_allocm(void *, int, size_t, int, int);
88 void envy_freem(void *, void *, int);
89 int envy_query_encoding(void *, struct audio_encoding *);
90 int envy_set_params(void *, int, int, struct audio_params *,
91     struct audio_params *);
92 int envy_round_blocksize(void *, int);
93 size_t envy_round_buffersize(void *, int, size_t);
94 int envy_trigger_output(void *, void *, void *, int,
95     void (*)(void *), void *, struct audio_params *);
96 int envy_trigger_input(void *, void *, void *, int,
97     void (*)(void *), void *, struct audio_params *);
98 int envy_halt_output(void *);
99 int envy_halt_input(void *);
100 int envy_getdev(void *, struct audio_device *);
101 int envy_query_devinfo(void *, struct mixer_devinfo *);
102 int envy_get_port(void *, struct mixer_ctrl *);
103 int envy_set_port(void *, struct mixer_ctrl *);
104 int envy_get_props(void *);
105 
106 void delta_init(struct envy_softc *);
107 void delta_codec_write(struct envy_softc *, int, int, int);
108 
109 void revo51_init(struct envy_softc *);
110 void revo51_codec_write(struct envy_softc *, int, int, int);
111 
112 void julia_init(struct envy_softc *);
113 void julia_codec_write(struct envy_softc *, int, int, int);
114 
115 void unkenvy_init(struct envy_softc *);
116 void unkenvy_codec_write(struct envy_softc *, int, int, int);
117 int unkenvy_codec_ndev(struct envy_softc *);
118 
119 int ak4524_dac_ndev(struct envy_softc *);
120 void ak4524_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
121 void ak4524_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
122 int ak4524_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
123 int ak4524_adc_ndev(struct envy_softc *);
124 void ak4524_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
125 void ak4524_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
126 int ak4524_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
127 
128 int ak4358_dac_ndev(struct envy_softc *);
129 void ak4358_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
130 void ak4358_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
131 int ak4358_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
132 
133 int ak5365_adc_ndev(struct envy_softc *);
134 void ak5365_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
135 void ak5365_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
136 int ak5365_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
137 
138 struct cfattach envy_ca = {
139 	sizeof(struct envy_softc), envymatch, envyattach, envydetach
140 };
141 
142 struct cfdriver envy_cd = {
143 	NULL, "envy", DV_DULL
144 };
145 
146 struct audio_hw_if envy_hw_if = {
147 	envy_open,		/* open */
148 	envy_close,		/* close */
149 	NULL,			/* drain */
150 	envy_query_encoding,	/* query_encoding */
151 	envy_set_params,	/* set_params */
152 	envy_round_blocksize,	/* round_blocksize */
153 	NULL,			/* commit_settings */
154 	NULL,			/* init_output */
155 	NULL,			/* init_input */
156 	NULL,			/* start_output */
157 	NULL,			/* start_input */
158 	envy_halt_output,	/* halt_output */
159 	envy_halt_input,	/* halt_input */
160 	NULL,			/* speaker_ctl */
161 	envy_getdev,		/* getdev */
162 	NULL,			/* setfd */
163 	envy_set_port,		/* set_port */
164 	envy_get_port,		/* get_port */
165 	envy_query_devinfo,	/* query_devinfo */
166 	envy_allocm,		/* malloc */
167 	envy_freem,		/* free */
168 	envy_round_buffersize,	/* round_buffersize */
169 	NULL,			/* mappage */
170 	envy_get_props,		/* get_props */
171 	envy_trigger_output,	/* trigger_output */
172 	envy_trigger_input,	/* trigger_input */
173 	NULL
174 };
175 
176 struct pci_matchid envy_matchids[] = {
177 	{ PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_ICE1712 },
178 	{ PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_VT172x }
179 };
180 
181 /*
182  * correspondence between rates (in frames per second)
183  * and values of rate register
184  */
185 struct {
186 	int rate, reg;
187 } envy_rates[] = {
188 	{ 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5},
189 	{22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0},
190 	{64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1}
191 };
192 
193 /*
194  * ESI julia cards don't have EEPROM, use this copy
195  */
196 static unsigned char julia_eeprom[ENVY_EEPROM_MAXSZ] = {
197 	/* gpio mask/dir/state is from linux */
198 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
199 	0x20, 0x80, 0xf8, 0xc3,
200 	0x9f, 0xff, 0x7f,
201 	0x9f, 0xff, 0x7f,
202 	0x60, 0x00, 0x00
203 };
204 
205 struct envy_codec ak4524_dac = {
206 	"ak4524 dac", ak4524_dac_ndev, ak4524_dac_devinfo, ak4524_dac_get, ak4524_dac_set
207 }, ak4524_adc = {
208 	"ak4524 adc", ak4524_adc_ndev, ak4524_adc_devinfo, ak4524_adc_get, ak4524_adc_set
209 }, ak4358_dac = {
210 	"ak4358 dac", ak4358_dac_ndev, ak4358_dac_devinfo, ak4358_dac_get, ak4358_dac_set
211 }, ak5365_adc = {
212 	"ak5365 adc", ak5365_adc_ndev, ak5365_adc_devinfo, ak5365_adc_get, ak5365_adc_set
213 }, unkenvy_codec = {
214 	"unknown codec", unkenvy_codec_ndev, NULL, NULL, NULL
215 };
216 
217 /*
218  * array with vendor/product sub-IDs to card info
219  */
220 struct envy_card envy_cards[] = {
221 	{
222 		PCI_ID_CODE(0x1412, 0xd630),
223 		"M-Audio Delta 1010",
224 		8, &ak4524_adc, 8, &ak4524_dac,
225 		delta_init,
226 		delta_codec_write,
227 		NULL
228 	}, {
229 		PCI_ID_CODE(0x1412, 0xd632),
230 		"M-Audio Delta 66",
231 		4, &ak4524_adc, 4, &ak4524_dac,
232 		delta_init,
233 		delta_codec_write,
234 		NULL
235 	}, {
236 		PCI_ID_CODE(0x1412, 0xd633),
237 		"M-Audio Delta 44",
238 		4, &ak4524_adc, 4, &ak4524_dac,
239 		delta_init,
240 		delta_codec_write,
241 		NULL
242 	}, {
243 		PCI_ID_CODE(0x1412, 0xd63b),
244 		"M-Audio Delta 1010LT",
245 		8, &ak4524_adc, 8, &ak4524_dac,
246 		delta_init,
247 		delta_codec_write,
248 		NULL
249 	}, {
250 		PCI_ID_CODE(0x1412, 0xd634),
251 		"M-Audio Audiophile 2496",
252 		2, &ak4524_adc, 2, &ak4524_dac,
253 		delta_init,
254 		delta_codec_write,
255 		NULL
256 	}, {
257 		0,
258 		"unknown 1712-based card",
259 		8, &unkenvy_codec, 8, &unkenvy_codec,
260 		unkenvy_init,
261 		unkenvy_codec_write
262 	}
263 }, envy_cards_ht[] = {
264 	{
265 		PCI_ID_CODE(0x3031, 0x4553),
266 		"ESI Julia",
267 		2, &unkenvy_codec, 2, &ak4358_dac,
268 		julia_init,
269 		julia_codec_write,
270 		julia_eeprom
271 	}, {
272 		PCI_ID_CODE(0x1412, 0x3631),
273 		"M-Audio Revolution 5.1",
274 		2, &ak5365_adc, 6, &ak4358_dac,
275 		revo51_init,
276 		revo51_codec_write
277 	}, {
278 		0,
279 		"unknown 1724-based card",
280 		2, &unkenvy_codec, 8, &unkenvy_codec,
281 		unkenvy_init,
282 		unkenvy_codec_write
283 	}
284 };
285 
286 
287 /*
288  * m-audio delta specific code
289  */
290 
291 void
292 delta_init(struct envy_softc *sc)
293 {
294 	int dev;
295 
296 	for (dev = 0; dev < sc->card->noch / 2; dev++) {
297 		envy_codec_write(sc, dev, AK4524_RST, 0x0);
298 		delay(300);
299 		envy_codec_write(sc, dev, AK4524_RST,
300 		    AK4524_RST_AD | AK4524_RST_DA);
301 		envy_codec_write(sc, dev, AK4524_FMT,
302 		    AK4524_FMT_IIS24);
303 		sc->shadow[dev][AK4524_DEEMVOL] = AK4524_DEEM_OFF;
304 		sc->shadow[dev][AK4524_ADC_GAIN0] = 0x7f;
305 		sc->shadow[dev][AK4524_ADC_GAIN1] = 0x7f;
306 		sc->shadow[dev][AK4524_DAC_GAIN0] = 0x7f;
307 		sc->shadow[dev][AK4524_DAC_GAIN1] = 0x7f;
308 	}
309 }
310 
311 void
312 delta_codec_write(struct envy_softc *sc, int dev, int addr, int data)
313 {
314 	int bits, i, reg;
315 
316 	reg = envy_gpio_getstate(sc);
317 	reg &= ~ENVY_GPIO_CSMASK;
318 	reg |=  ENVY_GPIO_CS(dev);
319 	envy_gpio_setstate(sc, reg);
320 	delay(1);
321 
322 	bits  = 0xa000 | (addr << 8) | data;
323 	for (i = 0; i < 16; i++) {
324 		reg &= ~(ENVY_GPIO_CLK | ENVY_GPIO_DOUT);
325 		reg |= (bits & 0x8000) ? ENVY_GPIO_DOUT : 0;
326 		envy_gpio_setstate(sc, reg);
327 		delay(1);
328 
329 		reg |= ENVY_GPIO_CLK;
330 		envy_gpio_setstate(sc, reg);
331 		delay(1);
332 		bits <<= 1;
333 	}
334 
335 	reg |= ENVY_GPIO_CSMASK;
336 	envy_gpio_setstate(sc, reg);
337 	delay(1);
338 }
339 
340 /*
341  * m-audio revolution 5.1 specific code
342  */
343 
344 #define REVO51_GPIO_CSMASK	0x30
345 #define REVO51_GPIO_CS(dev)	((dev) ? 0x10 : 0x20)
346 #define REVO51_MUTE		0x400000
347 #define REVO51_PT2258S_SDA	0x40
348 #define REVO51_PT2258S_SCL	0x80
349 #define REVO51_PT2258S_ADDR	0x80
350 #define REVO51_PT2258S_MUTE	6
351 
352 void
353 revo51_init(struct envy_softc *sc)
354 {
355 	int i, reg;
356 
357 	/* AK4358 */
358 	envy_codec_write(sc, 0, 0, 0);	/* reset */
359 	delay(300);
360 	envy_codec_write(sc, 0, 0, 0x87);	/* i2s mode */
361 	for (i = 0; i < sc->card->noch; i++) {
362 		sc->shadow[0][AK4358_ATT(i)] = 0xff;
363 	}
364 
365 	/* AK5365 */
366 	envy_codec_write(sc, 1, AK5365_RST, 0);	/* reset */
367 	delay(300);
368 	envy_codec_write(sc, 1, AK5365_CTRL, AK5365_CTRL_I2S);	/* i2s mode */
369 	envy_codec_write(sc, 1, AK5365_RST , AK5365_RST_NORM);
370 	sc->shadow[1][AK5365_ATT(0)] = 0x7f;
371 	sc->shadow[1][AK5365_ATT(1)] = 0x7f;
372 
373 	/* PT2258S */
374 	envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xc0);	/* reset */
375 	envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xf9);	/* mute */
376 
377 	reg = envy_gpio_getstate(sc);
378 	reg |= REVO51_MUTE;
379 	envy_gpio_setstate(sc, reg);
380 }
381 
382 void
383 revo51_codec_write(struct envy_softc *sc, int dev, int addr, int data)
384 {
385 	int attn, bits, mask, reg;
386 	int xlat[6] = {0x90, 0x50, 0x10, 0x30, 0x70, 0xb0};
387 
388 	/* AK4358 & AK5365 */
389 	if (dev < 2) {
390 		reg = envy_gpio_getstate(sc);
391 		reg &= ~REVO51_GPIO_CSMASK;
392 		reg |=  REVO51_GPIO_CS(dev);
393 		envy_gpio_setstate(sc, reg);
394 		delay(1);
395 
396 		bits  = 0xa000 | (addr << 8) | data;
397 		for (mask = 0x8000; mask != 0; mask >>= 1) {
398 			reg &= ~(ENVY_GPIO_CLK | ENVY_GPIO_DOUT);
399 			reg |= (bits & mask) ? ENVY_GPIO_DOUT : 0;
400 			envy_gpio_setstate(sc, reg);
401 			delay(1);
402 
403 			reg |= ENVY_GPIO_CLK;
404 			envy_gpio_setstate(sc, reg);
405 			delay(1);
406 		}
407 
408 		reg |= REVO51_GPIO_CSMASK;
409 		envy_gpio_setstate(sc, reg);
410 		delay(1);
411 		return;
412 	}
413 
414 	/* PT2258S */
415 	envy_gpio_i2c_start_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
416 	envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL,
417 	    REVO51_PT2258S_ADDR);
418 
419 	if (addr == REVO51_PT2258S_MUTE) {
420 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
421 		    REVO51_PT2258S_SCL, data);
422 	} else {
423 		/* 1's digit */
424 		attn = data % 10;
425 		attn += xlat[addr];
426 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
427 		    REVO51_PT2258S_SCL, attn);
428 
429 		/* 10's digit */
430 		attn = data / 10;
431 		attn += xlat[addr] - 0x10;
432 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
433 		    REVO51_PT2258S_SCL, attn);
434 	}
435 
436 	envy_gpio_i2c_stop_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
437 }
438 
439 /*
440  * esi julia specific code
441  */
442 
443 void
444 julia_init(struct envy_softc *sc)
445 {
446 	int i;
447 
448 	envy_codec_write(sc, 0, 0, 0);	/* reset */
449 	delay(300);
450 	envy_codec_write(sc, 0, 0, 0x87);	/* i2s mode */
451 	for (i = 0; i < sc->card->noch; i++) {
452 		sc->shadow[0][AK4358_ATT(i)] = 0xff;
453 	}
454 }
455 
456 void
457 julia_codec_write(struct envy_softc *sc, int dev, int addr, int data)
458 {
459 #define JULIA_AK4358_ADDR	0x11
460 	envy_i2c_write(sc, JULIA_AK4358_ADDR, addr, data);
461 }
462 
463 /*
464  * unknown card, ignore codecs setup and hope it works with the power on
465  * settings
466  */
467 
468 void
469 unkenvy_init(struct envy_softc *sc)
470 {
471 }
472 
473 void
474 unkenvy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
475 {
476 }
477 
478 int
479 unkenvy_codec_ndev(struct envy_softc *sc)
480 {
481 	return 0;
482 }
483 
484 /*
485  * AK 4358 DAC specific code
486  */
487 int
488 ak4358_dac_ndev(struct envy_softc *sc)
489 {
490 	/* 1 volume knob per channel */
491 	return sc->card->noch;
492 }
493 
494 void
495 ak4358_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
496 {
497 	dev->type = AUDIO_MIXER_VALUE;
498 	dev->mixer_class = ENVY_MIX_CLASSOUT;
499 	dev->un.v.delta = 2;
500 	dev->un.v.num_channels = 1;
501 	snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
502 	    AudioNline "%d", idx);
503 	strlcpy(dev->un.v.units.name, AudioNvolume,
504 	    MAX_AUDIO_DEV_LEN);
505 }
506 
507 void
508 ak4358_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
509 {
510 	int val;
511 
512 	val = envy_codec_read(sc, 0, AK4358_ATT(idx)) & ~AK4358_ATT_EN;
513 	ctl->un.value.num_channels = 1;
514 	ctl->un.value.level[0] = 2 * val;
515 }
516 
517 int
518 ak4358_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
519 {
520 	int val;
521 
522 	if (ctl->un.value.num_channels != 1)
523 		return EINVAL;
524 	val = ctl->un.value.level[0] / 2;
525 	envy_codec_write(sc, 0, AK4358_ATT(idx), val | AK4358_ATT_EN);
526 	return 0;
527 }
528 
529 /*
530  * AK 4524 DAC specific code
531  */
532 int
533 ak4524_dac_ndev(struct envy_softc *sc)
534 {
535 	/* 1 mute + 2 volume knobs per channel pair */
536 	return 3 * (sc->card->noch / 2);
537 }
538 
539 void
540 ak4524_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
541 {
542 	int ndev;
543 
544 	ndev = sc->card->noch;
545 	if (idx < ndev) {
546 		dev->type = AUDIO_MIXER_VALUE;
547 		dev->mixer_class = ENVY_MIX_CLASSOUT;
548 		dev->un.v.delta = 2;
549 		dev->un.v.num_channels = 1;
550 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
551 		    AudioNline "%d", idx);
552 		strlcpy(dev->un.v.units.name, AudioNvolume,
553 		    MAX_AUDIO_DEV_LEN);
554 	} else {
555 		idx -= ndev;
556 		dev->type = AUDIO_MIXER_ENUM;
557 		dev->mixer_class = ENVY_MIX_CLASSOUT;
558 		dev->un.e.member[0].ord = 0;
559 		strlcpy(dev->un.e.member[0].label.name, AudioNoff,
560 		    MAX_AUDIO_DEV_LEN);
561 		dev->un.e.member[1].ord = 1;
562 		strlcpy(dev->un.e.member[1].label.name, AudioNon,
563 		   MAX_AUDIO_DEV_LEN);
564 		dev->un.e.num_mem = 2;
565 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
566 		    AudioNmute "%d-%d", 2 * idx, 2 * idx + 1);
567 	}
568 }
569 
570 void
571 ak4524_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
572 {
573 	int val, ndev;
574 
575 	ndev = sc->card->noch;
576 	if (idx < ndev) {
577 		val = envy_codec_read(sc, idx / 2,
578 		    (idx % 2) + AK4524_DAC_GAIN0);
579 		ctl->un.value.num_channels = 1;
580 		ctl->un.value.level[0] = 2 * val;
581 	} else {
582 		idx -= ndev;
583 		val = envy_codec_read(sc, idx, AK4524_DEEMVOL);
584 		ctl->un.ord = (val & AK4524_MUTE) ? 1 : 0;
585 	}
586 }
587 
588 int
589 ak4524_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
590 {
591 	int val, ndev;
592 
593 	ndev = sc->card->noch;
594 	if (idx < ndev) {
595 		if (ctl->un.value.num_channels != 1)
596 			return EINVAL;
597 		val = ctl->un.value.level[0] / 2;
598 		envy_codec_write(sc, idx / 2,
599 		    (idx % 2) + AK4524_DAC_GAIN0, val);
600 	} else {
601 		idx -= ndev;
602 		if (ctl->un.ord >= 2)
603 			return EINVAL;
604 		val = AK4524_DEEM_OFF | (ctl->un.ord ? AK4524_MUTE : 0);
605 		envy_codec_write(sc, idx, AK4524_DEEMVOL, val);
606 	}
607 	return 0;
608 }
609 
610 /*
611  * AK 4524 ADC specific code
612  */
613 int
614 ak4524_adc_ndev(struct envy_softc *sc)
615 {
616 	/* one volume per channel */
617 	return sc->card->nich;
618 }
619 
620 void
621 ak4524_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
622 {
623 	dev->type = AUDIO_MIXER_VALUE;
624 	dev->mixer_class = ENVY_MIX_CLASSIN;
625 	dev->un.v.delta = 2;
626 	dev->un.v.num_channels = 1;
627 	snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, AudioNline "%d", idx);
628 	strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
629 }
630 
631 void
632 ak4524_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
633 {
634 	int val;
635 
636 	val = envy_codec_read(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0);
637 	ctl->un.value.num_channels = 1;
638 	ctl->un.value.level[0] = 2 * val;
639 }
640 
641 int
642 ak4524_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
643 {
644 	int val;
645 
646 	if (ctl->un.value.num_channels != 1)
647 		return EINVAL;
648 	val = ctl->un.value.level[0] / 2;
649 	envy_codec_write(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0, val);
650 	return 0;
651 }
652 
653 /*
654  * AK 5365 ADC specific code
655  */
656 int
657 ak5365_adc_ndev(struct envy_softc *sc)
658 {
659 	/* 1 source + 2 volume knobs per channel pair */
660 	return (sc->card->nich + 1);
661 }
662 
663 void
664 ak5365_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
665 {
666 	int ndev, i;
667 
668 	ndev = sc->card->nich;
669 	if (idx < ndev) {
670 		dev->type = AUDIO_MIXER_VALUE;
671 		dev->mixer_class = ENVY_MIX_CLASSIN;
672 		dev->un.v.delta = 2;
673 		dev->un.v.num_channels = 1;
674 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
675 		    AudioNline "%d", idx);
676 		strlcpy(dev->un.v.units.name, AudioNvolume,
677 		    MAX_AUDIO_DEV_LEN);
678 	} else {
679 		dev->type = AUDIO_MIXER_ENUM;
680 		dev->mixer_class = ENVY_MIX_CLASSIN;
681 		for (i = 0; i < 5; i++) {
682 			dev->un.e.member[i].ord = i;
683 			snprintf(dev->un.e.member[i].label.name,
684 			    MAX_AUDIO_DEV_LEN, AudioNline "%d", i);
685 		}
686 		dev->un.e.num_mem = 5;
687 		strlcpy(dev->label.name, AudioNsource,
688 		    MAX_AUDIO_DEV_LEN);
689 	}
690 }
691 
692 void
693 ak5365_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
694 {
695 	int val, ndev;
696 
697 	ndev = sc->card->nich;
698 	if (idx < ndev) {
699 		val = envy_codec_read(sc, 1, AK5365_ATT(idx));
700 		ctl->un.value.num_channels = 1;
701 		ctl->un.value.level[0] = 2 * val;
702 	} else {
703 		ctl->un.ord = envy_codec_read(sc, 1, AK5365_SRC);
704 	}
705 }
706 
707 int
708 ak5365_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
709 {
710 	int val, ndev;
711 
712 	ndev = sc->card->nich;
713 	if (idx < ndev) {
714 		if (ctl->un.value.num_channels != 1)
715 			return EINVAL;
716 		val = ctl->un.value.level[0] / 2;
717 		envy_codec_write(sc, 1, AK5365_ATT(idx), val);
718 	} else {
719 		if (ctl->un.ord >= 5)
720 			return EINVAL;
721 		val = ctl->un.ord & AK5365_SRC_MASK;
722 		envy_codec_write(sc, 1, AK5365_SRC, val);
723 	}
724 	return 0;
725 }
726 
727 /*
728  * generic Envy24 and Envy24HT code, common to all cards
729  */
730 
731 int
732 envy_ccs_read(struct envy_softc *sc, int reg)
733 {
734 	return bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg);
735 }
736 
737 void
738 envy_ccs_write(struct envy_softc *sc, int reg, int val)
739 {
740 	bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val);
741 }
742 
743 int
744 envy_cci_read(struct envy_softc *sc, int index)
745 {
746 	int val;
747 	envy_ccs_write(sc, ENVY_CCI_INDEX, index);
748 	val = envy_ccs_read(sc, ENVY_CCI_DATA);
749 	return val;
750 }
751 
752 void
753 envy_cci_write(struct envy_softc *sc, int index, int data)
754 {
755 	envy_ccs_write(sc, ENVY_CCI_INDEX, index);
756 	envy_ccs_write(sc, ENVY_CCI_DATA, data);
757 }
758 
759 int
760 envy_gpio_getstate(struct envy_softc *sc)
761 {
762 	if (sc->isht) {
763 		return envy_ccs_read(sc, ENVY_CCS_GPIODATA0) |
764 		    (envy_ccs_read(sc, ENVY_CCS_GPIODATA1) << 8) |
765 		    (envy_ccs_read(sc, ENVY_CCS_GPIODATA2) << 16);
766 	} else
767 		return envy_cci_read(sc, ENVY_CCI_GPIODATA);
768 }
769 
770 void
771 envy_gpio_setstate(struct envy_softc *sc, int reg)
772 {
773 	if (sc->isht) {
774 		envy_ccs_write(sc, ENVY_CCS_GPIODATA0, reg & 0xff);
775 		envy_ccs_write(sc, ENVY_CCS_GPIODATA1, (reg >> 8) & 0xff);
776 		envy_ccs_write(sc, ENVY_CCS_GPIODATA2, (reg >> 16) & 0xff);
777 	} else
778 		envy_cci_write(sc, ENVY_CCI_GPIODATA, reg);
779 }
780 
781 int
782 envy_gpio_getmask(struct envy_softc *sc)
783 {
784 	if (sc->isht) {
785 		return envy_ccs_read(sc, ENVY_CCS_GPIOMASK0) |
786 		    (envy_ccs_read(sc, ENVY_CCS_GPIOMASK1) << 8) |
787 		    (envy_ccs_read(sc, ENVY_CCS_GPIOMASK2) << 16);
788 	} else
789 		return envy_cci_read(sc, ENVY_CCI_GPIOMASK);
790 }
791 
792 void
793 envy_gpio_setmask(struct envy_softc *sc, int mask)
794 {
795 	if (sc->isht) {
796 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK0, mask & 0xff);
797 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK1, (mask >> 8) & 0xff);
798 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK2, (mask >> 16) & 0xff);
799 	} else
800 		envy_cci_write(sc, ENVY_CCI_GPIOMASK, mask);
801 }
802 
803 int
804 envy_gpio_getdir(struct envy_softc *sc)
805 {
806 	if (sc->isht) {
807 		return envy_ccs_read(sc, ENVY_CCS_GPIODIR0) |
808 		    (envy_ccs_read(sc, ENVY_CCS_GPIODIR1) << 8) |
809 		    (envy_ccs_read(sc, ENVY_CCS_GPIODIR2) << 16);
810 	} else
811 		return envy_cci_read(sc, ENVY_CCI_GPIODIR);
812 }
813 
814 void
815 envy_gpio_setdir(struct envy_softc *sc, int dir)
816 {
817 	if (sc->isht) {
818 		envy_ccs_write(sc, ENVY_CCS_GPIODIR0, dir & 0xff);
819 		envy_ccs_write(sc, ENVY_CCS_GPIODIR1, (dir >> 8) & 0xff);
820 		envy_ccs_write(sc, ENVY_CCS_GPIODIR2, (dir >> 16) & 0xff);
821 	} else
822 		envy_cci_write(sc, ENVY_CCI_GPIODIR, dir);
823 }
824 
825 void
826 envy_gpio_i2c_start_bit(struct envy_softc *sc, int sda, int scl)
827 {
828 	int reg;
829 
830 	reg = envy_gpio_getstate(sc);
831 	reg |= (sda | scl);
832 	envy_gpio_setstate(sc, reg);
833 	delay(5);
834 	reg &= ~sda;
835 	envy_gpio_setstate(sc, reg);
836 	delay(4);
837 	reg &= ~scl;
838 	envy_gpio_setstate(sc, reg);
839 	delay(5);
840 }
841 
842 void
843 envy_gpio_i2c_stop_bit(struct envy_softc *sc, int sda, int scl)
844 {
845 	int reg;
846 
847 	reg = envy_gpio_getstate(sc);
848 	reg &= ~sda;
849 	reg |= scl;
850 	envy_gpio_setstate(sc, reg);
851 	delay(4);
852 	reg |= sda;
853 	envy_gpio_setstate(sc, reg);
854 }
855 
856 void
857 envy_gpio_i2c_byte_out(struct envy_softc *sc, int sda, int scl, int val)
858 {
859 	int mask, reg;
860 
861 	reg = envy_gpio_getstate(sc);
862 
863 	for (mask = 0x80; mask != 0; mask >>= 1) {
864 		reg &= ~sda;
865 		reg |= (val & mask) ? sda : 0;
866 		envy_gpio_setstate(sc, reg);
867 		delay(1);
868 		reg |= scl;
869 		envy_gpio_setstate(sc, reg);
870 		delay(4);
871 		reg &= ~scl;
872 		envy_gpio_setstate(sc, reg);
873 		delay(5);
874 	}
875 
876 	reg |= scl;
877 	envy_gpio_setstate(sc, reg);
878 	delay(4);
879 	reg &= ~scl;
880 	envy_gpio_setstate(sc, reg);
881 	delay(5);
882 }
883 
884 void
885 envy_i2c_wait(struct envy_softc *sc)
886 {
887 	int timeout = 50, st;
888 
889         for (;;) {
890 		st = envy_ccs_read(sc, ENVY_I2C_CTL);
891 		if (!(st & ENVY_I2C_CTL_BUSY))
892 			break;
893 		if (timeout == 0) {
894 			printf("%s: i2c busy timeout\n", DEVNAME(sc));
895 			break;
896 		}
897 		delay(50);
898 		timeout--;
899 	}
900 }
901 
902 int
903 envy_i2c_read(struct envy_softc *sc, int dev, int addr)
904 {
905 	envy_i2c_wait(sc);
906 	envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
907 	envy_i2c_wait(sc);
908 	envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1);
909 	envy_i2c_wait(sc);
910 	return envy_ccs_read(sc, ENVY_I2C_DATA);
911 }
912 
913 void
914 envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data)
915 {
916 	if (dev == 0x50) {
917 		printf("%s: writing on eeprom is evil...\n", DEVNAME(sc));
918 		return;
919 	}
920 	envy_i2c_wait(sc);
921 	envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
922 	envy_i2c_wait(sc);
923 	envy_ccs_write(sc, ENVY_I2C_DATA, data);
924 	envy_i2c_wait(sc);
925 	envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1);
926 }
927 
928 int
929 envy_codec_read(struct envy_softc *sc, int dev, int addr) {
930 	return sc->shadow[dev][addr];
931 }
932 
933 void
934 envy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
935 {
936 	DPRINTFN(2, "envy_codec_write: %d, %d, 0x%x\n", dev, addr, data);
937 	sc->shadow[dev][addr] = data;
938 	sc->card->codec_write(sc, dev, addr, data);
939 }
940 
941 int
942 envy_eeprom_gpioxxx(struct envy_softc *sc, int addr)
943 {
944 	int val;
945 
946 	val = sc->eeprom[addr];
947 	if (sc->isht) {
948 		val |= sc->eeprom[++addr] << 8;
949 		val |= sc->eeprom[++addr] << 16;
950 	}
951 	return val;
952 }
953 
954 void
955 envy_reset(struct envy_softc *sc)
956 {
957 	int i;
958 
959 	/*
960 	 * full reset
961 	 */
962 	envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE);
963 	delay(200);
964 	envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE);
965 	delay(200);
966 
967 	/*
968 	 * read eeprom using i2c device or from a static array
969 	 */
970 	if (sc->card->eeprom == NULL) {
971 		for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
972 			sc->eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i);
973 		}
974 #ifdef ENVY_DEBUG
975 		printf("%s: eeprom: ", DEVNAME(sc));
976 		for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
977 			printf(" %02x", (unsigned)sc->eeprom[i]);
978 		}
979 		printf("\n");
980 #endif
981 	} else
982 		memcpy(sc->eeprom, sc->card->eeprom, ENVY_EEPROM_MAXSZ);
983 
984 	/*
985 	 * write eeprom values to corresponding registers
986 	 */
987 	if (sc->isht) {
988 		envy_ccs_write(sc, ENVY_CCS_CONF,
989 		    sc->eeprom[ENVY_EEPROM_CONF]);
990 		envy_ccs_write(sc, ENVY_CCS_ACLINK,
991 		    sc->eeprom[ENVY_EEPROM_ACLINK]);
992 		envy_ccs_write(sc, ENVY_CCS_I2S,
993 		    sc->eeprom[ENVY_EEPROM_I2S]);
994 		envy_ccs_write(sc, ENVY_CCS_SPDIF,
995 		    sc->eeprom[ENVY_EEPROM_SPDIF]);
996 	} else {
997 		pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF,
998 		    sc->eeprom[ENVY_EEPROM_CONF] |
999 		    (sc->eeprom[ENVY_EEPROM_ACLINK] << 8) |
1000 		    (sc->eeprom[ENVY_EEPROM_I2S] << 16) |
1001 		    (sc->eeprom[ENVY_EEPROM_SPDIF] << 24));
1002 	}
1003 
1004 	envy_gpio_setmask(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOMASK(sc)));
1005 	envy_gpio_setdir(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIODIR(sc)));
1006 	envy_gpio_setstate(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOST(sc)));
1007 
1008 	DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc),
1009 		envy_gpio_getmask(sc));
1010 	DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc),
1011 		envy_gpio_getdir(sc));
1012 	DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc),
1013 		envy_gpio_getstate(sc));
1014 
1015 	/*
1016 	 * clear all interrupts and unmask used ones
1017 	 */
1018 	envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff);
1019 	envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT);
1020 	if (sc->isht) {
1021 		bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_NSTREAM,
1022 		    4 - sc->card->noch / 2);
1023 		bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_IMASK,
1024 		    ~(ENVY_MT_IMASK_PDMA0 | ENVY_MT_IMASK_RDMA0));
1025 	}
1026 	sc->card->init(sc);
1027 }
1028 
1029 int
1030 envy_intr(void *self)
1031 {
1032 	struct envy_softc *sc = (struct envy_softc *)self;
1033 	int st;
1034 
1035 	st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR);
1036 	if (!(st & (ENVY_MT_INTR_PACK | ENVY_MT_INTR_RACK))) {
1037 		return 0;
1038 	}
1039 	if (st & ENVY_MT_INTR_PACK) {
1040 		st = ENVY_MT_INTR_PACK;
1041 		bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st);
1042 		sc->ointr(sc->oarg);
1043 	}
1044 	if (st & ENVY_MT_INTR_RACK) {
1045 		st = ENVY_MT_INTR_RACK;
1046 		bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st);
1047 		sc->iintr(sc->iarg);
1048 	}
1049 	return 1;
1050 }
1051 
1052 int
1053 envy_lineout_getsrc(struct envy_softc *sc, int out)
1054 {
1055 	int reg, shift, src;
1056 
1057 	if (sc->isht) {
1058 		reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC);
1059 		DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1060 		shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1061 		src = (reg >> shift) & ENVY_MT_HTSRC_MASK;
1062 		if (src == ENVY_MT_HTSRC_DMA) {
1063 			return ENVY_MIX_OUTSRC_DMA;
1064 		} else {
1065 			src -= ENVY_MT_HTSRC_LINE;
1066 			return ENVY_MIX_OUTSRC_LINEIN + src;
1067 		}
1068 	}
1069 
1070 	reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC);
1071 	DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1072 	shift = (out  & 1) ? (out & ~1) + 8 : out;
1073 	src = (reg >> shift) & 3;
1074 	if (src == ENVY_MT_OUTSRC_DMA) {
1075 		return ENVY_MIX_OUTSRC_DMA;
1076 	} else if (src == ENVY_MT_OUTSRC_MON) {
1077 		return ENVY_MIX_OUTSRC_MON;
1078 	}
1079 	reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL);
1080 	DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg);
1081 	reg = (reg >> (out * 4)) & 0xf;
1082 	if (src == ENVY_MT_OUTSRC_LINE)
1083 		return ENVY_MIX_OUTSRC_LINEIN + (reg & 7);
1084 	else
1085 		return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3);
1086 }
1087 
1088 void
1089 envy_lineout_setsrc(struct envy_softc *sc, int out, int src)
1090 {
1091 	int reg, shift, mask, sel;
1092 
1093 	if (sc->isht) {
1094 		if (src < ENVY_MIX_OUTSRC_SPDIN) {
1095 			sel = ENVY_MT_HTSRC_LINE;
1096 			sel += src;
1097 		} else if (src < ENVY_MIX_OUTSRC_DMA) {
1098 			sel = ENVY_MT_HTSRC_SPD;
1099 			sel += src - ENVY_MIX_OUTSRC_SPDIN;
1100 		} else {
1101 			sel = ENVY_MT_HTSRC_DMA;
1102 		}
1103 		shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1104 		mask = ENVY_MT_HTSRC_MASK << shift;
1105 		reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC);
1106 		reg = (reg & ~mask) | (sel << shift);
1107 		bus_space_write_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_HTSRC, reg);
1108 		DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1109 		return;
1110 	}
1111 
1112 	if (src < ENVY_MIX_OUTSRC_DMA) {
1113 		/*
1114 		 * linein and spdin are used as output source so we
1115 		 * must select the input source channel number
1116 		 */
1117 		if (src < ENVY_MIX_OUTSRC_SPDIN)
1118 			sel = src - ENVY_MIX_OUTSRC_LINEIN;
1119 		else
1120 			sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1121 
1122 		shift = out * ENVY_MT_INSEL_BITS;
1123 		mask = ENVY_MT_INSEL_MASK << shift;
1124 		reg = bus_space_read_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL);
1125 		reg = (reg & ~mask) | (sel << shift);
1126 		bus_space_write_4(sc->mt_iot, sc->mt_ioh, ENVY_MT_INSEL, reg);
1127 		DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg);
1128 	}
1129 
1130 	/*
1131 	 * set the lineout route register
1132 	 */
1133 	if (src < ENVY_MIX_OUTSRC_SPDIN) {
1134 		sel = ENVY_MT_OUTSRC_LINE;
1135 	} else if (src < ENVY_MIX_OUTSRC_DMA) {
1136 		sel = ENVY_MT_OUTSRC_SPD;
1137 	} else if (src == ENVY_MIX_OUTSRC_DMA) {
1138 		sel = ENVY_MT_OUTSRC_DMA;
1139 	} else {
1140 		sel = ENVY_MT_OUTSRC_MON;
1141 	}
1142 	shift = (out  & 1) ? (out & ~1) + 8 : out;
1143 	mask = ENVY_MT_OUTSRC_MASK << shift;
1144 	reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC);
1145 	reg = (reg & ~mask) | (sel << shift);
1146 	bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_OUTSRC, reg);
1147 	DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1148 }
1149 
1150 
1151 int
1152 envy_spdout_getsrc(struct envy_softc *sc, int out)
1153 {
1154 	int reg, src, sel;
1155 
1156 	reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE);
1157 	DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg);
1158 	src = (out == 0) ? reg : reg >> 2;
1159 	src &= ENVY_MT_SPDSRC_MASK;
1160 	if (src == ENVY_MT_SPDSRC_DMA) {
1161 		return ENVY_MIX_OUTSRC_DMA;
1162 	} else if (src == ENVY_MT_SPDSRC_MON) {
1163 		return ENVY_MIX_OUTSRC_MON;
1164 	}
1165 
1166 	sel = (out == 0) ? reg >> 8 : reg >> 12;
1167 	sel &= ENVY_MT_SPDSEL_MASK;
1168 	if (src == ENVY_MT_SPDSRC_LINE)
1169 		return ENVY_MIX_OUTSRC_LINEIN + (sel & 7);
1170 	else
1171 		return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3);
1172 }
1173 
1174 void
1175 envy_spdout_setsrc(struct envy_softc *sc, int out, int src)
1176 {
1177 	int reg, shift, mask, sel;
1178 
1179 	reg = bus_space_read_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE);
1180 	if (src < ENVY_MIX_OUTSRC_DMA) {
1181 		/*
1182 		 * linein and spdin are used as output source so we
1183 		 * must select the input source channel number
1184 		 */
1185 		if (src < ENVY_MIX_OUTSRC_SPDIN)
1186 			sel = src - ENVY_MIX_OUTSRC_LINEIN;
1187 		else
1188 			sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1189 
1190 		shift = 8 + out * ENVY_MT_SPDSEL_BITS;
1191 		mask = ENVY_MT_SPDSEL_MASK << shift;
1192 		reg = (reg & ~mask) | (sel << shift);
1193 	}
1194 
1195 	/*
1196 	 * set the lineout route register
1197 	 */
1198 	if (src < ENVY_MIX_OUTSRC_SPDIN) {
1199 		sel = ENVY_MT_OUTSRC_LINE;
1200 	} else if (src < ENVY_MIX_OUTSRC_DMA) {
1201 		sel = ENVY_MT_OUTSRC_SPD;
1202 	} else if (src == ENVY_MIX_OUTSRC_DMA) {
1203 		sel = ENVY_MT_OUTSRC_DMA;
1204 	} else {
1205 		sel = ENVY_MT_OUTSRC_MON;
1206 	}
1207 	shift = out * 2;
1208 	mask = ENVY_MT_SPDSRC_MASK << shift;
1209 	reg = (reg & ~mask) | (sel << shift);
1210 	bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_SPDROUTE, reg);
1211 	DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg);
1212 }
1213 
1214 void
1215 envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val)
1216 {
1217 	int reg;
1218 
1219 	bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx);
1220 	reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch);
1221 	*val = 0x7f - (reg & 0x7f);
1222 }
1223 
1224 void
1225 envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val)
1226 {
1227 	int reg;
1228 
1229 	bus_space_write_2(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONIDX, idx);
1230 	reg = 0x7f - val;
1231 	DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val);
1232 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_MONDATA + ch, reg);
1233 }
1234 
1235 int
1236 envymatch(struct device *parent, void *match, void *aux)
1237 {
1238 	return pci_matchbyid((struct pci_attach_args *)aux, envy_matchids,
1239 	    sizeof(envy_matchids) / sizeof(envy_matchids[0]));
1240 }
1241 
1242 void
1243 envyattach(struct device *parent, struct device *self, void *aux)
1244 {
1245 	struct envy_softc *sc = (struct envy_softc *)self;
1246 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
1247 	pci_intr_handle_t ih;
1248 	const char *intrstr;
1249 	int subid;
1250 
1251 	sc->pci_tag = pa->pa_tag;
1252 	sc->pci_pc = pa->pa_pc;
1253 	sc->pci_dmat = pa->pa_dmat;
1254 	sc->pci_ih = NULL;
1255 	sc->ibuf.addr = sc->obuf.addr = NULL;
1256 	sc->ccs_iosz = 0;
1257 	sc->mt_iosz = 0;
1258 	sc->isht = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_VT172x);
1259 
1260 	if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0,
1261 		&sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) {
1262 		printf(": can't map ctl i/o space\n");
1263 		sc->ccs_iosz = 0;
1264 		return;
1265         }
1266 	if (pci_mapreg_map(pa, ENVY_MT_BAR(sc->isht), PCI_MAPREG_TYPE_IO, 0,
1267 		&sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) {
1268 		printf(": can't map mt i/o space\n");
1269 		sc->mt_iosz = 0;
1270 		return;
1271         }
1272 	if (pci_intr_map(pa, &ih)) {
1273 		printf(": can't map interrupt\n");
1274 	}
1275 	intrstr = pci_intr_string(sc->pci_pc, ih);
1276 	sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO,
1277 	    envy_intr, sc, sc->dev.dv_xname);
1278 	if (sc->pci_ih == NULL) {
1279 		printf(": can't establish interrupt");
1280 		if (intrstr)
1281 			printf(" at %s", intrstr);
1282 		printf("\n");
1283 		return;
1284 	}
1285 	printf(": %s\n", intrstr);
1286 	subid = pci_conf_read(sc->pci_pc, sc->pci_tag, PCI_SUBVEND_0);
1287 	sc->card = sc->isht ? envy_cards_ht : envy_cards;
1288 	while (sc->card->subid != subid) {
1289 		if (sc->card->subid == 0)
1290 			break;
1291 		sc->card++;
1292 	}
1293 	printf("%s: %s, %u inputs, %u outputs\n", DEVNAME(sc),
1294 	    sc->card->name, sc->card->nich, sc->card->noch);
1295 	envy_reset(sc);
1296 	sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev);
1297 }
1298 
1299 int
1300 envydetach(struct device *self, int flags)
1301 {
1302 	struct envy_softc *sc = (struct envy_softc *)self;
1303 
1304 	if (sc->pci_ih != NULL) {
1305 		pci_intr_disestablish(sc->pci_pc, sc->pci_ih);
1306 		sc->pci_ih = NULL;
1307 	}
1308 	if (sc->ccs_iosz) {
1309 		bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz);
1310 	}
1311 	if (sc->mt_iosz) {
1312 		bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz);
1313 	}
1314 	return 0;
1315 }
1316 
1317 int
1318 envy_open(void *self, int flags)
1319 {
1320 	return 0;
1321 }
1322 
1323 void
1324 envy_close(void *self)
1325 {
1326 }
1327 
1328 void *
1329 envy_allocm(void *self, int dir, size_t size, int type, int flags)
1330 {
1331 	struct envy_softc *sc = (struct envy_softc *)self;
1332 	int err, rsegs, basereg, wait;
1333 	struct envy_buf *buf;
1334 
1335 	if (dir == AUMODE_RECORD) {
1336 		buf = &sc->ibuf;
1337 		basereg = ENVY_MT_RADDR;
1338 	} else {
1339 		buf = &sc->obuf;
1340 		basereg = ENVY_MT_PADDR;
1341 	}
1342 	if (buf->addr != NULL) {
1343 		DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir);
1344 		return NULL;
1345 	}
1346 	buf->size = size;
1347 	wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
1348 
1349 #define ENVY_ALIGN	4
1350 #define ENVY_BOUNDARY	0
1351 
1352 	err = bus_dmamem_alloc(sc->pci_dmat, buf->size, ENVY_ALIGN,
1353 	    ENVY_BOUNDARY, &buf->seg, 1, &rsegs, wait);
1354 	if (err) {
1355 		DPRINTF("%s: dmamem_alloc: failed %d\n", DEVNAME(sc), err);
1356 		goto err_ret;
1357 	}
1358 
1359 	err = bus_dmamem_map(sc->pci_dmat, &buf->seg, rsegs, buf->size,
1360             &buf->addr, wait | BUS_DMA_COHERENT);
1361 	if (err) {
1362 		DPRINTF("%s: dmamem_map: failed %d\n", DEVNAME(sc), err);
1363 		goto err_free;
1364 	}
1365 
1366 	err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0,
1367 	    wait, &buf->map);
1368 	if (err) {
1369 		DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err);
1370 		goto err_unmap;
1371 	}
1372 
1373 	err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr,
1374             buf->size, NULL, wait);
1375 	if (err) {
1376 		DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err);
1377 		goto err_destroy;
1378 	}
1379 	bus_space_write_4(sc->mt_iot, sc->mt_ioh, basereg, buf->seg.ds_addr);
1380 	DPRINTF("%s: allocated %ld bytes dir=%d, ka=%p, da=%p\n",
1381 		DEVNAME(sc), buf->size, dir, buf->addr, (void *)buf->seg.ds_addr);
1382 	return buf->addr;
1383 
1384  err_destroy:
1385 	bus_dmamap_destroy(sc->pci_dmat, buf->map);
1386  err_unmap:
1387 	bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size);
1388  err_free:
1389 	bus_dmamem_free(sc->pci_dmat, &buf->seg, 1);
1390  err_ret:
1391 	return NULL;
1392 }
1393 
1394 void
1395 envy_freem(void *self, void *addr, int type)
1396 {
1397 	struct envy_buf *buf;
1398 	struct envy_softc *sc = (struct envy_softc *)self;
1399 	int dir;
1400 
1401 	if (sc->ibuf.addr == addr) {
1402 		buf = &sc->ibuf;
1403 		dir = AUMODE_RECORD;
1404 	} else if (sc->obuf.addr == addr) {
1405 		buf = &sc->obuf;
1406 		dir = AUMODE_PLAY;
1407 	} else {
1408 		DPRINTF("%s: no buf to free\n", DEVNAME(sc));
1409 		return;
1410 	}
1411 	bus_dmamap_destroy(sc->pci_dmat, buf->map);
1412 	bus_dmamem_unmap(sc->pci_dmat, buf->addr, buf->size);
1413 	bus_dmamem_free(sc->pci_dmat, &buf->seg, 1);
1414 	buf->addr = NULL;
1415 	DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir);
1416 }
1417 
1418 int
1419 envy_query_encoding(void *self, struct audio_encoding *enc)
1420 {
1421 	if (enc->index == 0) {
1422 		strlcpy(enc->name, AudioEslinear_le, sizeof(enc->name));
1423 		enc->encoding = AUDIO_ENCODING_SLINEAR_LE;
1424 		enc->precision = 24;
1425 		enc->flags = 0;
1426 		return 0;
1427 	}
1428 	return EINVAL;
1429 }
1430 
1431 int
1432 envy_set_params(void *self, int setmode, int usemode,
1433     struct audio_params *p, struct audio_params *r)
1434 {
1435 	struct envy_softc *sc = (struct envy_softc *)self;
1436 	int i, rate, reg;
1437 
1438 	if (setmode == 0) {
1439 		DPRINTF("%s: no params to set\n", DEVNAME(sc));
1440 		return 0;
1441 	}
1442 	if (setmode == (AUMODE_PLAY | AUMODE_RECORD) &&
1443 	    p->sample_rate != r->sample_rate) {
1444 		DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc));
1445 		r->sample_rate = p->sample_rate;
1446 	}
1447 	rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate;
1448 	for (i = 0; envy_rates[i].rate < rate; i++) {
1449 		if (envy_rates[i].rate == -1) {
1450 			i--;
1451 			DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i);
1452 			break;
1453 		}
1454 	}
1455 	reg = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE);
1456 	reg &= ~ENVY_MT_RATEMASK;
1457 	reg |= envy_rates[i].reg;
1458 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_RATE, reg);
1459 	if (setmode & AUMODE_PLAY) {
1460 		p->encoding = AUDIO_ENCODING_SLINEAR;
1461 		p->precision = 24;
1462 		p->channels = sc->isht ? sc->card->noch : ENVY_PCHANS;
1463 	}
1464 	if (setmode & AUMODE_RECORD) {
1465 		r->encoding = AUDIO_ENCODING_SLINEAR;
1466 		r->precision = 24;
1467 		r->channels = sc->isht ? sc->card->nich : ENVY_RCHANS;
1468 	}
1469 	return 0;
1470 }
1471 
1472 int
1473 envy_round_blocksize(void *self, int blksz)
1474 {
1475 	struct envy_softc *sc = (struct envy_softc *)self;
1476 	int mul, pmult, rmult;
1477 
1478 	/*
1479 	 * XXX: audio(4) layer doesn't round to the sample size
1480 	 * until it's fixed, roll our own rounding
1481 	 */
1482 
1483 	pmult = (sc->isht ? sc->card->noch : ENVY_PCHANS);
1484 	if (pmult == 0)
1485 		pmult = 1;
1486 	rmult = (sc->isht ? sc->card->nich : ENVY_RCHANS);
1487 	if (rmult == 0)
1488 		rmult = 1;
1489 	mul = pmult * rmult;
1490 	while ((mul & 0x1f) != 0)
1491 		mul <<= 1;
1492 	blksz -= blksz % mul;
1493 	if (blksz == 0)
1494 		blksz = mul;
1495 	return blksz;
1496 }
1497 
1498 size_t
1499 envy_round_buffersize(void *self, int dir, size_t bufsz)
1500 {
1501 	return bufsz;
1502 }
1503 
1504 int
1505 envy_trigger_output(void *self, void *start, void *end, int blksz,
1506     void (*intr)(void *), void *arg, struct audio_params *param)
1507 {
1508 	struct envy_softc *sc = (struct envy_softc *)self;
1509 	size_t bufsz;
1510 	int st;
1511 
1512 	bufsz = (char *)end - (char *)start;
1513 #ifdef ENVY_DEBUG
1514 	if (blksz % (sc->isht ? sc->card->noch * 4 : ENVY_PFRAME_SIZE) != 0) {
1515 		printf("%s: %d: bad output blksz\n", DEVNAME(sc), blksz);
1516 		return EINVAL;
1517 	}
1518 	if (bufsz % blksz) {
1519 		printf("%s: %ld: bad output bufsz\n", DEVNAME(sc), bufsz);
1520 		return EINVAL;
1521 	}
1522 #endif
1523 	bus_space_write_2(sc->mt_iot, sc->mt_ioh,
1524 	    ENVY_MT_PBUFSZ, bufsz / 4 - 1);
1525 	bus_space_write_2(sc->mt_iot, sc->mt_ioh,
1526 	    ENVY_MT_PBLKSZ(sc), blksz / 4 - 1);
1527 
1528 	sc->ointr = intr;
1529 	sc->oarg = arg;
1530 
1531 	st = ENVY_MT_INTR_PACK;
1532 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st);
1533 
1534 	st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL);
1535 	st |= ENVY_MT_CTL_PSTART;
1536 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st);
1537 	return 0;
1538 }
1539 
1540 int
1541 envy_trigger_input(void *self, void *start, void *end, int blksz,
1542     void (*intr)(void *), void *arg, struct audio_params *param)
1543 {
1544 	struct envy_softc *sc = (struct envy_softc *)self;
1545 	size_t bufsz;
1546 	int st;
1547 
1548 	bufsz = (char *)end - (char *)start;
1549 #ifdef ENVY_DEBUG
1550 	if (blksz % (sc->isht ? sc->card->nich * 4 : ENVY_RFRAME_SIZE) != 0) {
1551 		printf("%s: %d: bad input blksz\n", DEVNAME(sc), blksz);
1552 		return EINVAL;
1553 	}
1554 	if (bufsz % blksz != 0) {
1555 		printf("%s: %ld: bad input bufsz\n", DEVNAME(sc), bufsz);
1556 		return EINVAL;
1557 	}
1558 #endif
1559 	bus_space_write_2(sc->mt_iot, sc->mt_ioh,
1560 	    ENVY_MT_RBUFSZ, bufsz / 4 - 1);
1561 	bus_space_write_2(sc->mt_iot, sc->mt_ioh,
1562 	    ENVY_MT_RBLKSZ, blksz / 4 - 1);
1563 
1564 	sc->iintr = intr;
1565 	sc->iarg = arg;
1566 
1567 	st = ENVY_MT_INTR_RACK;
1568 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_INTR, st);
1569 
1570 	st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL);
1571 	st |= ENVY_MT_CTL_RSTART(sc);
1572 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st);
1573 	return 0;
1574 }
1575 
1576 int
1577 envy_halt_output(void *self)
1578 {
1579 	struct envy_softc *sc = (struct envy_softc *)self;
1580 	int st;
1581 
1582 	st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL);
1583 	st &= ~ENVY_MT_CTL_PSTART;
1584 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st);
1585 	return 0;
1586 }
1587 
1588 int
1589 envy_halt_input(void *self)
1590 {
1591 	struct envy_softc *sc = (struct envy_softc *)self;
1592 	int st;
1593 
1594 	st = bus_space_read_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL);
1595 	st &= ~ENVY_MT_CTL_RSTART(sc);
1596 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, ENVY_MT_CTL, st);
1597 	return 0;
1598 }
1599 
1600 int
1601 envy_getdev(void *self, struct audio_device *dev)
1602 {
1603 	struct envy_softc *sc = (struct envy_softc *)self;
1604 
1605 	strlcpy(dev->name, sc->isht ? "Envy24HT" : "Envy24", MAX_AUDIO_DEV_LEN);
1606 	strlcpy(dev->version, "-", MAX_AUDIO_DEV_LEN);
1607 	strlcpy(dev->config, sc->card->name, MAX_AUDIO_DEV_LEN);
1608 	return 0;
1609 }
1610 
1611 int
1612 envy_query_devinfo(void *self, struct mixer_devinfo *dev)
1613 {
1614 	struct envy_softc *sc = (struct envy_softc *)self;
1615 	int i, n, idx, ndev;
1616 	char *classes[] = {
1617 		AudioCinputs, AudioCoutputs, AudioCmonitor
1618 	};
1619 
1620 	if (dev->index < 0)
1621 		return ENXIO;
1622 
1623 	idx = dev->index;
1624 	ndev = ENVY_MIX_NCLASS;
1625 	dev->prev = dev->next = AUDIO_MIXER_LAST;
1626 
1627 	/*
1628 	 * classes
1629 	 */
1630 	if (idx < ndev) {
1631 		dev->type = AUDIO_MIXER_CLASS;
1632 		dev->mixer_class = idx;
1633 		strlcpy(dev->label.name, classes[idx], MAX_AUDIO_DEV_LEN);
1634 		return 0;
1635 	}
1636 	idx -= ndev;
1637 
1638 	/*
1639 	 * output.lineX_source
1640 	 */
1641 	ndev = sc->card->noch;
1642 	if (idx < ndev) {
1643 		n = 0;
1644 		dev->type = AUDIO_MIXER_ENUM;
1645 		dev->mixer_class = ENVY_MIX_CLASSOUT;
1646 		for (i = 0; i < sc->card->nich; i++) {
1647 			dev->un.e.member[n].ord = n;
1648 			snprintf(dev->un.e.member[n++].label.name,
1649 			    MAX_AUDIO_DEV_LEN, AudioNline "%d", i);
1650 		}
1651 		dev->un.e.member[n].ord = n;
1652 		snprintf(dev->un.e.member[n++].label.name,
1653 			 MAX_AUDIO_DEV_LEN, "play%d", idx);
1654 		if (!sc->isht && idx < 2) {
1655 			dev->un.e.member[n].ord = n;
1656 			snprintf(dev->un.e.member[n++].label.name,
1657 			    MAX_AUDIO_DEV_LEN, "mon%d", idx);
1658 		}
1659 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
1660 		    "line%u_" AudioNsource, idx);
1661 		dev->un.s.num_mem = n;
1662 		return 0;
1663 	}
1664 	idx -= ndev;
1665 
1666 	/*
1667 	 * envy monitor level
1668 	 */
1669 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
1670 	if (idx < ndev) {
1671 		dev->type = AUDIO_MIXER_VALUE;
1672 		dev->mixer_class = ENVY_MIX_CLASSMON;
1673 		dev->un.v.delta = 2;
1674 		dev->un.v.num_channels = 1;
1675 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
1676 			 "%s%d", idx < 10 ? "play" : "rec", idx % 10);
1677 		strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
1678 		return 0;
1679 	}
1680 	idx -= ndev;
1681 
1682 	/*
1683 	 * inputs.xxx
1684 	 */
1685 	ndev = sc->card->adc->ndev(sc);
1686 	if (idx < ndev) {
1687 		sc->card->adc->devinfo(sc, dev, idx);
1688 		return 0;
1689 	}
1690 	idx -= ndev;
1691 
1692 	/*
1693 	 * outputs.xxx
1694 	 */
1695 	ndev = sc->card->dac->ndev(sc);
1696 	if (idx < ndev) {
1697 		sc->card->dac->devinfo(sc, dev, idx);
1698 		return 0;
1699 	}
1700 	return ENXIO;
1701 }
1702 
1703 int
1704 envy_get_port(void *self, struct mixer_ctrl *ctl)
1705 {
1706 	struct envy_softc *sc = (struct envy_softc *)self;
1707 	int val, idx, ndev;
1708 
1709 	if (ctl->dev < ENVY_MIX_NCLASS) {
1710 		return EINVAL;
1711 	}
1712 
1713 	idx = ctl->dev - ENVY_MIX_NCLASS;
1714 	ndev = sc->card->noch;
1715 	if (idx < ndev) {
1716 		ctl->un.ord = envy_lineout_getsrc(sc, idx);
1717 		if (ctl->un.ord >= ENVY_MIX_NOUTSRC)
1718 			ctl->un.ord -= ENVY_MIX_NOUTSRC - sc->card->nich;
1719 		return 0;
1720 	}
1721 	idx -= ndev;
1722 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
1723 	if (idx < ndev) {
1724 		envy_mon_getvol(sc, idx / 2, idx % 2, &val);
1725 		ctl->un.value.num_channels = 1;
1726 		ctl->un.value.level[0] = 2 * val;
1727 		return 0;
1728 	}
1729 	idx -= ndev;
1730 	ndev = sc->card->adc->ndev(sc);
1731 	if (idx < ndev) {
1732 		sc->card->adc->get(sc, ctl, idx);
1733 		return 0;
1734 	}
1735 	idx -= ndev;
1736 	ndev = sc->card->dac->ndev(sc);
1737 	if (idx < ndev) {
1738 		sc->card->dac->get(sc, ctl, idx);
1739 		return 0;
1740 	}
1741 	return ENXIO;
1742 }
1743 
1744 int
1745 envy_set_port(void *self, struct mixer_ctrl *ctl)
1746 {
1747 	struct envy_softc *sc = (struct envy_softc *)self;
1748 	int maxsrc, val, idx, ndev;
1749 
1750 	if (ctl->dev < ENVY_MIX_NCLASS) {
1751 		return EINVAL;
1752 	}
1753 
1754 	idx = ctl->dev - ENVY_MIX_NCLASS;
1755 	ndev = sc->card->noch;
1756 	if (idx < ndev) {
1757 		maxsrc = sc->card->nich + 1;
1758 		if (idx < 2)
1759 			maxsrc++;
1760 		if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc)
1761 			return EINVAL;
1762 		if (ctl->un.ord >= sc->card->nich)
1763 			ctl->un.ord += ENVY_MIX_NOUTSRC - sc->card->nich;
1764 		envy_lineout_setsrc(sc, idx, ctl->un.ord);
1765 		return 0;
1766 	}
1767 	idx -= ndev;
1768 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
1769 	if (idx < ndev) {
1770 		if (ctl->un.value.num_channels != 1) {
1771 			return EINVAL;
1772 		}
1773 		val = ctl->un.value.level[0] / 2;
1774 		envy_mon_setvol(sc, idx / 2, idx % 2, val);
1775 		return 0;
1776 	}
1777 	idx -= ndev;
1778 	ndev = sc->card->adc->ndev(sc);
1779 	if (idx < ndev)
1780 		return sc->card->adc->set(sc, ctl, idx);
1781 	idx -= ndev;
1782 	ndev = sc->card->dac->ndev(sc);
1783 	if (idx < ndev)
1784 		return sc->card->dac->set(sc, ctl, idx);
1785 	return ENXIO;
1786 }
1787 
1788 int
1789 envy_get_props(void *self)
1790 {
1791 	return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT;
1792 }
1793