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