xref: /openbsd-src/sys/dev/pci/envy.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: envy.c,v 1.66 2015/08/30 08:52:26 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 "midi.h"
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/device.h>
33 #include <sys/audioio.h>
34 #include <sys/malloc.h>
35 #include <sys/kernel.h>
36 #include <dev/audio_if.h>
37 #include <dev/midi_if.h>
38 #include <dev/ic/ac97.h>
39 #include <dev/pci/pcivar.h>
40 #include <dev/pci/pcidevs.h>
41 #include <dev/pci/envyvar.h>
42 #include <dev/pci/envyreg.h>
43 #include <machine/bus.h>
44 #include <uvm/uvm.h>
45 
46 #ifdef ENVY_DEBUG
47 #define DPRINTF(...) do { if (envydebug) printf(__VA_ARGS__); } while(0)
48 #define DPRINTFN(n, ...) do { if (envydebug > (n)) printf(__VA_ARGS__); } while(0)
49 int envydebug = 1;
50 #else
51 #define DPRINTF(...) do {} while(0)
52 #define DPRINTFN(n, ...) do {} while(0)
53 #endif
54 #define DEVNAME(sc) ((sc)->dev.dv_xname)
55 
56 int  envymatch(struct device *, void *, void *);
57 void envyattach(struct device *, struct device *, void *);
58 int  envydetach(struct device *, int);
59 
60 int  envy_ccs_read(struct envy_softc *, int);
61 void envy_ccs_write(struct envy_softc *, int, int);
62 int  envy_mt_read_1(struct envy_softc *, int);
63 void envy_mt_write_1(struct envy_softc *, int, int);
64 int  envy_mt_read_2(struct envy_softc *, int);
65 void envy_mt_write_2(struct envy_softc *, int, int);
66 int  envy_mt_read_4(struct envy_softc *, int);
67 void envy_mt_write_4(struct envy_softc *, int, int);
68 int  envy_cci_read(struct envy_softc *, int);
69 void envy_cci_write(struct envy_softc *, int, int);
70 void envy_i2c_wait(struct envy_softc *);
71 int  envy_i2c_read(struct envy_softc *, int, int);
72 void envy_i2c_write(struct envy_softc *, int, int, int);
73 int  envy_gpio_getstate(struct envy_softc *);
74 void envy_gpio_setstate(struct envy_softc *, int);
75 int  envy_gpio_getmask(struct envy_softc *);
76 void envy_gpio_setmask(struct envy_softc *, int);
77 int  envy_gpio_getdir(struct envy_softc *);
78 void envy_gpio_setdir(struct envy_softc *, int);
79 void envy_gpio_i2c_start_bit(struct envy_softc *, int, int);
80 void envy_gpio_i2c_stop_bit(struct envy_softc *, int, int);
81 void envy_gpio_i2c_byte_out(struct envy_softc *, int, int, int);
82 int  envy_eeprom_gpioxxx(struct envy_softc *, int);
83 void envy_midi_wait(struct envy_softc *);
84 void envy_reset(struct envy_softc *);
85 int  envy_codec_read(struct envy_softc *, int, int);
86 void envy_codec_write(struct envy_softc *, int, int, int);
87 void envy_pintr(struct envy_softc *);
88 int  envy_intr(void *);
89 
90 int envy_lineout_getsrc(struct envy_softc *, int);
91 void envy_lineout_setsrc(struct envy_softc *, int, int);
92 int envy_spdout_getsrc(struct envy_softc *, int);
93 void envy_spdout_setsrc(struct envy_softc *, int, int);
94 void envy_mon_getvol(struct envy_softc *, int, int, int *);
95 void envy_mon_setvol(struct envy_softc *, int, int, int);
96 
97 int envy_open(void *, int);
98 void envy_close(void *);
99 void *envy_allocm(void *, int, size_t, int, int);
100 void envy_freem(void *, void *, int);
101 int envy_query_encoding(void *, struct audio_encoding *);
102 int envy_set_params(void *, int, int, struct audio_params *,
103     struct audio_params *);
104 int envy_round_blocksize(void *, int);
105 size_t envy_round_buffersize(void *, int, size_t);
106 int envy_trigger_output(void *, void *, void *, int,
107     void (*)(void *), void *, struct audio_params *);
108 int envy_trigger_input(void *, void *, void *, int,
109     void (*)(void *), void *, struct audio_params *);
110 int envy_halt_output(void *);
111 int envy_halt_input(void *);
112 int envy_getdev(void *, struct audio_device *);
113 int envy_query_devinfo(void *, struct mixer_devinfo *);
114 int envy_get_port(void *, struct mixer_ctrl *);
115 int envy_set_port(void *, struct mixer_ctrl *);
116 int envy_get_props(void *);
117 #if NMIDI > 0
118 int envy_midi_open(void *, int, void (*)(void *, int),
119     void (*)(void *), void *);
120 void envy_midi_close(void *);
121 int envy_midi_output(void *, int);
122 void envy_midi_getinfo(void *, struct midi_info *);
123 #endif
124 
125 int  envy_ac97_wait(struct envy_softc *);
126 int  envy_ac97_attach_codec(void *, struct ac97_codec_if *);
127 int  envy_ac97_read_codec(void *, u_int8_t, u_int16_t *);
128 int  envy_ac97_write_codec(void *, u_int8_t, u_int16_t);
129 void envy_ac97_reset_codec(void *);
130 enum ac97_host_flags envy_ac97_flags_codec(void *);
131 
132 void delta_init(struct envy_softc *);
133 void delta_codec_write(struct envy_softc *, int, int, int);
134 
135 void ap192k_init(struct envy_softc *);
136 void ap192k_codec_write(struct envy_softc *, int, int, int);
137 
138 void ewx_codec_write(struct envy_softc *, int, int, int);
139 
140 void revo51_init(struct envy_softc *);
141 void revo51_codec_write(struct envy_softc *, int, int, int);
142 
143 void envy_ac97_init(struct envy_softc *);
144 void dynex_sc51_init(struct envy_softc *);
145 
146 void julia_init(struct envy_softc *);
147 void julia_codec_write(struct envy_softc *, int, int, int);
148 
149 void unkenvy_init(struct envy_softc *);
150 void unkenvy_codec_write(struct envy_softc *, int, int, int);
151 int unkenvy_codec_ndev(struct envy_softc *);
152 
153 int ak4524_dac_ndev(struct envy_softc *);
154 void ak4524_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
155 void ak4524_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
156 int ak4524_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
157 int ak4524_adc_ndev(struct envy_softc *);
158 void ak4524_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
159 void ak4524_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
160 int ak4524_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
161 
162 int ak4358_dac_ndev(struct envy_softc *);
163 void ak4358_dac_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
164 void ak4358_dac_get(struct envy_softc *, struct mixer_ctrl *, int);
165 int ak4358_dac_set(struct envy_softc *, struct mixer_ctrl *, int);
166 
167 int ak5365_adc_ndev(struct envy_softc *);
168 void ak5365_adc_devinfo(struct envy_softc *, struct mixer_devinfo *, int);
169 void ak5365_adc_get(struct envy_softc *, struct mixer_ctrl *, int);
170 int ak5365_adc_set(struct envy_softc *, struct mixer_ctrl *, int);
171 
172 struct cfattach envy_ca = {
173 	sizeof(struct envy_softc), envymatch, envyattach, envydetach
174 };
175 
176 struct cfdriver envy_cd = {
177 	NULL, "envy", DV_DULL
178 };
179 
180 struct audio_hw_if envy_hw_if = {
181 	envy_open,		/* open */
182 	envy_close,		/* close */
183 	NULL,			/* drain */
184 	envy_query_encoding,	/* query_encoding */
185 	envy_set_params,	/* set_params */
186 	envy_round_blocksize,	/* round_blocksize */
187 	NULL,			/* commit_settings */
188 	NULL,			/* init_output */
189 	NULL,			/* init_input */
190 	NULL,			/* start_output */
191 	NULL,			/* start_input */
192 	envy_halt_output,	/* halt_output */
193 	envy_halt_input,	/* halt_input */
194 	NULL,			/* speaker_ctl */
195 	envy_getdev,		/* getdev */
196 	NULL,			/* setfd */
197 	envy_set_port,		/* set_port */
198 	envy_get_port,		/* get_port */
199 	envy_query_devinfo,	/* query_devinfo */
200 	envy_allocm,		/* malloc */
201 	envy_freem,		/* free */
202 	envy_round_buffersize,	/* round_buffersize */
203 	NULL,			/* mappage */
204 	envy_get_props,		/* get_props */
205 	envy_trigger_output,	/* trigger_output */
206 	envy_trigger_input,	/* trigger_input */
207 	NULL
208 };
209 
210 #if NMIDI > 0
211 struct midi_hw_if envy_midi_hw_if = {
212 	envy_midi_open,
213 	envy_midi_close,
214 	envy_midi_output,
215 	NULL,				/* flush */
216 	envy_midi_getinfo,
217 	NULL				/* ioctl */
218 };
219 #endif
220 
221 struct pci_matchid envy_matchids[] = {
222 	{ PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_ICE1712 },
223 	{ PCI_VENDOR_ICENSEMBLE, PCI_PRODUCT_ICENSEMBLE_VT172x }
224 };
225 
226 /*
227  * correspondence between rates (in frames per second)
228  * and values of rate register
229  */
230 struct {
231 	int rate, reg;
232 } envy_rates[] = {
233 	{ 8000, 0x6}, { 9600, 0x3}, {11025, 0xa}, {12000, 2}, {16000, 5},
234 	{22050, 0x9}, {24000, 0x1}, {32000, 0x4}, {44100, 8}, {48000, 0},
235 	{64000, 0xf}, {88200, 0xb}, {96000, 0x7}, {-1, -1}
236 };
237 
238 /*
239  * ESI Julia cards don't have EEPROM, use this copy
240  */
241 static unsigned char julia_eeprom[ENVY_EEPROM_MAXSZ] = {
242 	/* gpio mask/dir/state is from linux */
243 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244 	0x20, 0x80, 0xf8, 0xc3,
245 	0x9f, 0xff, 0x7f,
246 	0x90, 0xff, 0x7f,
247 	0x66, 0x00, 0x00
248 };
249 
250 struct envy_codec ak4524_dac = {
251 	"ak4524 dac", ak4524_dac_ndev, ak4524_dac_devinfo, ak4524_dac_get, ak4524_dac_set
252 }, ak4524_adc = {
253 	"ak4524 adc", ak4524_adc_ndev, ak4524_adc_devinfo, ak4524_adc_get, ak4524_adc_set
254 }, ak4358_dac = {
255 	"ak4358 dac", ak4358_dac_ndev, ak4358_dac_devinfo, ak4358_dac_get, ak4358_dac_set
256 }, ak5365_adc = {
257 	"ak5365 adc", ak5365_adc_ndev, ak5365_adc_devinfo, ak5365_adc_get, ak5365_adc_set
258 }, unkenvy_codec = {
259 	"unknown codec", unkenvy_codec_ndev, NULL, NULL, NULL
260 };
261 
262 /*
263  * array with vendor/product sub-IDs to card info
264  */
265 struct envy_card envy_cards[] = {
266 	{
267 		PCI_ID_CODE(0x1412, 0xd630),
268 		"M-Audio Delta 1010",
269 		8, &ak4524_adc, 8, &ak4524_dac, 1,
270 		delta_init,
271 		delta_codec_write,
272 		NULL
273 	}, {
274 		PCI_ID_CODE(0x1412, 0xd632),
275 		"M-Audio Delta 66",
276 		4, &ak4524_adc, 4, &ak4524_dac, 0,
277 		delta_init,
278 		delta_codec_write,
279 		NULL
280 	}, {
281 #define ENVY_SUBID_DELTA44	(PCI_ID_CODE(0x1412, 0xd633))
282 		PCI_ID_CODE(0x1412, 0xd633),
283 		"M-Audio Delta 44",
284 		4, &ak4524_adc, 4, &ak4524_dac, 0,
285 		delta_init,
286 		delta_codec_write,
287 		NULL
288 	}, {
289 		PCI_ID_CODE(0x1412, 0xd63b),
290 		"M-Audio Delta 1010LT",
291 		8, &ak4524_adc, 8, &ak4524_dac, 1,
292 		delta_init,
293 		delta_codec_write,
294 		NULL
295 	}, {
296 		PCI_ID_CODE(0x1412, 0xd634),
297 		"M-Audio Audiophile 2496",
298 		2, &ak4524_adc, 2, &ak4524_dac, 1,
299 		delta_init,
300 		delta_codec_write,
301 		NULL
302 	}, {
303 		PCI_ID_CODE(0x153b, 0x1130),
304 		"Terratec EWX 24/96",
305 		2, &ak4524_adc, 2, &ak4524_dac, 1,
306 		delta_init,
307 		ewx_codec_write,
308 		NULL
309 	}, {
310 		0,
311 		"unknown 1712-based card",
312 		8, &unkenvy_codec, 8, &unkenvy_codec, 1,
313 		unkenvy_init,
314 		unkenvy_codec_write
315 	}
316 }, envy_cards_ht[] = {
317 	{
318 		PCI_ID_CODE(0x3031, 0x4553),
319 		"ESI Julia",
320 		2, &unkenvy_codec, 2, &ak4358_dac, 1,
321 		julia_init,
322 		julia_codec_write,
323 		julia_eeprom
324 	}, {
325 		PCI_ID_CODE(0x1412, 0x3632),
326 		"M-Audio Audiophile 192k",
327 		2, &unkenvy_codec, 2, &ak4358_dac, 1,
328 		ap192k_init,
329 		ap192k_codec_write
330 	}, {
331 		PCI_ID_CODE(0x1412, 0x3631),
332 		"M-Audio Revolution 5.1",
333 		2, &ak5365_adc, 6, &ak4358_dac, 1,
334 		revo51_init,
335 		revo51_codec_write
336 	}, {
337 		PCI_ID_CODE(0x1412, 0x2403),
338 		"VIA Tremor 5.1",
339 		2, &unkenvy_codec, 6, &unkenvy_codec, 1,
340 		envy_ac97_init,
341 		unkenvy_codec_write
342 	}, {
343 		PCI_ID_CODE(0x14c3, 0x1705),
344 		"Dynex DX-SC51",
345 		2, &unkenvy_codec, 6, &unkenvy_codec, 0,
346 		dynex_sc51_init,
347 		unkenvy_codec_write
348 	}, {
349 		0,
350 		"unknown 1724-based card",
351 		2, &unkenvy_codec, 8, &unkenvy_codec, 1,
352 		unkenvy_init,
353 		unkenvy_codec_write
354 	}
355 };
356 
357 
358 /*
359  * M-Audio Delta specific code
360  */
361 
362 void
363 delta_init(struct envy_softc *sc)
364 {
365 	int dev;
366 
367 	for (dev = 0; dev < sc->card->noch / 2; dev++) {
368 		envy_codec_write(sc, dev, AK4524_RST, 0x0);
369 		delay(300);
370 		envy_codec_write(sc, dev, AK4524_RST,
371 		    AK4524_RST_AD | AK4524_RST_DA);
372 		envy_codec_write(sc, dev, AK4524_FMT,
373 		    AK4524_FMT_IIS24);
374 		sc->shadow[dev][AK4524_DEEMVOL] = AK4524_DEEM_OFF;
375 		sc->shadow[dev][AK4524_ADC_GAIN0] = 0x7f;
376 		sc->shadow[dev][AK4524_ADC_GAIN1] = 0x7f;
377 		sc->shadow[dev][AK4524_DAC_GAIN0] = 0x7f;
378 		sc->shadow[dev][AK4524_DAC_GAIN1] = 0x7f;
379 	}
380 }
381 
382 void
383 delta_codec_write(struct envy_softc *sc, int dev, int addr, int data)
384 {
385 	int bits, i, reg;
386 	int clk, dout, csmask, cs;
387 
388 	/*
389 	 * GPIO pin numbers
390 	 */
391 	if (sc->card->subid == ENVY_SUBID_DELTA44) {
392 		clk = 0x20;
393 		dout = 0x10;
394 		csmask = 0xc0;
395 		cs = dev ? 0x40 : 0x80;
396 	} else {
397 		clk = 0x2;
398 		dout = 0x8;
399 		csmask = 0x70;
400 		cs = dev << 4;
401 	}
402 
403 	reg = envy_gpio_getstate(sc);
404 	reg &= ~csmask;
405 	reg |= cs;
406 	envy_gpio_setstate(sc, reg);
407 	delay(1);
408 
409 	bits  = 0xa000 | (addr << 8) | data;
410 	for (i = 0; i < 16; i++) {
411 		reg &= ~(clk | dout);
412 		reg |= (bits & 0x8000) ? dout : 0;
413 		envy_gpio_setstate(sc, reg);
414 		delay(1);
415 
416 		reg |= clk;
417 		envy_gpio_setstate(sc, reg);
418 		delay(1);
419 		bits <<= 1;
420 	}
421 
422 	reg |= csmask;
423 	envy_gpio_setstate(sc, reg);
424 	delay(1);
425 }
426 
427 /*
428  * M-Audio Audiophile 192 specific code
429  */
430 
431 /*
432  * GPIO pin numbers
433  */
434 #define AP192K_GPIO_CLK		0x2
435 #define AP192K_GPIO_DOUT	0x8
436 #define AP192K_GPIO_CSMASK	0x30
437 #define AP192K_GPIO_CS(dev)	((dev) << 4)
438 #define AP192K_GPIO_ADC_PWR	0x800
439 #define AP192K_GPIO_ADC_DFSMASK	(3 << 9)
440 #define AP192K_GPIO_ADC_DFS(v)	((v) << 9)
441 #define AP192K_GPIO_MUTE	0x400000
442 
443 void
444 ap192k_init(struct envy_softc *sc)
445 {
446 	int i, reg;
447 
448 	/* AK4358 */
449 	envy_codec_write(sc, 0, 0, 0);	/* reset */
450 	delay(300);
451 	envy_codec_write(sc, 0, 0, 0x87);	/* i2s mode */
452 	delay(1);
453 	for (i = 0; i < sc->card->noch; i++) {
454 		sc->shadow[0][AK4358_ATT(i)] = 0xff;
455 	}
456 
457 	/* AK5385 */
458 	delay(1);
459 	reg = envy_gpio_getstate(sc);
460 	reg &= ~(AP192K_GPIO_ADC_PWR | AP192K_GPIO_ADC_DFSMASK);
461 	reg |= AP192K_GPIO_ADC_DFS(0);
462 	envy_gpio_setstate(sc, reg);
463 	reg |= AP192K_GPIO_ADC_PWR;
464 	envy_gpio_setstate(sc, reg);
465 }
466 
467 void
468 ap192k_codec_write(struct envy_softc *sc, int dev, int addr, int data)
469 {
470 	int bits, i, reg;
471 
472 	reg = envy_gpio_getstate(sc);
473 	reg &= ~AP192K_GPIO_CSMASK;
474 	reg |=  AP192K_GPIO_CS(dev);
475 	envy_gpio_setstate(sc, reg);
476 	delay(1);
477 
478 	bits  = 0xa000 | (addr << 8) | data;
479 	for (i = 0; i < 16; i++) {
480 		reg &= ~(AP192K_GPIO_CLK | AP192K_GPIO_DOUT);
481 		reg |= (bits & 0x8000) ? AP192K_GPIO_DOUT : 0;
482 		envy_gpio_setstate(sc, reg);
483 		delay(1);
484 
485 		reg |= AP192K_GPIO_CLK;
486 		envy_gpio_setstate(sc, reg);
487 		delay(1);
488 		bits <<= 1;
489 	}
490 
491 	reg |= AP192K_GPIO_CSMASK;
492 	envy_gpio_setstate(sc, reg);
493 	delay(1);
494 }
495 
496 /*
497  * Terratec EWX specific code
498  */
499 
500 /*
501  * GPIO pin numbers
502  */
503 #define EWX_GPIO_CSMASK		0x01
504 #define EWX_GPIO_DOUT		0x10
505 #define EWX_GPIO_CLK		0x20
506 
507 void
508 ewx_codec_write(struct envy_softc *sc, int dev, int addr, int data)
509 {
510 	int bits, i, reg;
511 
512 	reg = envy_gpio_getstate(sc);
513 	reg |= (EWX_GPIO_CSMASK | EWX_GPIO_CLK);
514 	envy_gpio_setstate(sc, reg);
515 	delay(1);
516 
517 	bits = 0xa000 | (addr << 8) | data;
518 	for (i = 0; i < 16; i++) {
519 		reg &= ~(EWX_GPIO_CLK | EWX_GPIO_DOUT);
520 		reg |= (bits & 0x8000) ? EWX_GPIO_DOUT : 0;
521 		envy_gpio_setstate(sc, reg);
522 		delay(1);
523 
524 		reg |= EWX_GPIO_CLK;
525 		envy_gpio_setstate(sc, reg);
526 		delay(1);
527 		bits <<= 1;
528 	}
529 
530 	reg &= ~EWX_GPIO_CSMASK;
531 	envy_gpio_setstate(sc, reg);
532 	delay(1);
533 
534 	reg |= EWX_GPIO_CSMASK;
535 	envy_gpio_setstate(sc, reg);
536 	delay(1);
537 }
538 
539 
540 /*
541  * M-Audio Revolution 5.1 specific code
542  */
543 
544 #define REVO51_GPIO_CLK		0x2
545 #define REVO51_GPIO_DOUT	0x8
546 #define REVO51_GPIO_CSMASK	0x30
547 #define REVO51_GPIO_CS(dev)	((dev) ? 0x10 : 0x20)
548 #define REVO51_MUTE		0x400000
549 #define REVO51_PT2258S_SDA	0x40
550 #define REVO51_PT2258S_SCL	0x80
551 #define REVO51_PT2258S_ADDR	0x80
552 #define REVO51_PT2258S_MUTE	6
553 
554 void
555 revo51_init(struct envy_softc *sc)
556 {
557 	int i, reg;
558 
559 	/* AK4358 */
560 	envy_codec_write(sc, 0, 0, 0);	/* reset */
561 	delay(300);
562 	envy_codec_write(sc, 0, 0, 0x87);	/* i2s mode */
563 	for (i = 0; i < sc->card->noch; i++) {
564 		sc->shadow[0][AK4358_ATT(i)] = 0xff;
565 	}
566 
567 	/* AK5365 */
568 	envy_codec_write(sc, 1, AK5365_RST, 0);	/* reset */
569 	delay(300);
570 	envy_codec_write(sc, 1, AK5365_CTRL, AK5365_CTRL_I2S);	/* i2s mode */
571 	envy_codec_write(sc, 1, AK5365_RST , AK5365_RST_NORM);
572 	sc->shadow[1][AK5365_ATT(0)] = 0x7f;
573 	sc->shadow[1][AK5365_ATT(1)] = 0x7f;
574 
575 	/* PT2258S */
576 	envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xc0);	/* reset */
577 	envy_codec_write(sc, 2, REVO51_PT2258S_MUTE, 0xf9);	/* mute */
578 
579 	reg = envy_gpio_getstate(sc);
580 	reg |= REVO51_MUTE;
581 	envy_gpio_setstate(sc, reg);
582 }
583 
584 void
585 revo51_codec_write(struct envy_softc *sc, int dev, int addr, int data)
586 {
587 	int attn, bits, mask, reg;
588 	int xlat[6] = {0x90, 0x50, 0x10, 0x30, 0x70, 0xb0};
589 
590 	/* AK4358 & AK5365 */
591 	if (dev < 2) {
592 		reg = envy_gpio_getstate(sc);
593 		reg &= ~REVO51_GPIO_CSMASK;
594 		reg |=  REVO51_GPIO_CS(dev);
595 		envy_gpio_setstate(sc, reg);
596 		delay(1);
597 
598 		bits  = 0xa000 | (addr << 8) | data;
599 		for (mask = 0x8000; mask != 0; mask >>= 1) {
600 			reg &= ~(REVO51_GPIO_CLK | REVO51_GPIO_DOUT);
601 			reg |= (bits & mask) ? REVO51_GPIO_DOUT : 0;
602 			envy_gpio_setstate(sc, reg);
603 			delay(1);
604 
605 			reg |= REVO51_GPIO_CLK;
606 			envy_gpio_setstate(sc, reg);
607 			delay(1);
608 		}
609 
610 		reg |= REVO51_GPIO_CSMASK;
611 		envy_gpio_setstate(sc, reg);
612 		delay(1);
613 		return;
614 	}
615 
616 	/* PT2258S */
617 	envy_gpio_i2c_start_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
618 	envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL,
619 	    REVO51_PT2258S_ADDR);
620 
621 	if (addr == REVO51_PT2258S_MUTE) {
622 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
623 		    REVO51_PT2258S_SCL, data);
624 	} else {
625 		/* 1's digit */
626 		attn = data % 10;
627 		attn += xlat[addr];
628 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
629 		    REVO51_PT2258S_SCL, attn);
630 
631 		/* 10's digit */
632 		attn = data / 10;
633 		attn += xlat[addr] - 0x10;
634 		envy_gpio_i2c_byte_out(sc, REVO51_PT2258S_SDA,
635 		    REVO51_PT2258S_SCL, attn);
636 	}
637 
638 	envy_gpio_i2c_stop_bit(sc, REVO51_PT2258S_SDA, REVO51_PT2258S_SCL);
639 }
640 
641 /*
642  * Generic AC'97 initialization
643  */
644 
645 void
646 envy_ac97_init(struct envy_softc *sc)
647 {
648 	sc->isac97 = 1;
649 	sc->host_if.arg = sc;
650 	sc->host_if.attach = envy_ac97_attach_codec;
651 	sc->host_if.read = envy_ac97_read_codec;
652 	sc->host_if.write = envy_ac97_write_codec;
653 	sc->host_if.reset = envy_ac97_reset_codec;
654 	sc->host_if.flags = envy_ac97_flags_codec;
655 
656 	if (ac97_attach(&sc->host_if) != 0)
657 		printf("%s: can't attach ac97\n", DEVNAME(sc));
658 }
659 
660 /*
661  * Dynex
662  */
663 
664 void
665 dynex_sc51_init(struct envy_softc *sc)
666 {
667 	sc->codec_flags |= AC97_HOST_VT1616_DYNEX;
668 	envy_ac97_init(sc);
669 }
670 
671 /*
672  * ESI Julia specific code
673  */
674 
675 void
676 julia_init(struct envy_softc *sc)
677 {
678 	int i;
679 
680 	envy_codec_write(sc, 0, 0, 0);	/* reset */
681 	delay(300);
682 	envy_codec_write(sc, 0, 0, 0x87);	/* i2s mode */
683 	for (i = 0; i < sc->card->noch; i++) {
684 		sc->shadow[0][AK4358_ATT(i)] = 0xff;
685 	}
686 }
687 
688 void
689 julia_codec_write(struct envy_softc *sc, int dev, int addr, int data)
690 {
691 #define JULIA_AK4358_ADDR	0x11
692 	envy_i2c_write(sc, JULIA_AK4358_ADDR, addr, data);
693 }
694 
695 /*
696  * unknown card, ignore codecs setup and hope it works with the power on
697  * settings
698  */
699 
700 void
701 unkenvy_init(struct envy_softc *sc)
702 {
703 }
704 
705 void
706 unkenvy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
707 {
708 }
709 
710 int
711 unkenvy_codec_ndev(struct envy_softc *sc)
712 {
713 	return 0;
714 }
715 
716 /*
717  * AK 4358 DAC specific code
718  */
719 int
720 ak4358_dac_ndev(struct envy_softc *sc)
721 {
722 	/* 1 volume knob per channel */
723 	return sc->card->noch;
724 }
725 
726 void
727 ak4358_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
728 {
729 	dev->type = AUDIO_MIXER_VALUE;
730 	dev->mixer_class = ENVY_MIX_CLASSOUT;
731 	dev->un.v.delta = 2;
732 	dev->un.v.num_channels = 1;
733 	snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
734 	    AudioNline "-%d", idx);
735 	strlcpy(dev->un.v.units.name, AudioNvolume,
736 	    MAX_AUDIO_DEV_LEN);
737 }
738 
739 void
740 ak4358_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
741 {
742 	int val;
743 
744 	val = envy_codec_read(sc, 0, AK4358_ATT(idx)) & ~AK4358_ATT_EN;
745 	ctl->un.value.num_channels = 1;
746 	ctl->un.value.level[0] = 2 * val;
747 }
748 
749 int
750 ak4358_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
751 {
752 	int val;
753 
754 	if (ctl->un.value.num_channels != 1)
755 		return EINVAL;
756 	val = ctl->un.value.level[0] / 2;
757 	envy_codec_write(sc, 0, AK4358_ATT(idx), val | AK4358_ATT_EN);
758 	return 0;
759 }
760 
761 /*
762  * AK 4524 DAC specific code
763  */
764 int
765 ak4524_dac_ndev(struct envy_softc *sc)
766 {
767 	/* 1 mute + 2 volume knobs per channel pair */
768 	return 3 * (sc->card->noch / 2);
769 }
770 
771 void
772 ak4524_dac_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
773 {
774 	int ndev;
775 
776 	ndev = sc->card->noch;
777 	if (idx < ndev) {
778 		dev->type = AUDIO_MIXER_VALUE;
779 		dev->mixer_class = ENVY_MIX_CLASSOUT;
780 		dev->un.v.delta = 2;
781 		dev->un.v.num_channels = 1;
782 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
783 		    AudioNline "-%d", idx);
784 		strlcpy(dev->un.v.units.name, AudioNvolume,
785 		    MAX_AUDIO_DEV_LEN);
786 	} else {
787 		idx -= ndev;
788 		dev->type = AUDIO_MIXER_ENUM;
789 		dev->mixer_class = ENVY_MIX_CLASSOUT;
790 		dev->un.e.member[0].ord = 0;
791 		strlcpy(dev->un.e.member[0].label.name, AudioNoff,
792 		    MAX_AUDIO_DEV_LEN);
793 		dev->un.e.member[1].ord = 1;
794 		strlcpy(dev->un.e.member[1].label.name, AudioNon,
795 		   MAX_AUDIO_DEV_LEN);
796 		dev->un.e.num_mem = 2;
797 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
798 		    AudioNline "-%d:%d_" AudioNmute, 2 * idx, 2 * idx + 1);
799 	}
800 }
801 
802 void
803 ak4524_dac_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
804 {
805 	int val, ndev;
806 
807 	ndev = sc->card->noch;
808 	if (idx < ndev) {
809 		val = envy_codec_read(sc, idx / 2,
810 		    (idx % 2) + AK4524_DAC_GAIN0);
811 		ctl->un.value.num_channels = 1;
812 		ctl->un.value.level[0] = 2 * val;
813 	} else {
814 		idx -= ndev;
815 		val = envy_codec_read(sc, idx, AK4524_DEEMVOL);
816 		ctl->un.ord = (val & AK4524_MUTE) ? 1 : 0;
817 	}
818 }
819 
820 int
821 ak4524_dac_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
822 {
823 	int val, ndev;
824 
825 	ndev = sc->card->noch;
826 	if (idx < ndev) {
827 		if (ctl->un.value.num_channels != 1)
828 			return EINVAL;
829 		val = ctl->un.value.level[0] / 2;
830 		envy_codec_write(sc, idx / 2,
831 		    (idx % 2) + AK4524_DAC_GAIN0, val);
832 	} else {
833 		idx -= ndev;
834 		if (ctl->un.ord >= 2)
835 			return EINVAL;
836 		val = AK4524_DEEM_OFF | (ctl->un.ord ? AK4524_MUTE : 0);
837 		envy_codec_write(sc, idx, AK4524_DEEMVOL, val);
838 	}
839 	return 0;
840 }
841 
842 /*
843  * AK 4524 ADC specific code
844  */
845 int
846 ak4524_adc_ndev(struct envy_softc *sc)
847 {
848 	/* one volume per channel */
849 	return sc->card->nich;
850 }
851 
852 void
853 ak4524_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
854 {
855 	dev->type = AUDIO_MIXER_VALUE;
856 	dev->mixer_class = ENVY_MIX_CLASSIN;
857 	dev->un.v.delta = 2;
858 	dev->un.v.num_channels = 1;
859 	snprintf(dev->label.name, MAX_AUDIO_DEV_LEN, AudioNline "-%d", idx);
860 	strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
861 }
862 
863 void
864 ak4524_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
865 {
866 	int val;
867 
868 	val = envy_codec_read(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0);
869 	ctl->un.value.num_channels = 1;
870 	ctl->un.value.level[0] = 2 * val;
871 }
872 
873 int
874 ak4524_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
875 {
876 	int val;
877 
878 	if (ctl->un.value.num_channels != 1)
879 		return EINVAL;
880 	val = ctl->un.value.level[0] / 2;
881 	envy_codec_write(sc, idx / 2, (idx % 2) + AK4524_ADC_GAIN0, val);
882 	return 0;
883 }
884 
885 /*
886  * AK 5365 ADC specific code
887  */
888 int
889 ak5365_adc_ndev(struct envy_softc *sc)
890 {
891 	/* 1 source + 2 volume knobs per channel pair */
892 	return (sc->card->nich + 1);
893 }
894 
895 void
896 ak5365_adc_devinfo(struct envy_softc *sc, struct mixer_devinfo *dev, int idx)
897 {
898 	int ndev, i;
899 
900 	ndev = sc->card->nich;
901 	if (idx < ndev) {
902 		dev->type = AUDIO_MIXER_VALUE;
903 		dev->mixer_class = ENVY_MIX_CLASSIN;
904 		dev->un.v.delta = 2;
905 		dev->un.v.num_channels = 1;
906 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
907 		    AudioNline "-%d", idx);
908 		strlcpy(dev->un.v.units.name, AudioNvolume,
909 		    MAX_AUDIO_DEV_LEN);
910 	} else {
911 		dev->type = AUDIO_MIXER_ENUM;
912 		dev->mixer_class = ENVY_MIX_CLASSIN;
913 		for (i = 0; i < 5; i++) {
914 			dev->un.e.member[i].ord = i;
915 			snprintf(dev->un.e.member[i].label.name,
916 			    MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
917 		}
918 		dev->un.e.num_mem = 5;
919 		strlcpy(dev->label.name, AudioNsource,
920 		    MAX_AUDIO_DEV_LEN);
921 	}
922 }
923 
924 void
925 ak5365_adc_get(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
926 {
927 	int val, ndev;
928 
929 	ndev = sc->card->nich;
930 	if (idx < ndev) {
931 		val = envy_codec_read(sc, 1, AK5365_ATT(idx));
932 		ctl->un.value.num_channels = 1;
933 		ctl->un.value.level[0] = 2 * val;
934 	} else {
935 		ctl->un.ord = envy_codec_read(sc, 1, AK5365_SRC);
936 	}
937 }
938 
939 int
940 ak5365_adc_set(struct envy_softc *sc, struct mixer_ctrl *ctl, int idx)
941 {
942 	int val, ndev;
943 
944 	ndev = sc->card->nich;
945 	if (idx < ndev) {
946 		if (ctl->un.value.num_channels != 1)
947 			return EINVAL;
948 		val = ctl->un.value.level[0] / 2;
949 		envy_codec_write(sc, 1, AK5365_ATT(idx), val);
950 	} else {
951 		if (ctl->un.ord >= 5)
952 			return EINVAL;
953 		val = ctl->un.ord & AK5365_SRC_MASK;
954 		envy_codec_write(sc, 1, AK5365_SRC, val);
955 	}
956 	return 0;
957 }
958 
959 /*
960  * generic Envy24 and Envy24HT code, common to all cards
961  */
962 
963 int
964 envy_ccs_read(struct envy_softc *sc, int reg)
965 {
966 	int val;
967 
968 	val = bus_space_read_1(sc->ccs_iot, sc->ccs_ioh, reg);
969 	bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
970 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
971 	return val;
972 }
973 
974 void
975 envy_ccs_write(struct envy_softc *sc, int reg, int val)
976 {
977 	bus_space_write_1(sc->ccs_iot, sc->ccs_ioh, reg, val);
978 	bus_space_barrier(sc->ccs_iot, sc->ccs_ioh, 0, sc->ccs_iosz,
979 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
980 }
981 
982 int
983 envy_mt_read_1(struct envy_softc *sc, int reg)
984 {
985 	int val;
986 
987 	val = bus_space_read_1(sc->mt_iot, sc->mt_ioh, reg);
988 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
989 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
990 	return val;
991 }
992 
993 void
994 envy_mt_write_1(struct envy_softc *sc, int reg, int val)
995 {
996 	bus_space_write_1(sc->mt_iot, sc->mt_ioh, reg, val);
997 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
998 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
999 }
1000 
1001 int
1002 envy_mt_read_2(struct envy_softc *sc, int reg)
1003 {
1004 	int val;
1005 
1006 	val = bus_space_read_2(sc->mt_iot, sc->mt_ioh, reg);
1007 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1008 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1009 	return val;
1010 }
1011 
1012 void
1013 envy_mt_write_2(struct envy_softc *sc, int reg, int val)
1014 {
1015 	bus_space_write_2(sc->mt_iot, sc->mt_ioh, reg, val);
1016 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1017 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1018 }
1019 
1020 int
1021 envy_mt_read_4(struct envy_softc *sc, int reg)
1022 {
1023 	int val;
1024 
1025 	val = bus_space_read_4(sc->mt_iot, sc->mt_ioh, reg);
1026 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1027 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1028 	return val;
1029 }
1030 
1031 void
1032 envy_mt_write_4(struct envy_softc *sc, int reg, int val)
1033 {
1034 	bus_space_write_4(sc->mt_iot, sc->mt_ioh, reg, val);
1035 	bus_space_barrier(sc->mt_iot, sc->mt_ioh, 0, sc->mt_iosz,
1036 	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1037 }
1038 
1039 int
1040 envy_cci_read(struct envy_softc *sc, int index)
1041 {
1042 	int val;
1043 
1044 	envy_ccs_write(sc, ENVY_CCI_INDEX, index);
1045 	val = envy_ccs_read(sc, ENVY_CCI_DATA);
1046 	return val;
1047 }
1048 
1049 void
1050 envy_cci_write(struct envy_softc *sc, int index, int data)
1051 {
1052 	envy_ccs_write(sc, ENVY_CCI_INDEX, index);
1053 	envy_ccs_write(sc, ENVY_CCI_DATA, data);
1054 }
1055 
1056 int
1057 envy_gpio_getstate(struct envy_softc *sc)
1058 {
1059 	if (sc->isht) {
1060 		return envy_ccs_read(sc, ENVY_CCS_GPIODATA0) |
1061 		    (envy_ccs_read(sc, ENVY_CCS_GPIODATA1) << 8) |
1062 		    (envy_ccs_read(sc, ENVY_CCS_GPIODATA2) << 16);
1063 	} else
1064 		return envy_cci_read(sc, ENVY_CCI_GPIODATA);
1065 }
1066 
1067 void
1068 envy_gpio_setstate(struct envy_softc *sc, int reg)
1069 {
1070 	if (sc->isht) {
1071 		envy_ccs_write(sc, ENVY_CCS_GPIODATA0, reg & 0xff);
1072 		envy_ccs_write(sc, ENVY_CCS_GPIODATA1, (reg >> 8) & 0xff);
1073 		envy_ccs_write(sc, ENVY_CCS_GPIODATA2, (reg >> 16) & 0xff);
1074 	} else
1075 		envy_cci_write(sc, ENVY_CCI_GPIODATA, reg);
1076 }
1077 
1078 int
1079 envy_gpio_getmask(struct envy_softc *sc)
1080 {
1081 	if (sc->isht) {
1082 		return envy_ccs_read(sc, ENVY_CCS_GPIOMASK0) |
1083 		    (envy_ccs_read(sc, ENVY_CCS_GPIOMASK1) << 8) |
1084 		    (envy_ccs_read(sc, ENVY_CCS_GPIOMASK2) << 16);
1085 	} else
1086 		return envy_cci_read(sc, ENVY_CCI_GPIOMASK);
1087 }
1088 
1089 void
1090 envy_gpio_setmask(struct envy_softc *sc, int mask)
1091 {
1092 	if (sc->isht) {
1093 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK0, mask & 0xff);
1094 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK1, (mask >> 8) & 0xff);
1095 		envy_ccs_write(sc, ENVY_CCS_GPIOMASK2, (mask >> 16) & 0xff);
1096 	} else
1097 		envy_cci_write(sc, ENVY_CCI_GPIOMASK, mask);
1098 }
1099 
1100 int
1101 envy_gpio_getdir(struct envy_softc *sc)
1102 {
1103 	if (sc->isht) {
1104 		return envy_ccs_read(sc, ENVY_CCS_GPIODIR0) |
1105 		    (envy_ccs_read(sc, ENVY_CCS_GPIODIR1) << 8) |
1106 		    (envy_ccs_read(sc, ENVY_CCS_GPIODIR2) << 16);
1107 	} else
1108 		return envy_cci_read(sc, ENVY_CCI_GPIODIR);
1109 }
1110 
1111 void
1112 envy_gpio_setdir(struct envy_softc *sc, int dir)
1113 {
1114 	if (sc->isht) {
1115 		envy_ccs_write(sc, ENVY_CCS_GPIODIR0, dir & 0xff);
1116 		envy_ccs_write(sc, ENVY_CCS_GPIODIR1, (dir >> 8) & 0xff);
1117 		envy_ccs_write(sc, ENVY_CCS_GPIODIR2, (dir >> 16) & 0xff);
1118 	} else
1119 		envy_cci_write(sc, ENVY_CCI_GPIODIR, dir);
1120 }
1121 
1122 void
1123 envy_gpio_i2c_start_bit(struct envy_softc *sc, int sda, int scl)
1124 {
1125 	int reg;
1126 
1127 	reg = envy_gpio_getstate(sc);
1128 	reg |= (sda | scl);
1129 	envy_gpio_setstate(sc, reg);
1130 	delay(5);
1131 	reg &= ~sda;
1132 	envy_gpio_setstate(sc, reg);
1133 	delay(4);
1134 	reg &= ~scl;
1135 	envy_gpio_setstate(sc, reg);
1136 	delay(5);
1137 }
1138 
1139 void
1140 envy_gpio_i2c_stop_bit(struct envy_softc *sc, int sda, int scl)
1141 {
1142 	int reg;
1143 
1144 	reg = envy_gpio_getstate(sc);
1145 	reg &= ~sda;
1146 	reg |= scl;
1147 	envy_gpio_setstate(sc, reg);
1148 	delay(4);
1149 	reg |= sda;
1150 	envy_gpio_setstate(sc, reg);
1151 }
1152 
1153 void
1154 envy_gpio_i2c_byte_out(struct envy_softc *sc, int sda, int scl, int val)
1155 {
1156 	int mask, reg;
1157 
1158 	reg = envy_gpio_getstate(sc);
1159 
1160 	for (mask = 0x80; mask != 0; mask >>= 1) {
1161 		reg &= ~sda;
1162 		reg |= (val & mask) ? sda : 0;
1163 		envy_gpio_setstate(sc, reg);
1164 		delay(1);
1165 		reg |= scl;
1166 		envy_gpio_setstate(sc, reg);
1167 		delay(4);
1168 		reg &= ~scl;
1169 		envy_gpio_setstate(sc, reg);
1170 		delay(5);
1171 	}
1172 
1173 	reg |= scl;
1174 	envy_gpio_setstate(sc, reg);
1175 	delay(4);
1176 	reg &= ~scl;
1177 	envy_gpio_setstate(sc, reg);
1178 	delay(5);
1179 }
1180 
1181 void
1182 envy_i2c_wait(struct envy_softc *sc)
1183 {
1184 	int timeout = 50, st;
1185 
1186 	for (;;) {
1187 		st = envy_ccs_read(sc, ENVY_I2C_CTL);
1188 		if (!(st & ENVY_I2C_CTL_BUSY))
1189 			break;
1190 		if (timeout == 0) {
1191 			printf("%s: i2c busy timeout\n", DEVNAME(sc));
1192 			break;
1193 		}
1194 		delay(50);
1195 		timeout--;
1196 	}
1197 }
1198 
1199 int
1200 envy_i2c_read(struct envy_softc *sc, int dev, int addr)
1201 {
1202 	envy_i2c_wait(sc);
1203 	envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
1204 	envy_i2c_wait(sc);
1205 	envy_ccs_write(sc, ENVY_I2C_DEV, dev << 1);
1206 	envy_i2c_wait(sc);
1207 	return envy_ccs_read(sc, ENVY_I2C_DATA);
1208 }
1209 
1210 void
1211 envy_i2c_write(struct envy_softc *sc, int dev, int addr, int data)
1212 {
1213 	if (dev == 0x50) {
1214 		printf("%s: writing on eeprom is evil...\n", DEVNAME(sc));
1215 		return;
1216 	}
1217 	envy_i2c_wait(sc);
1218 	envy_ccs_write(sc, ENVY_I2C_ADDR, addr);
1219 	envy_i2c_wait(sc);
1220 	envy_ccs_write(sc, ENVY_I2C_DATA, data);
1221 	envy_i2c_wait(sc);
1222 	envy_ccs_write(sc, ENVY_I2C_DEV, (dev << 1) | 1);
1223 }
1224 
1225 int
1226 envy_codec_read(struct envy_softc *sc, int dev, int addr) {
1227 	return sc->shadow[dev][addr];
1228 }
1229 
1230 void
1231 envy_codec_write(struct envy_softc *sc, int dev, int addr, int data)
1232 {
1233 	DPRINTFN(2, "envy_codec_write: %d, %d, 0x%x\n", dev, addr, data);
1234 	sc->shadow[dev][addr] = data;
1235 	sc->card->codec_write(sc, dev, addr, data);
1236 }
1237 
1238 int
1239 envy_eeprom_gpioxxx(struct envy_softc *sc, int addr)
1240 {
1241 	int val;
1242 
1243 	val = sc->eeprom[addr];
1244 	if (sc->isht) {
1245 		val |= sc->eeprom[++addr] << 8;
1246 		val |= sc->eeprom[++addr] << 16;
1247 	}
1248 	return val;
1249 }
1250 
1251 int
1252 envy_ac97_wait(struct envy_softc *sc)
1253 {
1254 	int timeout = 50, st;
1255 
1256 	for (;;) {
1257 		st = envy_mt_read_1(sc, ENVY_MT_AC97_CMD);
1258 		if ((st & ENVY_MT_AC97_READY) && !(st & ENVY_MT_AC97_CMD_MASK)) {
1259 			st = 0;
1260 			break;
1261 		}
1262 		if (timeout == 0) {
1263 			st = -1;
1264 			break;
1265 		}
1266 		delay(50);
1267 		timeout--;
1268 	}
1269 
1270 	return (st);
1271 }
1272 
1273 int
1274 envy_ac97_attach_codec(void *hdl, struct ac97_codec_if *codec_if)
1275 {
1276 	struct envy_softc *sc = hdl;
1277 
1278 	sc->codec_if = codec_if;
1279 
1280 	return (0);
1281 }
1282 
1283 int
1284 envy_ac97_read_codec(void *hdl, u_int8_t reg, u_int16_t *result)
1285 {
1286 	struct envy_softc *sc = hdl;
1287 
1288 	if (envy_ac97_wait(sc)) {
1289 		printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
1290 		return (-1);
1291 	}
1292 
1293 	envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
1294 	envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
1295 	    ENVY_MT_AC97_CMD_RD);
1296 	delay(50);
1297 
1298 	if (envy_ac97_wait(sc)) {
1299 		printf("%s: envy_ac97_read_codec: timed out\n", DEVNAME(sc));
1300 		return (-1);
1301 	}
1302 
1303 	*result = envy_mt_read_2(sc, ENVY_MT_AC97_DATA);
1304 
1305 	return (0);
1306 }
1307 
1308 int
1309 envy_ac97_write_codec(void *hdl, u_int8_t reg, u_int16_t data)
1310 {
1311 	struct envy_softc *sc = hdl;
1312 
1313 	if (envy_ac97_wait(sc)) {
1314 		printf("%s: envy_ac97_write_codec: timed out\n", DEVNAME(sc));
1315 		return (-1);
1316 	}
1317 
1318 	envy_mt_write_1(sc, ENVY_MT_AC97_IDX, reg & 0x7f);
1319 	envy_mt_write_2(sc, ENVY_MT_AC97_DATA, data);
1320 	envy_mt_write_1(sc, ENVY_MT_AC97_CMD,
1321 	    ENVY_MT_AC97_CMD_WR);
1322 	delay(50);
1323 
1324 	return (0);
1325 }
1326 
1327 void
1328 envy_ac97_reset_codec(void *hdl)
1329 {
1330 	struct envy_softc *sc = hdl;
1331 
1332 	envy_mt_write_1(sc, ENVY_MT_AC97_CMD, ENVY_MT_AC97_CMD_RST);
1333 	delay(50);
1334 	envy_mt_write_1(sc, ENVY_MT_AC97_CMD, 0);
1335 	delay(50);
1336 
1337 	if (envy_ac97_wait(sc)) {
1338 		printf("%s: envy_ac97_reset_codec: timed out\n", DEVNAME(sc));
1339 	}
1340 
1341 	return;
1342 }
1343 
1344 enum ac97_host_flags
1345 envy_ac97_flags_codec(void *hdl)
1346 {
1347 	struct envy_softc *sc = hdl;
1348 
1349 	return (sc->codec_flags);
1350 }
1351 
1352 void
1353 envy_midi_wait(struct envy_softc *sc)
1354 {
1355 	int i, st;
1356 
1357 	for (i = 100;; i--) {
1358 		st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
1359 		if (!(st & ENVY_MIDISTAT_OBUSY(sc)))
1360 			break;
1361 		if (i == 0) {
1362 			printf("%s: midi wait timeout\n", DEVNAME(sc));
1363 			break;
1364 		}
1365 		delay(10);
1366 	}
1367 }
1368 
1369 void
1370 envy_reset(struct envy_softc *sc)
1371 {
1372 	int i, reg;
1373 
1374 	/*
1375 	 * full reset
1376 	 */
1377 	envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_RESET | ENVY_CTL_NATIVE);
1378 	delay(200);
1379 	envy_ccs_write(sc, ENVY_CTL, ENVY_CTL_NATIVE);
1380 	delay(200);
1381 
1382 	/*
1383 	 * read EEPROM using i2c device or from a static array
1384 	 */
1385 	if (sc->card->eeprom == NULL) {
1386 		for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
1387 			sc->eeprom[i] = envy_i2c_read(sc, ENVY_I2C_DEV_EEPROM, i);
1388 		}
1389 #ifdef ENVY_DEBUG
1390 		printf("%s: eeprom: ", DEVNAME(sc));
1391 		for (i = 0; i < ENVY_EEPROM_MAXSZ; i++) {
1392 			printf(" %02x", (unsigned)sc->eeprom[i]);
1393 		}
1394 		printf("\n");
1395 #endif
1396 	} else
1397 		memcpy(sc->eeprom, sc->card->eeprom, ENVY_EEPROM_MAXSZ);
1398 
1399 	/*
1400 	 * write EEPROM values to corresponding registers
1401 	 */
1402 	if (sc->isht) {
1403 		envy_ccs_write(sc, ENVY_CCS_CONF,
1404 		    sc->eeprom[ENVY_EEPROM_CONF]);
1405 		envy_ccs_write(sc, ENVY_CCS_ACLINK,
1406 		    sc->eeprom[ENVY_EEPROM_ACLINK]);
1407 		envy_ccs_write(sc, ENVY_CCS_I2S,
1408 		    sc->eeprom[ENVY_EEPROM_I2S]);
1409 		envy_ccs_write(sc, ENVY_CCS_SPDIF,
1410 		    sc->eeprom[ENVY_EEPROM_SPDIF]);
1411 	} else {
1412 		pci_conf_write(sc->pci_pc, sc->pci_tag, ENVY_CONF,
1413 		    sc->eeprom[ENVY_EEPROM_CONF] |
1414 		    (sc->eeprom[ENVY_EEPROM_ACLINK] << 8) |
1415 		    (sc->eeprom[ENVY_EEPROM_I2S] << 16) |
1416 		    (sc->eeprom[ENVY_EEPROM_SPDIF] << 24));
1417 	}
1418 
1419 	envy_gpio_setmask(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOMASK(sc)));
1420 	envy_gpio_setdir(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIODIR(sc)));
1421 	envy_gpio_setstate(sc, envy_eeprom_gpioxxx(sc, ENVY_EEPROM_GPIOST(sc)));
1422 
1423 	DPRINTF("%s: gpio_mask = %02x\n", DEVNAME(sc),
1424 		envy_gpio_getmask(sc));
1425 	DPRINTF("%s: gpio_dir = %02x\n", DEVNAME(sc),
1426 		envy_gpio_getdir(sc));
1427 	DPRINTF("%s: gpio_state = %02x\n", DEVNAME(sc),
1428 		envy_gpio_getstate(sc));
1429 
1430 	if (sc->isht) {
1431 		/*
1432 		 * set water marks so we get an interrupt for each byte
1433 		 */
1434 		envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1);
1435 		envy_ccs_write(sc, ENVY_CCS_MIDIWAT, 1 | ENVY_CCS_MIDIWAT_RX);
1436 	}
1437 
1438 	/*
1439 	 * switch to UART mode
1440 	 */
1441 	envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, 0xff);
1442 	envy_midi_wait(sc);
1443 	envy_ccs_write(sc, ENVY_CCS_MIDISTAT0, ENVY_MIDISTAT_UART);
1444 	envy_midi_wait(sc);
1445 	if (!sc->isht)
1446 		(void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
1447 
1448 	/*
1449 	 * clear all interrupts and unmask used ones
1450 	 */
1451 	envy_ccs_write(sc, ENVY_CCS_INTSTAT, 0xff);
1452 	reg = ~ENVY_CCS_INT_MT;
1453 	if (sc->midi_isopen)
1454 		reg &= ~ENVY_CCS_INT_MIDI0;
1455 	envy_ccs_write(sc, ENVY_CCS_INTMASK, ~ENVY_CCS_INT_MT);
1456 	if (sc->isht) {
1457 		envy_mt_write_1(sc, ENVY_MT_NSTREAM, 4 - sc->card->noch / 2);
1458 		envy_mt_write_1(sc, ENVY_MT_IMASK, ~(ENVY_MT_IMASK_PDMA0 |
1459 		    ENVY_MT_IMASK_RDMA0 | ENVY_MT_IMASK_ERR));
1460 	}
1461 	sc->iactive = 0;
1462 	sc->oactive = 0;
1463 	sc->card->init(sc);
1464 }
1465 
1466 int
1467 envy_lineout_getsrc(struct envy_softc *sc, int out)
1468 {
1469 	int reg, shift, src;
1470 
1471 	if (sc->isht) {
1472 		reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
1473 		DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1474 		shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1475 		src = (reg >> shift) & ENVY_MT_HTSRC_MASK;
1476 		if (src == ENVY_MT_HTSRC_DMA) {
1477 			return ENVY_MIX_OUTSRC_DMA;
1478 		} else {
1479 			src -= ENVY_MT_HTSRC_LINE;
1480 			return ENVY_MIX_OUTSRC_LINEIN + src;
1481 		}
1482 	}
1483 
1484 	reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
1485 	DPRINTF("%s: outsrc=%x\n", DEVNAME(sc), reg);
1486 	shift = (out  & 1) ? (out & ~1) + 8 : out;
1487 	src = (reg >> shift) & 3;
1488 	if (src == ENVY_MT_OUTSRC_DMA) {
1489 		return ENVY_MIX_OUTSRC_DMA;
1490 	} else if (src == ENVY_MT_OUTSRC_MON) {
1491 		return ENVY_MIX_OUTSRC_MON;
1492 	}
1493 	reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
1494 	DPRINTF("%s: insel=%x\n", DEVNAME(sc), reg);
1495 	reg = (reg >> (out * 4)) & 0xf;
1496 	if (src == ENVY_MT_OUTSRC_LINE)
1497 		return ENVY_MIX_OUTSRC_LINEIN + (reg & 7);
1498 	else
1499 		return ENVY_MIX_OUTSRC_SPDIN + (reg >> 3);
1500 }
1501 
1502 void
1503 envy_lineout_setsrc(struct envy_softc *sc, int out, int src)
1504 {
1505 	int reg, shift, mask, sel;
1506 
1507 	if (sc->isht) {
1508 		if (src < ENVY_MIX_OUTSRC_SPDIN) {
1509 			sel = ENVY_MT_HTSRC_LINE;
1510 			sel += src;
1511 		} else if (src < ENVY_MIX_OUTSRC_DMA) {
1512 			sel = ENVY_MT_HTSRC_SPD;
1513 			sel += src - ENVY_MIX_OUTSRC_SPDIN;
1514 		} else {
1515 			sel = ENVY_MT_HTSRC_DMA;
1516 		}
1517 		shift = 3 * (out / 2) + ((out & 1) ? 20 : 8);
1518 		mask = ENVY_MT_HTSRC_MASK << shift;
1519 		reg = envy_mt_read_4(sc, ENVY_MT_HTSRC);
1520 		reg = (reg & ~mask) | (sel << shift);
1521 		envy_mt_write_4(sc, ENVY_MT_HTSRC, reg);
1522 		DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1523 		return;
1524 	}
1525 
1526 	if (src < ENVY_MIX_OUTSRC_DMA) {
1527 		/*
1528 		 * linein and spdin are used as output source so we
1529 		 * must select the input source channel number
1530 		 */
1531 		if (src < ENVY_MIX_OUTSRC_SPDIN)
1532 			sel = src - ENVY_MIX_OUTSRC_LINEIN;
1533 		else
1534 			sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1535 
1536 		shift = out * ENVY_MT_INSEL_BITS;
1537 		mask = ENVY_MT_INSEL_MASK << shift;
1538 		reg = envy_mt_read_4(sc, ENVY_MT_INSEL);
1539 		reg = (reg & ~mask) | (sel << shift);
1540 		envy_mt_write_4(sc, ENVY_MT_INSEL, reg);
1541 		DPRINTF("%s: insel <- %x\n", DEVNAME(sc), reg);
1542 	}
1543 
1544 	/*
1545 	 * set the lineout route register
1546 	 */
1547 	if (src < ENVY_MIX_OUTSRC_SPDIN) {
1548 		sel = ENVY_MT_OUTSRC_LINE;
1549 	} else if (src < ENVY_MIX_OUTSRC_DMA) {
1550 		sel = ENVY_MT_OUTSRC_SPD;
1551 	} else if (src == ENVY_MIX_OUTSRC_DMA) {
1552 		sel = ENVY_MT_OUTSRC_DMA;
1553 	} else {
1554 		sel = ENVY_MT_OUTSRC_MON;
1555 	}
1556 	shift = (out  & 1) ? (out & ~1) + 8 : out;
1557 	mask = ENVY_MT_OUTSRC_MASK << shift;
1558 	reg = envy_mt_read_2(sc, ENVY_MT_OUTSRC);
1559 	reg = (reg & ~mask) | (sel << shift);
1560 	envy_mt_write_2(sc, ENVY_MT_OUTSRC, reg);
1561 	DPRINTF("%s: outsrc <- %x\n", DEVNAME(sc), reg);
1562 }
1563 
1564 
1565 int
1566 envy_spdout_getsrc(struct envy_softc *sc, int out)
1567 {
1568 	int reg, src, sel;
1569 
1570 	reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
1571 	DPRINTF("%s: spdroute=%x\n", DEVNAME(sc), reg);
1572 	src = (out == 0) ? reg : reg >> 2;
1573 	src &= ENVY_MT_SPDSRC_MASK;
1574 	if (src == ENVY_MT_SPDSRC_DMA) {
1575 		return ENVY_MIX_OUTSRC_DMA;
1576 	} else if (src == ENVY_MT_SPDSRC_MON) {
1577 		return ENVY_MIX_OUTSRC_MON;
1578 	}
1579 
1580 	sel = (out == 0) ? reg >> 8 : reg >> 12;
1581 	sel &= ENVY_MT_SPDSEL_MASK;
1582 	if (src == ENVY_MT_SPDSRC_LINE)
1583 		return ENVY_MIX_OUTSRC_LINEIN + (sel & 7);
1584 	else
1585 		return ENVY_MIX_OUTSRC_SPDIN + (sel >> 3);
1586 }
1587 
1588 void
1589 envy_spdout_setsrc(struct envy_softc *sc, int out, int src)
1590 {
1591 	int reg, shift, mask, sel;
1592 
1593 	reg = envy_mt_read_2(sc, ENVY_MT_SPDROUTE);
1594 	if (src < ENVY_MIX_OUTSRC_DMA) {
1595 		/*
1596 		 * linein and spdin are used as output source so we
1597 		 * must select the input source channel number
1598 		 */
1599 		if (src < ENVY_MIX_OUTSRC_SPDIN)
1600 			sel = src - ENVY_MIX_OUTSRC_LINEIN;
1601 		else
1602 			sel = (src - ENVY_MIX_OUTSRC_SPDIN) << 3;
1603 
1604 		shift = 8 + out * ENVY_MT_SPDSEL_BITS;
1605 		mask = ENVY_MT_SPDSEL_MASK << shift;
1606 		reg = (reg & ~mask) | (sel << shift);
1607 	}
1608 
1609 	/*
1610 	 * set the lineout route register
1611 	 */
1612 	if (src < ENVY_MIX_OUTSRC_SPDIN) {
1613 		sel = ENVY_MT_OUTSRC_LINE;
1614 	} else if (src < ENVY_MIX_OUTSRC_DMA) {
1615 		sel = ENVY_MT_OUTSRC_SPD;
1616 	} else if (src == ENVY_MIX_OUTSRC_DMA) {
1617 		sel = ENVY_MT_OUTSRC_DMA;
1618 	} else {
1619 		sel = ENVY_MT_OUTSRC_MON;
1620 	}
1621 	shift = out * 2;
1622 	mask = ENVY_MT_SPDSRC_MASK << shift;
1623 	reg = (reg & ~mask) | (sel << shift);
1624 	envy_mt_write_2(sc, ENVY_MT_SPDROUTE, reg);
1625 	DPRINTF("%s: spdroute <- %x\n", DEVNAME(sc), reg);
1626 }
1627 
1628 void
1629 envy_mon_getvol(struct envy_softc *sc, int idx, int ch, int *val)
1630 {
1631 	int reg;
1632 
1633 	envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
1634 	reg = envy_mt_read_1(sc, ENVY_MT_MONDATA + ch);
1635 	*val = 0x7f - (reg & 0x7f);
1636 }
1637 
1638 void
1639 envy_mon_setvol(struct envy_softc *sc, int idx, int ch, int val)
1640 {
1641 	int reg;
1642 
1643 	envy_mt_write_2(sc, ENVY_MT_MONIDX, idx);
1644 	reg = 0x7f - val;
1645 	DPRINTF("%s: mon=%d/%d <- %d\n", DEVNAME(sc), reg, ch, val);
1646 	envy_mt_write_1(sc, ENVY_MT_MONDATA + ch, reg);
1647 }
1648 
1649 int
1650 envymatch(struct device *parent, void *match, void *aux)
1651 {
1652 	return pci_matchbyid((struct pci_attach_args *)aux, envy_matchids,
1653 	    sizeof(envy_matchids) / sizeof(envy_matchids[0]));
1654 }
1655 
1656 void
1657 envyattach(struct device *parent, struct device *self, void *aux)
1658 {
1659 	struct envy_softc *sc = (struct envy_softc *)self;
1660 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
1661 	pci_intr_handle_t ih;
1662 	const char *intrstr;
1663 	int subid;
1664 
1665 #if NMIDI > 0
1666 	sc->midi_isopen = 0;
1667 #endif
1668 	sc->pci_tag = pa->pa_tag;
1669 	sc->pci_pc = pa->pa_pc;
1670 	sc->pci_dmat = pa->pa_dmat;
1671 	sc->pci_ih = NULL;
1672 	sc->ibuf.addr = sc->obuf.addr = NULL;
1673 	sc->ccs_iosz = 0;
1674 	sc->mt_iosz = 0;
1675 	sc->isht = (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ICENSEMBLE_VT172x);
1676 
1677 	if (pci_mapreg_map(pa, ENVY_CTL_BAR, PCI_MAPREG_TYPE_IO, 0,
1678 		&sc->ccs_iot, &sc->ccs_ioh, NULL, &sc->ccs_iosz, 0)) {
1679 		printf(": can't map ctl i/o space\n");
1680 		sc->ccs_iosz = 0;
1681 		return;
1682 	}
1683 	if (pci_mapreg_map(pa, ENVY_MT_BAR(sc->isht), PCI_MAPREG_TYPE_IO, 0,
1684 		&sc->mt_iot, &sc->mt_ioh, NULL, &sc->mt_iosz, 0)) {
1685 		printf(": can't map mt i/o space\n");
1686 		sc->mt_iosz = 0;
1687 		return;
1688 	}
1689 	if (pci_intr_map(pa, &ih)) {
1690 		printf(": can't map interrupt\n");
1691 	}
1692 	intrstr = pci_intr_string(sc->pci_pc, ih);
1693 	sc->pci_ih = pci_intr_establish(sc->pci_pc, ih, IPL_AUDIO | IPL_MPSAFE,
1694 	    envy_intr, sc, sc->dev.dv_xname);
1695 	if (sc->pci_ih == NULL) {
1696 		printf(": can't establish interrupt");
1697 		if (intrstr)
1698 			printf(" at %s", intrstr);
1699 		printf("\n");
1700 		return;
1701 	}
1702 	printf(": %s\n", intrstr);
1703 	subid = pci_conf_read(sc->pci_pc, sc->pci_tag, PCI_SUBVEND_0);
1704 	sc->card = sc->isht ? envy_cards_ht : envy_cards;
1705 	while (sc->card->subid != subid) {
1706 		if (sc->card->subid == 0)
1707 			break;
1708 		sc->card++;
1709 	}
1710 	printf("%s: %s, %u inputs, %u outputs\n", DEVNAME(sc),
1711 	    sc->card->name, sc->card->nich, sc->card->noch);
1712 	envy_reset(sc);
1713 	sc->audio = audio_attach_mi(&envy_hw_if, sc, &sc->dev);
1714 #if NMIDI > 0
1715 	if (sc->card->nmidi > 0 && (!sc->isht ||
1716 		sc->eeprom[ENVY_EEPROM_CONF] & ENVY_CONF_MIDI)) {
1717 		sc->midi = midi_attach_mi(&envy_midi_hw_if, sc, &sc->dev);
1718 	}
1719 #endif
1720 }
1721 
1722 int
1723 envydetach(struct device *self, int flags)
1724 {
1725 	struct envy_softc *sc = (struct envy_softc *)self;
1726 
1727 	if (sc->pci_ih != NULL) {
1728 		pci_intr_disestablish(sc->pci_pc, sc->pci_ih);
1729 		sc->pci_ih = NULL;
1730 	}
1731 	if (sc->ccs_iosz) {
1732 		bus_space_unmap(sc->ccs_iot, sc->ccs_ioh, sc->ccs_iosz);
1733 	}
1734 	if (sc->mt_iosz) {
1735 		bus_space_unmap(sc->mt_iot, sc->mt_ioh, sc->mt_iosz);
1736 	}
1737 	return 0;
1738 }
1739 
1740 int
1741 envy_open(void *self, int flags)
1742 {
1743 	return 0;
1744 }
1745 
1746 void
1747 envy_close(void *self)
1748 {
1749 }
1750 
1751 void *
1752 envy_allocm(void *self, int dir, size_t size, int type, int flags)
1753 {
1754 	struct envy_softc *sc = (struct envy_softc *)self;
1755 	int err, basereg, wait;
1756 	struct envy_buf *buf;
1757 	bus_addr_t dma_addr;
1758 
1759 	if (dir == AUMODE_RECORD) {
1760 		buf = &sc->ibuf;
1761 		basereg = ENVY_MT_RADDR;
1762 	} else {
1763 		buf = &sc->obuf;
1764 		basereg = ENVY_MT_PADDR;
1765 	}
1766 	if (buf->addr != NULL) {
1767 		DPRINTF("%s: multiple alloc, dir = %d\n", DEVNAME(sc), dir);
1768 		return NULL;
1769 	}
1770 	buf->size = size;
1771 	wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
1772 
1773 #define ENVY_ALIGN	4
1774 #define ENVY_MAXADDR	((1 << 28) - 1)
1775 
1776 	buf->addr = (caddr_t)uvm_km_kmemalloc_pla(kernel_map,
1777 	    uvm.kernel_object, buf->size, 0, UVM_KMF_NOWAIT, 0,
1778 	    (paddr_t)ENVY_MAXADDR, 0, 0, 1);
1779 	if (buf->addr == NULL) {
1780 		DPRINTF("%s: unable to alloc dma segment\n", DEVNAME(sc));
1781 		goto err_ret;
1782 	}
1783 	err = bus_dmamap_create(sc->pci_dmat, buf->size, 1, buf->size, 0,
1784 	    wait, &buf->map);
1785 	if (err) {
1786 		DPRINTF("%s: dmamap_create: failed %d\n", DEVNAME(sc), err);
1787 		goto err_unmap;
1788 	}
1789 	err = bus_dmamap_load(sc->pci_dmat, buf->map, buf->addr,
1790 	    buf->size, NULL, wait);
1791 	if (err) {
1792 		DPRINTF("%s: dmamap_load: failed %d\n", DEVNAME(sc), err);
1793 		goto err_destroy;
1794 	}
1795 	dma_addr = buf->map->dm_segs[0].ds_addr;
1796 	DPRINTF("%s: allocated %zd bytes dir=%d, ka=%p, da=%lx\n", DEVNAME(sc),
1797 	    buf->size, dir, buf->addr, dma_addr);
1798 	if (!sc->isht && (dma_addr & ~ENVY_MAXADDR)) {
1799 		printf("%s: DMA address beyond 0x10000000\n", DEVNAME(sc));
1800 		goto err_unload;
1801 	}
1802 	envy_mt_write_4(sc, basereg, dma_addr);
1803 	return buf->addr;
1804  err_unload:
1805 	bus_dmamap_unload(sc->pci_dmat, buf->map);
1806  err_destroy:
1807 	bus_dmamap_destroy(sc->pci_dmat, buf->map);
1808  err_unmap:
1809 	uvm_km_free(kernel_map, (vaddr_t)buf->addr, buf->size);
1810  err_ret:
1811 	return NULL;
1812 }
1813 
1814 void
1815 envy_freem(void *self, void *addr, int type)
1816 {
1817 	struct envy_buf *buf;
1818 	struct envy_softc *sc = (struct envy_softc *)self;
1819 	int dir;
1820 
1821 	if (sc->ibuf.addr == addr) {
1822 		buf = &sc->ibuf;
1823 		dir = AUMODE_RECORD;
1824 	} else if (sc->obuf.addr == addr) {
1825 		buf = &sc->obuf;
1826 		dir = AUMODE_PLAY;
1827 	} else {
1828 		DPRINTF("%s: no buf to free\n", DEVNAME(sc));
1829 		return;
1830 	}
1831 	bus_dmamap_unload(sc->pci_dmat, buf->map);
1832 	bus_dmamap_destroy(sc->pci_dmat, buf->map);
1833 	uvm_km_free(kernel_map, (vaddr_t)&buf->addr, buf->size);
1834 	buf->addr = NULL;
1835 	DPRINTF("%s: freed buffer (mode=%d)\n", DEVNAME(sc), dir);
1836 }
1837 
1838 int
1839 envy_query_encoding(void *self, struct audio_encoding *enc)
1840 {
1841 	if (enc->index == 0) {
1842 		strlcpy(enc->name, AudioEslinear_le, sizeof(enc->name));
1843 		enc->encoding = AUDIO_ENCODING_SLINEAR_LE;
1844 		enc->precision = 24;
1845 		enc->bps = 4;
1846 		enc->msb = 1;
1847 		enc->flags = 0;
1848 		return 0;
1849 	}
1850 	return EINVAL;
1851 }
1852 
1853 int
1854 envy_set_params(void *self, int setmode, int usemode,
1855     struct audio_params *p, struct audio_params *r)
1856 {
1857 	struct envy_softc *sc = (struct envy_softc *)self;
1858 	int i, rate, reg;
1859 
1860 	if (setmode == 0)
1861 		return 0;
1862 	if (setmode == (AUMODE_PLAY | AUMODE_RECORD) &&
1863 	    p->sample_rate != r->sample_rate) {
1864 		DPRINTF("%s: play/rec rates mismatch\n", DEVNAME(sc));
1865 		r->sample_rate = p->sample_rate;
1866 	}
1867 	rate = (setmode & AUMODE_PLAY) ? p->sample_rate : r->sample_rate;
1868 	for (i = 0; envy_rates[i].rate < rate; i++) {
1869 		if (envy_rates[i].rate == -1) {
1870 			i--;
1871 			DPRINTF("%s: rate: %d -> %d\n", DEVNAME(sc), rate, i);
1872 			break;
1873 		}
1874 	}
1875 	reg = envy_mt_read_1(sc, ENVY_MT_RATE);
1876 	reg &= ~ENVY_MT_RATEMASK;
1877 	reg |= envy_rates[i].reg;
1878 	envy_mt_write_1(sc, ENVY_MT_RATE, reg);
1879 	if (setmode & AUMODE_PLAY) {
1880 		p->encoding = AUDIO_ENCODING_SLINEAR_LE;
1881 		p->precision = 24;
1882 		p->bps = 4;
1883 		p->msb = 1;
1884 		p->channels = sc->isht ? sc->card->noch : ENVY_PCHANS;
1885 	}
1886 	if (setmode & AUMODE_RECORD) {
1887 		r->encoding = AUDIO_ENCODING_SLINEAR_LE;
1888 		r->precision = 24;
1889 		r->bps = 4;
1890 		r->msb = 1;
1891 		r->channels = sc->isht ? sc->card->nich : ENVY_RCHANS;
1892 	}
1893 	return 0;
1894 }
1895 
1896 int
1897 envy_round_blocksize(void *self, int blksz)
1898 {
1899 	return (blksz + 0x1f) & ~0x1f;
1900 }
1901 
1902 size_t
1903 envy_round_buffersize(void *self, int dir, size_t bufsz)
1904 {
1905 	return bufsz;
1906 }
1907 
1908 #ifdef ENVY_DEBUG
1909 void
1910 envy_pintr(struct envy_softc *sc)
1911 {
1912 	int i;
1913 
1914 	if (sc->spurious > 0 || envydebug >= 2) {
1915 		printf("%s: spurious = %u, start = %lld.%ld\n",
1916 			DEVNAME(sc), sc->spurious,
1917 			(long long)sc->start_ts.tv_sec, sc->start_ts.tv_nsec);
1918 		for (i = 0; i < sc->nintr; i++) {
1919 			printf("%lld.%09ld: "
1920 			    "active=%d/%d pos=%d/%d st=%x/%x, ctl=%x\n",
1921 			    (long long)sc->intrs[i].ts.tv_sec,
1922 			    sc->intrs[i].ts.tv_nsec,
1923 			    sc->intrs[i].iactive,
1924 			    sc->intrs[i].oactive,
1925 			    sc->intrs[i].ipos,
1926 			    sc->intrs[i].opos,
1927 			    sc->intrs[i].st,
1928 			    sc->intrs[i].mask,
1929 			    sc->intrs[i].ctl);
1930 		}
1931 	}
1932 }
1933 #endif
1934 
1935 int
1936 envy_intr(void *self)
1937 {
1938 	struct envy_softc *sc = (struct envy_softc *)self;
1939 	unsigned int reg, hwpos, cnt;
1940 	int mintr, mstat, mdata;
1941 	int st, err, ctl;
1942 	int max;
1943 
1944 	mtx_enter(&audio_lock);
1945 	st = envy_mt_read_1(sc, ENVY_MT_INTR);
1946 	mintr = envy_ccs_read(sc, ENVY_CCS_INTSTAT);
1947 	if (!(st & ENVY_MT_INTR_ALL) && !(mintr & ENVY_CCS_INT_MIDI0)) {
1948 		mtx_leave(&audio_lock);
1949 		return 0;
1950 	}
1951 	if (st & ENVY_MT_INTR_ERR) {
1952 		err = envy_mt_read_1(sc, ENVY_MT_ERR);
1953 		envy_mt_write_1(sc, ENVY_MT_ERR, err);
1954 	}
1955 	envy_mt_write_1(sc, ENVY_MT_INTR, st);
1956 	envy_ccs_write(sc, ENVY_CCS_INTSTAT, mintr);
1957 
1958 #ifdef ENVY_DEBUG
1959 	if (sc->nintr < ENVY_NINTR) {
1960 		sc->intrs[sc->nintr].iactive = sc->iactive;
1961 		sc->intrs[sc->nintr].oactive = sc->oactive;
1962 		sc->intrs[sc->nintr].st = st;
1963 		sc->intrs[sc->nintr].ipos = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
1964 		sc->intrs[sc->nintr].opos = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
1965 		sc->intrs[sc->nintr].ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
1966 		sc->intrs[sc->nintr].mask = envy_mt_read_1(sc, ENVY_MT_IMASK);
1967 		nanouptime(&sc->intrs[sc->nintr].ts);
1968 		sc->nintr++;
1969 	}
1970 #endif
1971 	if (mintr & ENVY_CCS_INT_MIDI0) {
1972 		for (max = 128; max > 0; max--) {
1973 			mstat = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
1974 			if (mstat & ENVY_MIDISTAT_IEMPTY(sc))
1975 				break;
1976 			mdata = envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
1977 #if NMIDI > 0
1978 			if (sc->midi_in)
1979 				sc->midi_in(sc->midi_arg, mdata);
1980 #endif
1981 		}
1982 	}
1983 	if (st & ENVY_MT_INTR_PACK) {
1984 		if (sc->oactive) {
1985 			reg = envy_mt_read_2(sc, ENVY_MT_PBUFSZ);
1986 			hwpos = sc->obuf.bufsz - 4 * (reg + 1);
1987 			if (hwpos >= sc->obuf.bufsz)
1988 				hwpos -= sc->obuf.bufsz;
1989 			DPRINTFN(2, "%s: play: reg = %u, pos: %u -> %u\n",
1990 			    DEVNAME(sc), reg, sc->obuf.swpos, hwpos);
1991 			cnt = 0;
1992 			while (hwpos - sc->obuf.swpos >= sc->obuf.blksz) {
1993 				sc->ointr(sc->oarg);
1994 				sc->obuf.swpos += sc->obuf.blksz;
1995 				if (sc->obuf.swpos == sc->obuf.bufsz)
1996 					sc->obuf.swpos = 0;
1997 				cnt++;
1998 			}
1999 			if (cnt != 1) {
2000 				DPRINTFN(2, "%s: play: %u intrs\n",
2001 				    DEVNAME(sc), cnt);
2002 			}
2003 		} else {
2004 			ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
2005 			if (ctl & ENVY_MT_CTL_PSTART) {
2006 				envy_mt_write_1(sc,
2007 				    ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_PSTART);
2008 				st &= ~ENVY_MT_INTR_PACK;
2009 				sc->obusy = 0;
2010 				wakeup(&sc->obusy);
2011 			}
2012 #ifdef ENVY_DEBUG
2013 			else
2014 				sc->spurious++;
2015 #endif
2016 		}
2017 	}
2018 	if (st & ENVY_MT_INTR_RACK) {
2019 		if (sc->iactive) {
2020 			reg = envy_mt_read_2(sc, ENVY_MT_RBUFSZ);
2021 			hwpos = sc->ibuf.bufsz - 4 * (reg + 1);
2022 			if (hwpos >= sc->ibuf.bufsz)
2023 				hwpos -= sc->ibuf.bufsz;
2024 			DPRINTFN(2, "%s: rec: reg = %u, pos: %u -> %u\n",
2025 			    DEVNAME(sc), reg, sc->ibuf.swpos, hwpos);
2026 			cnt = 0;
2027 			while (hwpos - sc->ibuf.swpos >= sc->ibuf.blksz) {
2028 				sc->iintr(sc->iarg);
2029 				sc->ibuf.swpos += sc->ibuf.blksz;
2030 				if (sc->ibuf.swpos == sc->ibuf.bufsz)
2031 					sc->ibuf.swpos = 0;
2032 				cnt++;
2033 			}
2034 			if (cnt != 1) {
2035 				DPRINTFN(2, "%s: rec: %u intrs\n",
2036 				    DEVNAME(sc), cnt);
2037 			}
2038 		} else {
2039 			ctl = envy_mt_read_1(sc, ENVY_MT_CTL);
2040 			if (ctl & ENVY_MT_CTL_RSTART(sc)) {
2041 				envy_mt_write_1(sc,
2042 				    ENVY_MT_CTL, ctl & ~ENVY_MT_CTL_RSTART(sc));
2043 				st &= ~ENVY_MT_INTR_RACK;
2044 				sc->ibusy = 0;
2045 				wakeup(&sc->ibusy);
2046 			}
2047 #ifdef ENVY_DEBUG
2048 			else
2049 				sc->spurious++;
2050 #endif
2051 		}
2052 	}
2053 	mtx_leave(&audio_lock);
2054 	return 1;
2055 }
2056 
2057 int
2058 envy_trigger_output(void *self, void *start, void *end, int blksz,
2059     void (*intr)(void *), void *arg, struct audio_params *param)
2060 {
2061 	struct envy_softc *sc = (struct envy_softc *)self;
2062 	size_t bufsz;
2063 	int st;
2064 
2065 	bufsz = (char *)end - (char *)start;
2066 #ifdef ENVY_DEBUG
2067 	if (blksz % (sc->isht ? sc->card->noch * 4 : ENVY_PFRAME_SIZE) != 0) {
2068 		printf("%s: %d: bad output blksz\n", DEVNAME(sc), blksz);
2069 		return EINVAL;
2070 	}
2071 	if (bufsz % blksz) {
2072 		printf("%s: %ld: bad output bufsz\n", DEVNAME(sc), bufsz);
2073 		return EINVAL;
2074 	}
2075 #endif
2076 	mtx_enter(&audio_lock);
2077 	envy_mt_write_2(sc, ENVY_MT_PBUFSZ, bufsz / 4 - 1);
2078 	envy_mt_write_2(sc, ENVY_MT_PBLKSZ(sc), blksz / 4 - 1);
2079 
2080 #ifdef ENVY_DEBUG
2081 	if (!sc->iactive) {
2082 		sc->nintr = 0;
2083 		sc->spurious = 0;
2084 		nanouptime(&sc->start_ts);
2085 	}
2086 #endif
2087 	sc->obuf.bufsz = bufsz;
2088 	sc->obuf.blksz = blksz;
2089 	sc->obuf.swpos = 0;
2090 	sc->ointr = intr;
2091 	sc->oarg = arg;
2092 	sc->oactive = 1;
2093 	sc->obusy = 1;
2094 	st = ENVY_MT_INTR_PACK;
2095 	envy_mt_write_1(sc, ENVY_MT_INTR, st);
2096 	st = envy_mt_read_1(sc, ENVY_MT_CTL);
2097 	st |= ENVY_MT_CTL_PSTART;
2098 	envy_mt_write_1(sc, ENVY_MT_CTL, st);
2099 	mtx_leave(&audio_lock);
2100 	return 0;
2101 }
2102 
2103 int
2104 envy_trigger_input(void *self, void *start, void *end, int blksz,
2105     void (*intr)(void *), void *arg, struct audio_params *param)
2106 {
2107 	struct envy_softc *sc = (struct envy_softc *)self;
2108 	size_t bufsz;
2109 	int st;
2110 
2111 	bufsz = (char *)end - (char *)start;
2112 #ifdef ENVY_DEBUG
2113 	if (blksz % (sc->isht ? sc->card->nich * 4 : ENVY_RFRAME_SIZE) != 0) {
2114 		printf("%s: %d: bad input blksz\n", DEVNAME(sc), blksz);
2115 		return EINVAL;
2116 	}
2117 	if (bufsz % blksz != 0) {
2118 		printf("%s: %ld: bad input bufsz\n", DEVNAME(sc), bufsz);
2119 		return EINVAL;
2120 	}
2121 #endif
2122 	mtx_enter(&audio_lock);
2123 	envy_mt_write_2(sc, ENVY_MT_RBUFSZ, bufsz / 4 - 1);
2124 	envy_mt_write_2(sc, ENVY_MT_RBLKSZ, blksz / 4 - 1);
2125 
2126 #ifdef ENVY_DEBUG
2127 	if (!sc->oactive) {
2128 		sc->nintr = 0;
2129 		sc->spurious = 0;
2130 		nanouptime(&sc->start_ts);
2131 	}
2132 #endif
2133 	sc->ibuf.bufsz = bufsz;
2134 	sc->ibuf.blksz = blksz;
2135 	sc->ibuf.swpos = 0;
2136 	sc->iintr = intr;
2137 	sc->iarg = arg;
2138 	sc->iactive = 1;
2139 	sc->ibusy = 1;
2140 	st = ENVY_MT_INTR_RACK;
2141 	envy_mt_write_1(sc, ENVY_MT_INTR, st);
2142 	st = envy_mt_read_1(sc, ENVY_MT_CTL);
2143 	st |= ENVY_MT_CTL_RSTART(sc);
2144 	envy_mt_write_1(sc, ENVY_MT_CTL, st);
2145 	mtx_leave(&audio_lock);
2146 	return 0;
2147 }
2148 
2149 int
2150 envy_halt_output(void *self)
2151 {
2152 	struct envy_softc *sc = (struct envy_softc *)self;
2153 	int err;
2154 
2155 	mtx_enter(&audio_lock);
2156 	sc->oactive = 0;
2157 	if (sc->obusy) {
2158 		err = msleep(&sc->obusy, &audio_lock, PWAIT, "envyobus", 4 * hz);
2159 		if (err)
2160 			printf("%s: output DMA halt timeout\n", DEVNAME(sc));
2161 	}
2162 #ifdef ENVY_DEBUG
2163 	if (!sc->iactive)
2164 		envy_pintr(sc);
2165 #endif
2166 	mtx_leave(&audio_lock);
2167 	return 0;
2168 }
2169 
2170 int
2171 envy_halt_input(void *self)
2172 {
2173 	struct envy_softc *sc = (struct envy_softc *)self;
2174 	int err;
2175 
2176 	mtx_enter(&audio_lock);
2177 	sc->iactive = 0;
2178 	if (sc->ibusy) {
2179 		err = msleep(&sc->ibusy, &audio_lock, PWAIT, "envyibus", 4 * hz);
2180 		if (err)
2181 			printf("%s: input DMA halt timeout\n", DEVNAME(sc));
2182 	}
2183 #ifdef ENVY_DEBUG
2184 	if (!sc->oactive)
2185 		envy_pintr(sc);
2186 #endif
2187 	mtx_leave(&audio_lock);
2188 	return 0;
2189 }
2190 
2191 int
2192 envy_getdev(void *self, struct audio_device *dev)
2193 {
2194 	struct envy_softc *sc = (struct envy_softc *)self;
2195 
2196 	strlcpy(dev->name, sc->isht ? "Envy24HT" : "Envy24", MAX_AUDIO_DEV_LEN);
2197 	strlcpy(dev->version, "-", MAX_AUDIO_DEV_LEN);
2198 	strlcpy(dev->config, sc->card->name, MAX_AUDIO_DEV_LEN);
2199 	return 0;
2200 }
2201 
2202 int
2203 envy_query_devinfo(void *self, struct mixer_devinfo *dev)
2204 {
2205 	struct envy_softc *sc = (struct envy_softc *)self;
2206 	int i, n, idx, ndev;
2207 	char *classes[] = {
2208 		AudioCinputs, AudioCoutputs, AudioCmonitor
2209 	};
2210 
2211 	if (sc->isac97)
2212 		return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dev));
2213 
2214 	if (dev->index < 0)
2215 		return ENXIO;
2216 
2217 	idx = dev->index;
2218 	ndev = ENVY_MIX_NCLASS;
2219 	dev->prev = dev->next = AUDIO_MIXER_LAST;
2220 
2221 	/*
2222 	 * classes
2223 	 */
2224 	if (idx < ndev) {
2225 		dev->type = AUDIO_MIXER_CLASS;
2226 		dev->mixer_class = idx;
2227 		strlcpy(dev->label.name, classes[idx], MAX_AUDIO_DEV_LEN);
2228 		return 0;
2229 	}
2230 	idx -= ndev;
2231 
2232 	/*
2233 	 * output.lineX_source
2234 	 */
2235 	ndev = sc->card->noch;
2236 	if (idx < ndev) {
2237 		n = 0;
2238 		dev->type = AUDIO_MIXER_ENUM;
2239 		dev->mixer_class = ENVY_MIX_CLASSOUT;
2240 		for (i = 0; i < sc->card->nich; i++) {
2241 			dev->un.e.member[n].ord = n;
2242 			snprintf(dev->un.e.member[n++].label.name,
2243 			    MAX_AUDIO_DEV_LEN, AudioNline "-%d", i);
2244 		}
2245 		dev->un.e.member[n].ord = n;
2246 		snprintf(dev->un.e.member[n++].label.name,
2247 			 MAX_AUDIO_DEV_LEN, "play-%d", idx);
2248 		if (!sc->isht && idx < 2) {
2249 			dev->un.e.member[n].ord = n;
2250 			snprintf(dev->un.e.member[n++].label.name,
2251 			    MAX_AUDIO_DEV_LEN, "mon-%d", idx);
2252 		}
2253 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
2254 		    AudioNline "-%d_" AudioNsource, idx);
2255 		dev->un.s.num_mem = n;
2256 		return 0;
2257 	}
2258 	idx -= ndev;
2259 
2260 	/*
2261 	 * envy monitor level
2262 	 */
2263 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2264 	if (idx < ndev) {
2265 		dev->type = AUDIO_MIXER_VALUE;
2266 		dev->mixer_class = ENVY_MIX_CLASSMON;
2267 		dev->un.v.delta = 2;
2268 		dev->un.v.num_channels = 1;
2269 		snprintf(dev->label.name, MAX_AUDIO_DEV_LEN,
2270 			 "%s-%d", idx < 10 ? "play" : "rec", idx % 10);
2271 		strlcpy(dev->un.v.units.name, AudioNvolume, MAX_AUDIO_DEV_LEN);
2272 		return 0;
2273 	}
2274 	idx -= ndev;
2275 
2276 	/*
2277 	 * inputs.xxx
2278 	 */
2279 	ndev = sc->card->adc->ndev(sc);
2280 	if (idx < ndev) {
2281 		sc->card->adc->devinfo(sc, dev, idx);
2282 		return 0;
2283 	}
2284 	idx -= ndev;
2285 
2286 	/*
2287 	 * outputs.xxx
2288 	 */
2289 	ndev = sc->card->dac->ndev(sc);
2290 	if (idx < ndev) {
2291 		sc->card->dac->devinfo(sc, dev, idx);
2292 		return 0;
2293 	}
2294 	return ENXIO;
2295 }
2296 
2297 int
2298 envy_get_port(void *self, struct mixer_ctrl *ctl)
2299 {
2300 	struct envy_softc *sc = (struct envy_softc *)self;
2301 	int val, idx, ndev;
2302 
2303 	if (sc->isac97)
2304 		return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, ctl));
2305 
2306 	if (ctl->dev < ENVY_MIX_NCLASS) {
2307 		return EINVAL;
2308 	}
2309 
2310 	idx = ctl->dev - ENVY_MIX_NCLASS;
2311 	ndev = sc->card->noch;
2312 	if (idx < ndev) {
2313 		ctl->un.ord = envy_lineout_getsrc(sc, idx);
2314 		if (ctl->un.ord >= ENVY_MIX_NOUTSRC)
2315 			ctl->un.ord -= ENVY_MIX_NOUTSRC - sc->card->nich;
2316 		return 0;
2317 	}
2318 	idx -= ndev;
2319 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2320 	if (idx < ndev) {
2321 		envy_mon_getvol(sc, idx / 2, idx % 2, &val);
2322 		ctl->un.value.num_channels = 1;
2323 		ctl->un.value.level[0] = 2 * val;
2324 		return 0;
2325 	}
2326 	idx -= ndev;
2327 	ndev = sc->card->adc->ndev(sc);
2328 	if (idx < ndev) {
2329 		sc->card->adc->get(sc, ctl, idx);
2330 		return 0;
2331 	}
2332 	idx -= ndev;
2333 	ndev = sc->card->dac->ndev(sc);
2334 	if (idx < ndev) {
2335 		sc->card->dac->get(sc, ctl, idx);
2336 		return 0;
2337 	}
2338 	return ENXIO;
2339 }
2340 
2341 int
2342 envy_set_port(void *self, struct mixer_ctrl *ctl)
2343 {
2344 	struct envy_softc *sc = (struct envy_softc *)self;
2345 	int maxsrc, val, idx, ndev;
2346 
2347 	if (sc->isac97)
2348 		return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, ctl));
2349 
2350 	if (ctl->dev < ENVY_MIX_NCLASS) {
2351 		return EINVAL;
2352 	}
2353 
2354 	idx = ctl->dev - ENVY_MIX_NCLASS;
2355 	ndev = sc->card->noch;
2356 	if (idx < ndev) {
2357 		maxsrc = sc->card->nich + 1;
2358 		if (idx < 2)
2359 			maxsrc++;
2360 		if (ctl->un.ord < 0 || ctl->un.ord >= maxsrc)
2361 			return EINVAL;
2362 		if (ctl->un.ord >= sc->card->nich)
2363 			ctl->un.ord += ENVY_MIX_NOUTSRC - sc->card->nich;
2364 		envy_lineout_setsrc(sc, idx, ctl->un.ord);
2365 		return 0;
2366 	}
2367 	idx -= ndev;
2368 	ndev = sc->isht ? 0 : ENVY_MIX_NMONITOR;
2369 	if (idx < ndev) {
2370 		if (ctl->un.value.num_channels != 1) {
2371 			return EINVAL;
2372 		}
2373 		val = ctl->un.value.level[0] / 2;
2374 		envy_mon_setvol(sc, idx / 2, idx % 2, val);
2375 		return 0;
2376 	}
2377 	idx -= ndev;
2378 	ndev = sc->card->adc->ndev(sc);
2379 	if (idx < ndev)
2380 		return sc->card->adc->set(sc, ctl, idx);
2381 	idx -= ndev;
2382 	ndev = sc->card->dac->ndev(sc);
2383 	if (idx < ndev)
2384 		return sc->card->dac->set(sc, ctl, idx);
2385 	return ENXIO;
2386 }
2387 
2388 int
2389 envy_get_props(void *self)
2390 {
2391 	return AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT;
2392 }
2393 
2394 #if NMIDI > 0
2395 int
2396 envy_midi_open(void *self, int flags,
2397     void (*in)(void *, int),
2398     void (*out)(void *),
2399     void *arg)
2400 {
2401 	struct envy_softc *sc = (struct envy_softc *)self;
2402 	unsigned int i, reg;
2403 
2404 	/* discard pending data */
2405 	for (i = 0; i < 128; i++) {
2406 		reg = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
2407 		if (reg & ENVY_MIDISTAT_IEMPTY(sc))
2408 			break;
2409 		(void)envy_ccs_read(sc, ENVY_CCS_MIDIDATA0);
2410 	}
2411 #ifdef ENVY_DEBUG
2412 	if (i > 0)
2413 		DPRINTF("%s: midi: discarded %u bytes\n", DEVNAME(sc), i);
2414 #endif
2415 
2416 	/* clear pending midi interrupt */
2417 	envy_ccs_write(sc, ENVY_CCS_INTSTAT, ENVY_CCS_INT_MIDI0);
2418 
2419 	/* interrupts are disabled, it safe to manipulate these */
2420 	sc->midi_in = in;
2421 	sc->midi_out = out;
2422 	sc->midi_arg = arg;
2423 	sc->midi_isopen = 1;
2424 
2425 	/* enable interrupts */
2426 	reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
2427 	reg &= ~ENVY_CCS_INT_MIDI0;
2428 	envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
2429 	return 0;
2430 }
2431 
2432 void
2433 envy_midi_close(void *self)
2434 {
2435 	struct envy_softc *sc = (struct envy_softc *)self;
2436 	unsigned int reg;
2437 
2438 	/* wait for output fifo to drain */
2439 	tsleep(sc, PWAIT, "envymid", hz / 10);
2440 
2441 	/* disable interrupts */
2442 	reg = envy_ccs_read(sc, ENVY_CCS_INTMASK);
2443 	reg |= ENVY_CCS_INT_MIDI0;
2444 	envy_ccs_write(sc, ENVY_CCS_INTMASK, reg);
2445 
2446 	/* interrupts are disabled, it safe to manipulate these */
2447 	sc->midi_in = NULL;
2448 	sc->midi_out = NULL;
2449 	sc->midi_isopen = 0;
2450 }
2451 
2452 int
2453 envy_midi_output(void *self, int data)
2454 {
2455 	struct envy_softc *sc = (struct envy_softc *)self;
2456 	int st;
2457 
2458 	st = envy_ccs_read(sc, ENVY_CCS_MIDISTAT0);
2459 	if (st & ENVY_MIDISTAT_OBUSY(sc))
2460 		return 0;
2461 	envy_ccs_write(sc, ENVY_CCS_MIDIDATA0, data);
2462 	return 1;
2463 }
2464 
2465 void
2466 envy_midi_getinfo(void *self, struct midi_info *mi)
2467 {
2468 	mi->props = MIDI_PROP_CAN_INPUT;
2469 	mi->name = "Envy24 MIDI UART";
2470 }
2471 #endif
2472