xref: /openbsd/sys/dev/pci/azalia_codec.c (revision 898184e3)
1 /*	$OpenBSD: azalia_codec.c,v 1.152 2012/11/30 12:05:45 sthen Exp $	*/
2 /*	$NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $	*/
3 
4 /*-
5  * Copyright (c) 2005 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by TAMURA Kent
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
37 #include <uvm/uvm_param.h>
38 #include <dev/pci/azalia.h>
39 
40 #define XNAME(co)	(((struct device *)co->az)->dv_xname)
41 #define MIXER_DELTA(n)	(AUDIO_MAX_GAIN / (n))
42 
43 int	azalia_add_convgroup(codec_t *, convgroupset_t *,
44     struct io_pin *, int, nid_t *, int, uint32_t, uint32_t);
45 
46 int	azalia_mixer_fix_indexes(codec_t *);
47 int	azalia_mixer_default(codec_t *);
48 int	azalia_mixer_ensure_capacity(codec_t *, size_t);
49 u_char	azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t );
50 uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char);
51 
52 void	azalia_devinfo_offon(mixer_devinfo_t *);
53 void	azalia_pin_config_ov(widget_t *, int, int);
54 void	azalia_ampcap_ov(widget_t *, int, int, int, int, int, int);
55 int	azalia_gpio_unmute(codec_t *, int);
56 
57 
58 int
59 azalia_codec_init_vtbl(codec_t *this)
60 {
61 	/**
62 	 * We can refer this->vid and this->subid.
63 	 */
64 	this->name = NULL;
65 	this->qrks = AZ_QRK_NONE;
66 	switch (this->vid) {
67 	case 0x10134206:
68 		this->name = "Cirrus Logic CS4206";
69 		if (this->subid == 0xcb8910de) {	/* APPLE_MBA3_1 */
70 			this->qrks |= AZ_QRK_GPIO_UNMUTE_1 |
71 			    AZ_QRK_GPIO_UNMUTE_3;
72 		}
73 		break;
74 	case 0x10ec0260:
75 		this->name = "Realtek ALC260";
76 		break;
77 	case 0x10ec0262:
78 		this->name = "Realtek ALC262";
79 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
80 		break;
81 	case 0x10ec0268:
82 		this->name = "Realtek ALC268";
83 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
84 		break;
85 	case 0x10ec0269:
86 		this->name = "Realtek ALC269";
87 		break;
88 	case 0x10ec0272:
89 		this->name = "Realtek ALC272";
90 		break;
91 	case 0x10ec0660:
92 		this->name = "Realtek ALC660";
93 		if (this->subid == 0x13391043) {	/* ASUS_G2K */
94 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
95 		}
96 		break;
97 	case 0x10ec0662:
98 		this->name = "Realtek ALC662";
99 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
100 		break;
101 	case 0x10ec0663:
102 		this->name = "Realtek ALC663";
103 		break;
104 	case 0x10ec0861:
105 		this->name = "Realtek ALC861";
106 		break;
107 	case 0x10ec0880:
108 		this->name = "Realtek ALC880";
109 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
110 		if (this->subid == 0x19931043 ||	/* ASUS_M5200 */
111 		    this->subid == 0x13231043) {	/* ASUS_A7M */
112 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
113 		}
114 		if (this->subid == 0x203d161f) {	/* MEDION_MD95257 */
115 			this->qrks |= AZ_QRK_GPIO_UNMUTE_1;
116 		}
117 		break;
118 	case 0x10ec0882:
119 		this->name = "Realtek ALC882";
120 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
121 		if (this->subid == 0x13c21043 ||	/* ASUS_A7T */
122 		    this->subid == 0x19711043) {	/* ASUS_W2J */
123 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
124 		}
125 		break;
126 	case 0x10ec0883:
127 		this->name = "Realtek ALC883";
128 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
129 		if (this->subid == 0x00981025) {	/* ACER_ID */
130 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0 |
131 			    AZ_QRK_GPIO_UNMUTE_1;
132 		}
133 		break;
134 	case 0x10ec0885:
135 		this->name = "Realtek ALC885";
136 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
137 		if (this->subid == 0x00a1106b ||	/* APPLE_MB3 */
138 		    this->subid == 0x00a0106b ||	/* APPLE_MB3_1 */
139 		    this->subid == 0x00a3106b) {	/* APPLE_MB4 */
140 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
141 		}
142 		if (this->subid == 0x00a1106b ||
143 		    this->subid == 0x00a0106b)
144 			this->qrks |= AZ_QRK_WID_OVREF50;
145 		break;
146 	case 0x10ec0888:
147 		this->name = "Realtek ALC888";
148 		this->qrks |= AZ_QRK_WID_CDIN_1C | AZ_QRK_WID_BEEP_1D;
149 		break;
150 	case 0x11060398:
151 	case 0x11061398:
152 	case 0x11062398:
153 	case 0x11063398:
154 	case 0x11064398:
155 	case 0x11065398:
156 	case 0x11066398:
157 	case 0x11067398:
158 		this->name = "VIA VT1702";
159 		break;
160 	case 0x111d7603:
161 		this->name = "IDT 92HD75B3/4";
162 		break;
163 	case 0x111d7604:
164 		this->name = "IDT 92HD83C1X";
165 		break;
166 	case 0x111d7605:
167 		this->name = "IDT 92HD81B1X";
168 		break;
169 	case 0x111d7608:
170 		this->name = "IDT 92HD75B1/2";
171 		break;
172 	case 0x111d7674:
173 		this->name = "IDT 92HD73D1";
174 		break;
175 	case 0x111d7675:
176 		this->name = "IDT 92HD73C1";	/* aka 92HDW74C1 */
177 		if ((this->subid & 0x0000ffff) == 0x00001028) {	/* DELL */
178 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
179 		}
180 		break;
181 	case 0x111d7676:
182 		this->name = "IDT 92HD73E1";	/* aka 92HDW74E1 */
183 		break;
184 	case 0x111d76b0:
185 		this->name = "IDT 92HD71B8";
186 		break;
187 	case 0x111d76b2:
188 		this->name = "IDT 92HD71B7";
189 		if ((this->subid & 0x0000ffff) == 0x00001028 || /* DELL */
190 		    (this->subid & 0x0000ffff) == 0x0000103c) { /* HP */
191 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
192 		}
193 		break;
194 	case 0x111d76b6:
195 		this->name = "IDT 92HD71B5";
196 		break;
197 	case 0x111d76d4:
198 		this->name = "IDT 92HD83C1C";
199 		break;
200 	case 0x111d76d5:
201 		this->name = "IDT 92HD81B1C";
202 		break;
203 	case 0x11d4184a:
204 		this->name = "Analog Devices AD1884A";
205 		break;
206 	case 0x11d41882:
207 		this->name = "Analog Devices AD1882";
208 		break;
209 	case 0x11d41883:
210 		this->name = "Analog Devices AD1883";
211 		break;
212 	case 0x11d41884:
213 		this->name = "Analog Devices AD1884";
214 		break;
215 	case 0x11d4194a:
216 		this->name = "Analog Devices AD1984A";
217 		break;
218 	case 0x11d41981:
219 		this->name = "Analog Devices AD1981HD";
220 		this->qrks |= AZ_QRK_WID_AD1981_OAMP;
221 		break;
222 	case 0x11d41983:
223 		this->name = "Analog Devices AD1983";
224 		break;
225 	case 0x11d41984:
226 		this->name = "Analog Devices AD1984";
227 		break;
228 	case 0x11d41988:
229 		this->name = "Analog Devices AD1988A";
230 		break;
231 	case 0x11d4198b:
232 		this->name = "Analog Devices AD1988B";
233 		break;
234 	case 0x11d4882a:
235 		this->name = "Analog Devices AD1882A";
236 		break;
237 	case 0x11d4989a:
238 		this->name = "Analog Devices AD1989A";
239 		break;
240 	case 0x11d4989b:
241 		this->name = "Analog Devices AD1989B";
242 		break;
243 	case 0x14f15045:
244 		this->name = "Conexant CX20549";  /* Venice */
245 		break;
246 	case 0x14f15047:
247 		this->name = "Conexant CX20551";  /* Waikiki */
248 		break;
249 	case 0x14f15051:
250 		this->name = "Conexant CX20561";  /* Hermosa */
251 		break;
252 	case 0x434d4980:
253 		this->name = "CMedia CMI9880";
254 		break;
255 	case 0x83847612:
256 		this->name = "Sigmatel STAC9230X";
257 		break;
258 	case 0x83847613:
259 		this->name = "Sigmatel STAC9230D";
260 		break;
261 	case 0x83847614:
262 		this->name = "Sigmatel STAC9229X";
263 		break;
264 	case 0x83847615:
265 		this->name = "Sigmatel STAC9229D";
266 		break;
267 	case 0x83847616:
268 		this->name = "Sigmatel STAC9228X";
269 		if (this->subid == 0x02271028 ||	/* DELL_V1400 */
270 		    this->subid == 0x01f31028) {	/* DELL_I1400 */
271 			this->qrks |= AZ_QRK_GPIO_UNMUTE_2;
272 	 	}
273 		break;
274 	case 0x83847617:
275 		this->name = "Sigmatel STAC9228D";
276 		break;
277 	case 0x83847618:
278 		this->name = "Sigmatel STAC9227X";
279 		break;
280 	case 0x83847619:
281 		this->name = "Sigmatel STAC9227D";
282 		break;
283 	case 0x83847620:
284 		this->name = "Sigmatel STAC9274";
285 		break;
286 	case 0x83847621:
287 		this->name = "Sigmatel STAC9274D";
288 		break;
289 	case 0x83847626:
290 		this->name = "Sigmatel STAC9271X";
291 		break;
292 	case 0x83847627:
293 		this->name = "Sigmatel STAC9271D";
294 		break;
295 	case 0x83847632:
296 		this->name = "Sigmatel STAC9202";
297 		break;
298 	case 0x83847634:
299 		this->name = "Sigmatel STAC9250";
300 		break;
301 	case 0x83847636:
302 		this->name = "Sigmatel STAC9251";
303 		break;
304 	case 0x83847638:
305 		this->name = "IDT 92HD700X";
306 		break;
307 	case 0x83847639:
308 		this->name = "IDT 92HD700D";
309 		break;
310 	case 0x83847645:
311 		this->name = "IDT 92HD206X";
312 		break;
313 	case 0x83847646:
314 		this->name = "IDT 92HD206D";
315 		break;
316 	case 0x83847661:
317 		/* FALLTHROUGH */
318 	case 0x83847662:
319 		this->name = "Sigmatel STAC9225";
320 		break;
321 	case 0x83847680:
322 		this->name = "Sigmatel STAC9220/1";
323 		if (this->subid == 0x76808384) {	/* APPLE_ID */
324 			this->qrks |= AZ_QRK_GPIO_POL_0 | AZ_QRK_GPIO_UNMUTE_0 |
325 			     AZ_QRK_GPIO_UNMUTE_1;
326 		}
327 		break;
328 	case 0x83847682:
329 		/* FALLTHROUGH */
330 	case 0x83847683:
331 		this->name = "Sigmatel STAC9221D";	/* aka IDT 92HD202 */
332 		break;
333 	case 0x83847690:
334 		this->name = "Sigmatel STAC9200";	/* aka IDT 92HD001 */
335 		break;
336 	case 0x83847691:
337 		this->name = "Sigmatel STAC9200D";
338 		break;
339 	case 0x83847698:
340 		this->name = "IDT 92HD005";
341 		break;
342 	case 0x83847699:
343 		this->name = "IDT 92HD005D";
344 		break;
345 	case 0x838476a0:
346 		this->name = "Sigmatel STAC9205X";
347 		if (this->subid == 0x01f91028 ||	/* DELL_D630 */
348 		    this->subid == 0x02281028) {	/* DELL_V1500 */
349 			this->qrks |= AZ_QRK_GPIO_UNMUTE_0;
350 		}
351 		break;
352 	case 0x838476a1:
353 		this->name = "Sigmatel STAC9205D";
354 		break;
355 	case 0x838476a2:
356 		this->name = "Sigmatel STAC9204X";
357 		break;
358 	case 0x838476a3:
359 		this->name = "Sigmatel STAC9204D";
360 		break;
361 	}
362 	return 0;
363 }
364 
365 /* ----------------------------------------------------------------
366  * functions for generic codecs
367  * ---------------------------------------------------------------- */
368 
369 int
370 azalia_widget_enabled(const codec_t *this, nid_t nid)
371 {
372 	if (!VALID_WIDGET_NID(nid, this) || !this->w[nid].enable)
373 		return 0;
374 	return 1;
375 }
376 
377 int
378 azalia_init_dacgroup(codec_t *this)
379 {
380 	this->dacs.ngroups = 0;
381 	if (this->na_dacs > 0)
382 		azalia_add_convgroup(this, &this->dacs,
383 		    this->opins, this->nopins,
384 		    this->a_dacs, this->na_dacs,
385 		    COP_AWTYPE_AUDIO_OUTPUT, 0);
386 	if (this->na_dacs_d > 0)
387 		azalia_add_convgroup(this, &this->dacs,
388 		    this->opins_d, this->nopins_d,
389 		    this->a_dacs_d, this->na_dacs_d,
390 		    COP_AWTYPE_AUDIO_OUTPUT, COP_AWCAP_DIGITAL);
391 	this->dacs.cur = 0;
392 
393 	this->adcs.ngroups = 0;
394 	if (this->na_adcs > 0)
395 		azalia_add_convgroup(this, &this->adcs,
396 		    this->ipins, this->nipins,
397 		    this->a_adcs, this->na_adcs,
398 		    COP_AWTYPE_AUDIO_INPUT, 0);
399 	if (this->na_adcs_d > 0)
400 		azalia_add_convgroup(this, &this->adcs,
401 		    this->ipins_d, this->nipins_d,
402 		    this->a_adcs_d, this->na_adcs_d,
403 		    COP_AWTYPE_AUDIO_INPUT, COP_AWCAP_DIGITAL);
404 	this->adcs.cur = 0;
405 
406 	return 0;
407 }
408 
409 int
410 azalia_add_convgroup(codec_t *this, convgroupset_t *group,
411     struct io_pin *pins, int npins, nid_t *all_convs, int nall_convs,
412     uint32_t type, uint32_t digital)
413 {
414 	nid_t convs[HDA_MAX_CHANNELS];
415 	int nconvs;
416 	nid_t conv;
417 	int i, j, k;
418 
419 	nconvs = 0;
420 
421 	/* default pin connections */
422 	for (i = 0; i < npins; i++) {
423 		conv = pins[i].conv;
424 		if (conv < 0)
425 			continue;
426 		for (j = 0; j < nconvs; j++) {
427 			if (convs[j] == conv)
428 				break;
429 		}
430 		if (j < nconvs)
431 			continue;
432 		convs[nconvs++] = conv;
433 		if (nconvs >= nall_convs) {
434 			goto done;
435 		}
436 	}
437 	/* non-default connections */
438 	for (i = 0; i < npins; i++) {
439 		for (j = 0; j < nall_convs; j++) {
440 			conv = all_convs[j];
441 			for (k = 0; k < nconvs; k++) {
442 				if (convs[k] == conv)
443 					break;
444 			}
445 			if (k < nconvs)
446 				continue;
447 			if (type == COP_AWTYPE_AUDIO_OUTPUT) {
448 				k = azalia_codec_fnode(this, conv,
449 				    pins[i].nid, 0);
450 				if (k < 0)
451 					continue;
452 			} else {
453 				if (!azalia_widget_enabled(this, conv))
454 					continue;
455 				k = azalia_codec_fnode(this, pins[i].nid,
456 				    conv, 0);
457 				if (k < 0)
458 					continue;
459 			}
460 			convs[nconvs++] = conv;
461 			if (nconvs >= nall_convs) {
462 				goto done;
463 			}
464 		}
465 	}
466 	/* Make sure the speaker dac is part of the analog output convgroup
467 	 * or it won't get connected by azalia_codec_connect_stream().
468 	 */
469 	if (type == COP_AWTYPE_AUDIO_OUTPUT && !digital &&
470 	    nconvs < nall_convs && this->spkr_dac != -1) {
471 		for (i = 0; i < nconvs; i++)
472 			if (convs[i] == this->spkr_dac)
473 				break;
474 		if (i == nconvs)
475 			convs[nconvs++] = this->spkr_dac;
476 	}
477 done:
478 	for (i = 0; i < nconvs; i++)
479 		group->groups[group->ngroups].conv[i] = convs[i];
480 	if (nconvs > 0) {
481 		group->groups[group->ngroups].nconv = i;
482 		group->ngroups++;
483 	}
484 
485 	/* Disable converters that aren't in a convgroup. */
486 	for (i = 0; i < nall_convs; i++) {
487 		conv = all_convs[i];
488 		for (j = 0; j < nconvs; j++)
489 			if (convs[j] == conv)
490 				break;
491 		if (j == nconvs)
492 			this->w[conv].enable = 0;
493 	}
494 
495 	return 0;
496 }
497 
498 int
499 azalia_codec_fnode(codec_t *this, nid_t node, int index, int depth)
500 {
501 	const widget_t *w;
502 	int i, ret;
503 
504 	w = &this->w[index];
505 	if (w->nid == node) {
506 		return index;
507 	}
508 	/* back at the beginning or a bad end */
509 	if (depth > 0 &&
510 	    (w->type == COP_AWTYPE_PIN_COMPLEX ||
511 	    w->type == COP_AWTYPE_BEEP_GENERATOR ||
512 	    w->type == COP_AWTYPE_AUDIO_OUTPUT ||
513 	    w->type == COP_AWTYPE_AUDIO_INPUT))
514 		return -1;
515 	if (++depth >= 10)
516 		return -1;
517 	for (i = 0; i < w->nconnections; i++) {
518 		if (!azalia_widget_enabled(this, w->connections[i]))
519 			continue;
520 		ret = azalia_codec_fnode(this, node, w->connections[i], depth);
521 		if (ret >= 0)
522 			return ret;
523 	}
524 	return -1;
525 }
526 
527 int
528 azalia_unsol_event(codec_t *this, int tag)
529 {
530 	mixer_ctrl_t mc;
531 	uint32_t result;
532 	int i, err, vol, vol2;
533 
534 	err = 0;
535 	tag = CORB_UNSOL_TAG(tag);
536 	switch (tag) {
537 	case AZ_TAG_SPKR:
538 		mc.type = AUDIO_MIXER_ENUM;
539 		vol = 0;
540 		for (i = 0; !vol && !err && i < this->nsense_pins; i++) {
541 			if (!(this->spkr_muters & (1 << i)))
542 				continue;
543 			err = azalia_comresp(this, this->sense_pins[i],
544 			    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
545 			if (err || !(result & CORB_PWC_OUTPUT))
546 				continue;
547 			err = azalia_comresp(this, this->sense_pins[i],
548 			    CORB_GET_PIN_SENSE, 0, &result);
549 			if (!err && (result & CORB_PS_PRESENCE))
550 				vol = 1;
551 		}
552 		if (err)
553 			break;
554 		this->spkr_muted = vol;
555 		switch(this->spkr_mute_method) {
556 		case AZ_SPKR_MUTE_SPKR_MUTE:
557 			mc.un.ord = vol;
558 			err = azalia_mixer_set(this, this->speaker,
559 			    MI_TARGET_OUTAMP, &mc);
560 			if (!err && this->speaker2 != -1 &&
561 			    (this->w[this->speaker2].widgetcap & COP_AWCAP_OUTAMP) &&
562 			    (this->w[this->speaker2].outamp_cap & COP_AMPCAP_MUTE))
563 				err = azalia_mixer_set(this, this->speaker2,
564 				    MI_TARGET_OUTAMP, &mc);
565 			break;
566 		case AZ_SPKR_MUTE_SPKR_DIR:
567 			mc.un.ord = vol ? 0 : 1;
568 			err = azalia_mixer_set(this, this->speaker,
569 			    MI_TARGET_PINDIR, &mc);
570 			if (!err && this->speaker2 != -1 &&
571 			    (this->w[this->speaker2].d.pin.cap & COP_PINCAP_OUTPUT) &&
572 			    (this->w[this->speaker2].d.pin.cap & COP_PINCAP_INPUT))
573 				err = azalia_mixer_set(this, this->speaker2,
574 				    MI_TARGET_PINDIR, &mc);
575 			break;
576 		case AZ_SPKR_MUTE_DAC_MUTE:
577 			mc.un.ord = vol;
578 			err = azalia_mixer_set(this, this->spkr_dac,
579 			    MI_TARGET_OUTAMP, &mc);
580 			break;
581 		}
582 		break;
583 
584 	case AZ_TAG_PLAYVOL:
585 		if (this->playvols.master == this->audiofunc)
586 			return EINVAL;
587 		err = azalia_comresp(this, this->playvols.master,
588 		    CORB_GET_VOLUME_KNOB, 0, &result);
589 		if (err)
590 			return err;
591 
592 		vol = CORB_VKNOB_VOLUME(result) - this->playvols.hw_step;
593 		vol2 = vol * (AUDIO_MAX_GAIN / this->playvols.hw_nsteps);
594 		this->playvols.hw_step = CORB_VKNOB_VOLUME(result);
595 
596 		vol = vol2 + this->playvols.vol_l;
597 		if (vol < 0)
598 			vol = 0;
599 		else if (vol > AUDIO_MAX_GAIN)
600 			vol = AUDIO_MAX_GAIN;
601 		this->playvols.vol_l = vol;
602 
603 		vol = vol2 + this->playvols.vol_r;
604 		if (vol < 0)
605 			vol = 0;
606 		else if (vol > AUDIO_MAX_GAIN)
607 			vol = AUDIO_MAX_GAIN;
608 		this->playvols.vol_r = vol;
609 
610 		mc.type = AUDIO_MIXER_VALUE;
611 		mc.un.value.num_channels = 2;
612 		mc.un.value.level[0] = this->playvols.vol_l;
613 		mc.un.value.level[1] = this->playvols.vol_r;
614 		err = azalia_mixer_set(this, this->playvols.master,
615 		    MI_TARGET_PLAYVOL, &mc);
616 		break;
617 
618 	default:
619 		DPRINTF(("%s: unknown tag %d\n", __func__, tag));
620 		break;
621 	}
622 
623 	return err;
624 }
625 
626 
627 /* ----------------------------------------------------------------
628  * Generic mixer functions
629  * ---------------------------------------------------------------- */
630 
631 int
632 azalia_mixer_init(codec_t *this)
633 {
634 	/*
635 	 * pin		"<color>%2.2x"
636 	 * audio output	"dac%2.2x"
637 	 * audio input	"adc%2.2x"
638 	 * mixer	"mixer%2.2x"
639 	 * selector	"sel%2.2x"
640 	 */
641 	const widget_t *w, *ww;
642 	mixer_item_t *m;
643 	int err, i, j, k, bits;
644 
645 	this->maxmixers = 10;
646 	this->nmixers = 0;
647 	this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers,
648 	    M_DEVBUF, M_NOWAIT | M_ZERO);
649 	if (this->mixers == NULL) {
650 		printf("%s: out of memory in %s\n", XNAME(this), __func__);
651 		return ENOMEM;
652 	}
653 
654 	/* register classes */
655 	m = &this->mixers[AZ_CLASS_INPUT];
656 	m->devinfo.index = AZ_CLASS_INPUT;
657 	strlcpy(m->devinfo.label.name, AudioCinputs,
658 	    sizeof(m->devinfo.label.name));
659 	m->devinfo.type = AUDIO_MIXER_CLASS;
660 	m->devinfo.mixer_class = AZ_CLASS_INPUT;
661 	m->devinfo.next = AUDIO_MIXER_LAST;
662 	m->devinfo.prev = AUDIO_MIXER_LAST;
663 	m->nid = 0;
664 
665 	m = &this->mixers[AZ_CLASS_OUTPUT];
666 	m->devinfo.index = AZ_CLASS_OUTPUT;
667 	strlcpy(m->devinfo.label.name, AudioCoutputs,
668 	    sizeof(m->devinfo.label.name));
669 	m->devinfo.type = AUDIO_MIXER_CLASS;
670 	m->devinfo.mixer_class = AZ_CLASS_OUTPUT;
671 	m->devinfo.next = AUDIO_MIXER_LAST;
672 	m->devinfo.prev = AUDIO_MIXER_LAST;
673 	m->nid = 0;
674 
675 	m = &this->mixers[AZ_CLASS_RECORD];
676 	m->devinfo.index = AZ_CLASS_RECORD;
677 	strlcpy(m->devinfo.label.name, AudioCrecord,
678 	    sizeof(m->devinfo.label.name));
679 	m->devinfo.type = AUDIO_MIXER_CLASS;
680 	m->devinfo.mixer_class = AZ_CLASS_RECORD;
681 	m->devinfo.next = AUDIO_MIXER_LAST;
682 	m->devinfo.prev = AUDIO_MIXER_LAST;
683 	m->nid = 0;
684 
685 	this->nmixers = AZ_CLASS_RECORD + 1;
686 
687 #define MIXER_REG_PROLOG	\
688 	mixer_devinfo_t *d; \
689 	err = azalia_mixer_ensure_capacity(this, this->nmixers + 1); \
690 	if (err) \
691 		return err; \
692 	m = &this->mixers[this->nmixers]; \
693 	d = &m->devinfo; \
694 	m->nid = i
695 
696 	FOR_EACH_WIDGET(this, i) {
697 
698 		w = &this->w[i];
699 		if (!w->enable)
700 			continue;
701 
702 		/* selector */
703 		if (w->nconnections > 0 && w->type != COP_AWTYPE_AUDIO_MIXER &&
704 		    !(w->nconnections == 1 &&
705 		    azalia_widget_enabled(this, w->connections[0]) &&
706 		    strcmp(w->name, this->w[w->connections[0]].name) == 0) &&
707 		    w->nid != this->mic) {
708 			MIXER_REG_PROLOG;
709 			snprintf(d->label.name, sizeof(d->label.name),
710 			    "%s_source", w->name);
711 			d->type = AUDIO_MIXER_ENUM;
712 			if (w->mixer_class >= 0)
713 				d->mixer_class = w->mixer_class;
714 			else {
715 				if (w->type == COP_AWTYPE_AUDIO_SELECTOR)
716 					d->mixer_class = AZ_CLASS_INPUT;
717 				else
718 					d->mixer_class = AZ_CLASS_OUTPUT;
719 			}
720 			m->target = MI_TARGET_CONNLIST;
721 			for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
722 				if (!azalia_widget_enabled(this,
723 				    w->connections[j]))
724 					continue;
725 				d->un.e.member[k].ord = j;
726 				strlcpy(d->un.e.member[k].label.name,
727 				    this->w[w->connections[j]].name,
728 				    MAX_AUDIO_DEV_LEN);
729 				k++;
730 			}
731 			d->un.e.num_mem = k;
732 			this->nmixers++;
733 		}
734 
735 		/* output mute */
736 		if (w->widgetcap & COP_AWCAP_OUTAMP &&
737 		    w->outamp_cap & COP_AMPCAP_MUTE &&
738 		    w->nid != this->mic) {
739 			MIXER_REG_PROLOG;
740 			snprintf(d->label.name, sizeof(d->label.name),
741 			    "%s_mute", w->name);
742 			if (w->mixer_class >= 0)
743 				d->mixer_class = w->mixer_class;
744 			else {
745 				if (w->type == COP_AWTYPE_AUDIO_MIXER ||
746 				    w->type == COP_AWTYPE_AUDIO_SELECTOR ||
747 				    w->type == COP_AWTYPE_PIN_COMPLEX)
748 					d->mixer_class = AZ_CLASS_OUTPUT;
749 				else
750 					d->mixer_class = AZ_CLASS_INPUT;
751 			}
752 			m->target = MI_TARGET_OUTAMP;
753 			azalia_devinfo_offon(d);
754 			this->nmixers++;
755 		}
756 
757 		/* output gain */
758 		if (w->widgetcap & COP_AWCAP_OUTAMP &&
759 		    COP_AMPCAP_NUMSTEPS(w->outamp_cap) &&
760 		    w->nid != this->mic) {
761 			MIXER_REG_PROLOG;
762 			snprintf(d->label.name, sizeof(d->label.name),
763 			    "%s", w->name);
764 			d->type = AUDIO_MIXER_VALUE;
765 			if (w->mixer_class >= 0)
766 				d->mixer_class = w->mixer_class;
767 			else {
768 				if (w->type == COP_AWTYPE_AUDIO_MIXER ||
769 				    w->type == COP_AWTYPE_AUDIO_SELECTOR ||
770 				    w->type == COP_AWTYPE_PIN_COMPLEX)
771 					d->mixer_class = AZ_CLASS_OUTPUT;
772 				else
773 					d->mixer_class = AZ_CLASS_INPUT;
774 			}
775 			m->target = MI_TARGET_OUTAMP;
776 			d->un.v.num_channels = WIDGET_CHANNELS(w);
777 			d->un.v.units.name[0] = 0;
778 			d->un.v.delta =
779 			    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap));
780 			this->nmixers++;
781 		}
782 
783 		/* input mute */
784 		if (w->widgetcap & COP_AWCAP_INAMP &&
785 		    w->inamp_cap & COP_AMPCAP_MUTE &&
786 		    w->nid != this->speaker &&
787 		    w->nid != this->speaker2) {
788 			if (w->type != COP_AWTYPE_AUDIO_MIXER) {
789 				MIXER_REG_PROLOG;
790 				snprintf(d->label.name, sizeof(d->label.name),
791 				    "%s_mute", w->name);
792 				if (w->mixer_class >= 0)
793 					d->mixer_class = w->mixer_class;
794 				else
795 					d->mixer_class = AZ_CLASS_INPUT;
796 				m->target = 0;
797 				azalia_devinfo_offon(d);
798 				this->nmixers++;
799 			} else {
800 				MIXER_REG_PROLOG;
801 				snprintf(d->label.name, sizeof(d->label.name),
802 				    "%s_source", w->name);
803 				m->target = MI_TARGET_MUTESET;
804 				d->type = AUDIO_MIXER_SET;
805 				if (w->mixer_class >= 0)
806 					d->mixer_class = w->mixer_class;
807 				else
808 					d->mixer_class = AZ_CLASS_INPUT;
809 				for (j = 0, k = 0;
810 				    j < w->nconnections && k < 32; j++) {
811 					if (!azalia_widget_enabled(this,
812 					    w->connections[j]))
813 						continue;
814 					if (w->connections[j] == this->speaker ||
815 					    w->connections[j] == this->speaker2)
816 						continue;
817 					d->un.s.member[k].mask = 1 << j;
818 					strlcpy(d->un.s.member[k].label.name,
819 					    this->w[w->connections[j]].name,
820 					    MAX_AUDIO_DEV_LEN);
821 					k++;
822 				}
823 				d->un.s.num_mem = k;
824 				if (k != 0)
825 					this->nmixers++;
826 			}
827 		}
828 
829 		/* input gain */
830 		if (w->widgetcap & COP_AWCAP_INAMP &&
831 		    COP_AMPCAP_NUMSTEPS(w->inamp_cap) &&
832 		    w->nid != this->speaker &&
833 		    w->nid != this->speaker2) {
834 			if (w->type != COP_AWTYPE_AUDIO_SELECTOR &&
835 			    w->type != COP_AWTYPE_AUDIO_MIXER) {
836 				MIXER_REG_PROLOG;
837 				snprintf(d->label.name, sizeof(d->label.name),
838 				    "%s", w->name);
839 				d->type = AUDIO_MIXER_VALUE;
840 				if (w->mixer_class >= 0)
841 					d->mixer_class = w->mixer_class;
842 				else
843 					d->mixer_class = AZ_CLASS_INPUT;
844 				m->target = 0;
845 				d->un.v.num_channels = WIDGET_CHANNELS(w);
846 				d->un.v.units.name[0] = 0;
847 				d->un.v.delta =
848 				    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
849 				this->nmixers++;
850 			} else {
851 				for (j = 0; j < w->nconnections; j++) {
852 					if (!azalia_widget_enabled(this,
853 					    w->connections[j]))
854 						continue;
855 					if (w->connections[j] == this->speaker ||
856 					    w->connections[j] == this->speaker2)
857 						continue;
858 					MIXER_REG_PROLOG;
859 					snprintf(d->label.name,
860 					    sizeof(d->label.name), "%s_%s",
861 					    w->name,
862 					    this->w[w->connections[j]].name);
863 					d->type = AUDIO_MIXER_VALUE;
864 					if (w->mixer_class >= 0)
865 						d->mixer_class = w->mixer_class;
866 					else
867 						d->mixer_class = AZ_CLASS_INPUT;
868 					m->target = j;
869 					d->un.v.num_channels = WIDGET_CHANNELS(w);
870 					d->un.v.units.name[0] = 0;
871 					d->un.v.delta =
872 					    MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap));
873 					this->nmixers++;
874 				}
875 			}
876 		}
877 
878 		/* hardcoded mixer inputs */
879 		if (w->type == COP_AWTYPE_AUDIO_MIXER &&
880 		    !(w->widgetcap & COP_AWCAP_INAMP)) {
881 			MIXER_REG_PROLOG;
882 			snprintf(d->label.name, sizeof(d->label.name),
883 			    "%s_source", w->name);
884 			m->target = MI_TARGET_MIXERSET;
885 			d->type = AUDIO_MIXER_SET;
886 			if (w->mixer_class >= 0)
887 				d->mixer_class = w->mixer_class;
888 			else
889 				d->mixer_class = AZ_CLASS_INPUT;
890 			for (j = 0, k = 0;
891 			    j < w->nconnections && k < 32; j++) {
892 				if (!azalia_widget_enabled(this,
893 				    w->connections[j]))
894 					continue;
895 				if (w->connections[j] == this->speaker ||
896 				    w->connections[j] == this->speaker2)
897 					continue;
898 				d->un.s.member[k].mask = 1 << j;
899 				strlcpy(d->un.s.member[k].label.name,
900 				    this->w[w->connections[j]].name,
901 				    MAX_AUDIO_DEV_LEN);
902 				k++;
903 			}
904 			d->un.s.num_mem = k;
905 			if (k != 0)
906 				this->nmixers++;
907 		}
908 
909 		/* pin direction */
910 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
911 		    ((w->d.pin.cap & COP_PINCAP_OUTPUT &&
912 		    w->d.pin.cap & COP_PINCAP_INPUT) ||
913 		    COP_PINCAP_VREF(w->d.pin.cap) > 1)) {
914 
915 			MIXER_REG_PROLOG;
916 			snprintf(d->label.name, sizeof(d->label.name),
917 			    "%s_dir", w->name);
918 			d->type = AUDIO_MIXER_ENUM;
919 			d->mixer_class = AZ_CLASS_OUTPUT;
920 			m->target = MI_TARGET_PINDIR;
921 
922 			k = 0;
923 			d->un.e.member[k].ord = 0;
924 			strlcpy(d->un.e.member[k].label.name, "none",
925 			    MAX_AUDIO_DEV_LEN);
926 			k++;
927 
928 			if (w->d.pin.cap & COP_PINCAP_OUTPUT) {
929 				d->un.e.member[k].ord = 1;
930 				strlcpy(d->un.e.member[k].label.name,
931 				    AudioNoutput, MAX_AUDIO_DEV_LEN);
932 				k++;
933 			}
934 
935 			if (w->d.pin.cap & COP_PINCAP_INPUT) {
936 				d->un.e.member[k].ord = 2;
937 				strlcpy(d->un.e.member[k].label.name,
938 				    AudioNinput, MAX_AUDIO_DEV_LEN);
939 				k++;
940 
941 				for (j = 0; j < 4; j++) {
942 					if (j == 0) {
943 						bits = (1 << CORB_PWC_VREF_GND);
944 						strlcpy(d->un.e.member[k].label.name,
945 						    AudioNinput "-vr0",
946 						    MAX_AUDIO_DEV_LEN);
947 					} else if (j == 1) {
948 						bits = (1 << CORB_PWC_VREF_50);
949 						strlcpy(d->un.e.member[k].label.name,
950 						    AudioNinput "-vr50",
951 						    MAX_AUDIO_DEV_LEN);
952 					} else if (j == 2) {
953 						bits = (1 << CORB_PWC_VREF_80);
954 						strlcpy(d->un.e.member[k].label.name,
955 						    AudioNinput "-vr80",
956 						    MAX_AUDIO_DEV_LEN);
957 					} else if (j == 3) {
958 						bits = (1 << CORB_PWC_VREF_100);
959 						strlcpy(d->un.e.member[k].label.name,
960 						    AudioNinput "-vr100",
961 						    MAX_AUDIO_DEV_LEN);
962 					}
963 					if ((COP_PINCAP_VREF(w->d.pin.cap) &
964 					    bits) == bits) {
965 						d->un.e.member[k].ord = j + 3;
966 						k++;
967 					}
968 				}
969 			}
970 			d->un.e.num_mem = k;
971 			this->nmixers++;
972 		}
973 
974 		/* pin headphone-boost */
975 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
976 		    w->d.pin.cap & COP_PINCAP_HEADPHONE &&
977 		    w->nid != this->mic) {
978 			MIXER_REG_PROLOG;
979 			snprintf(d->label.name, sizeof(d->label.name),
980 			    "%s_boost", w->name);
981 			d->mixer_class = AZ_CLASS_OUTPUT;
982 			m->target = MI_TARGET_PINBOOST;
983 			azalia_devinfo_offon(d);
984 			this->nmixers++;
985 		}
986 
987 		if (w->type == COP_AWTYPE_PIN_COMPLEX &&
988 		    w->d.pin.cap & COP_PINCAP_EAPD) {
989 			MIXER_REG_PROLOG;
990 			snprintf(d->label.name, sizeof(d->label.name),
991 			    "%s_eapd", w->name);
992 			d->mixer_class = AZ_CLASS_OUTPUT;
993 			m->target = MI_TARGET_EAPD;
994 			azalia_devinfo_offon(d);
995 			this->nmixers++;
996 		}
997 	}
998 
999 	/* sense pins */
1000 	for (i = 0; i < this->nsense_pins; i++) {
1001 		if (!azalia_widget_enabled(this, this->sense_pins[i])) {
1002 			DPRINTF(("%s: sense pin %2.2x not found\n",
1003 			    __func__, this->sense_pins[i]));
1004 			continue;
1005 		}
1006 
1007 		MIXER_REG_PROLOG;
1008 		m->nid = this->w[this->sense_pins[i]].nid;
1009 		snprintf(d->label.name, sizeof(d->label.name), "%s_sense",
1010 		    this->w[this->sense_pins[i]].name);
1011 		d->type = AUDIO_MIXER_ENUM;
1012 		d->mixer_class = AZ_CLASS_OUTPUT;
1013 		m->target = MI_TARGET_PINSENSE;
1014 		d->un.e.num_mem = 2;
1015 		d->un.e.member[0].ord = 0;
1016 		strlcpy(d->un.e.member[0].label.name, "unplugged",
1017 		    MAX_AUDIO_DEV_LEN);
1018 		d->un.e.member[1].ord = 1;
1019 		strlcpy(d->un.e.member[1].label.name, "plugged",
1020 		    MAX_AUDIO_DEV_LEN);
1021 		this->nmixers++;
1022 	}
1023 
1024 	/* spkr mute by jack sense */
1025 	this->spkr_mute_method = AZ_SPKR_MUTE_NONE;
1026 	if (this->speaker != -1 && this->spkr_dac != -1 && this->nsense_pins > 0) {
1027 		w = &this->w[this->speaker];
1028 		if ((w->widgetcap & COP_AWCAP_OUTAMP) &&
1029 		    (w->outamp_cap & COP_AMPCAP_MUTE))
1030 			this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_MUTE;
1031 		else if ((w->d.pin.cap & COP_PINCAP_OUTPUT) &&
1032 		    (w->d.pin.cap & COP_PINCAP_INPUT))
1033 			this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_DIR;
1034 		else {
1035 			w = &this->w[this->spkr_dac];
1036 			if (w->nid != this->dacs.groups[0].conv[0] &&
1037 			    (w->widgetcap & COP_AWCAP_OUTAMP) &&
1038 			    (w->outamp_cap & COP_AMPCAP_MUTE))
1039 				this->spkr_mute_method = AZ_SPKR_MUTE_DAC_MUTE;
1040 		}
1041 	}
1042 	if (this->spkr_mute_method != AZ_SPKR_MUTE_NONE) {
1043 		w = &this->w[this->speaker];
1044 		MIXER_REG_PROLOG;
1045 		m->nid = w->nid;
1046 		snprintf(d->label.name, sizeof(d->label.name),
1047 		    "%s_muters", w->name);
1048 		m->target = MI_TARGET_SENSESET;
1049 		d->type = AUDIO_MIXER_SET;
1050 		d->mixer_class = AZ_CLASS_OUTPUT;
1051 		this->spkr_muters = 0;
1052 		for (i = 0, j = 0; i < this->nsense_pins; i++) {
1053 			ww = &this->w[this->sense_pins[i]];
1054 			if (!(ww->d.pin.cap & COP_PINCAP_OUTPUT))
1055 				continue;
1056 			if (!(ww->widgetcap & COP_AWCAP_UNSOL))
1057 				continue;
1058 			d->un.s.member[j].mask = 1 << i;
1059 			this->spkr_muters |= (1 << i);
1060 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1061 			    MAX_AUDIO_DEV_LEN);
1062 		}
1063 		d->un.s.num_mem = j;
1064 		if (j != 0)
1065 			this->nmixers++;
1066 	}
1067 
1068 	/* playback volume group */
1069 	if (this->playvols.nslaves > 0) {
1070 		mixer_devinfo_t *d;
1071 		err = azalia_mixer_ensure_capacity(this,
1072 		    this->nmixers + 3);
1073 
1074 		/* volume */
1075 		m = &this->mixers[this->nmixers];
1076 		m->nid = this->playvols.master;
1077 		m->target = MI_TARGET_PLAYVOL;
1078 		d = &m->devinfo;
1079 		d->mixer_class = AZ_CLASS_OUTPUT;
1080 		snprintf(d->label.name, sizeof(d->label.name),
1081 		    "%s", AudioNmaster);
1082 		d->type = AUDIO_MIXER_VALUE;
1083 		d->un.v.num_channels = 2;
1084 		d->un.v.delta = 8;
1085 		this->nmixers++;
1086 		d->next = this->nmixers;
1087 
1088 		/* mute */
1089 		m = &this->mixers[this->nmixers];
1090 		m->nid = this->playvols.master;
1091 		m->target = MI_TARGET_PLAYVOL;
1092 		d = &m->devinfo;
1093 		d->prev = this->nmixers - 1;
1094 		d->mixer_class = AZ_CLASS_OUTPUT;
1095 		snprintf(d->label.name, sizeof(d->label.name),
1096 		    "%s", AudioNmute);
1097 		azalia_devinfo_offon(d);
1098 		this->nmixers++;
1099 		d->next = this->nmixers;
1100 
1101 		/* slaves */
1102 		m = &this->mixers[this->nmixers];
1103 		m->nid = this->playvols.master;
1104 		m->target = MI_TARGET_PLAYVOL;
1105 		d = &m->devinfo;
1106 		d->prev = this->nmixers - 1;
1107 		d->mixer_class = AZ_CLASS_OUTPUT;
1108 		snprintf(d->label.name, sizeof(d->label.name),
1109 		    "%s", "slaves");
1110 		d->type = AUDIO_MIXER_SET;
1111 		for (i = 0, j = 0; i < this->playvols.nslaves; i++) {
1112 			ww = &this->w[this->playvols.slaves[i]];
1113 			d->un.s.member[j].mask = (1 << i);
1114 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1115 			    MAX_AUDIO_DEV_LEN);
1116 		}
1117 		d->un.s.num_mem = j;
1118 		this->nmixers++;
1119 	}
1120 
1121 	/* recording volume group */
1122 	if (this->recvols.nslaves > 0) {
1123 		mixer_devinfo_t *d;
1124 		err = azalia_mixer_ensure_capacity(this,
1125 		    this->nmixers + 3);
1126 
1127 		/* volume */
1128 		m = &this->mixers[this->nmixers];
1129 		m->nid = this->recvols.master;
1130 		m->target = MI_TARGET_RECVOL;
1131 		d = &m->devinfo;
1132 		d->mixer_class = AZ_CLASS_RECORD;
1133 		snprintf(d->label.name, sizeof(d->label.name),
1134 		    "%s", AudioNvolume);
1135 		d->type = AUDIO_MIXER_VALUE;
1136 		d->un.v.num_channels = 2;
1137 		d->un.v.delta = 8;
1138 		this->nmixers++;
1139 		d->next = this->nmixers;
1140 
1141 		/* mute */
1142 		m = &this->mixers[this->nmixers];
1143 		m->nid = this->recvols.master;
1144 		m->target = MI_TARGET_RECVOL;
1145 		d = &m->devinfo;
1146 		d->prev = this->nmixers - 1;
1147 		d->mixer_class = AZ_CLASS_RECORD;
1148 		snprintf(d->label.name, sizeof(d->label.name),
1149 		    "%s", AudioNmute);
1150 		azalia_devinfo_offon(d);
1151 		this->nmixers++;
1152 		d->next = this->nmixers;
1153 
1154 		/* slaves */
1155 		m = &this->mixers[this->nmixers];
1156 		m->nid = this->recvols.master;
1157 		m->target = MI_TARGET_RECVOL;
1158 		d = &m->devinfo;
1159 		d->prev = this->nmixers - 1;
1160 		d->mixer_class = AZ_CLASS_RECORD;
1161 		snprintf(d->label.name, sizeof(d->label.name),
1162 		    "%s", "slaves");
1163 		d->type = AUDIO_MIXER_SET;
1164 		for (i = 0, j = 0; i < this->recvols.nslaves; i++) {
1165 			ww = &this->w[this->recvols.slaves[i]];
1166 			d->un.s.member[j].mask = (1 << i);
1167 			strlcpy(d->un.s.member[j++].label.name, ww->name,
1168 			    MAX_AUDIO_DEV_LEN);
1169 		}
1170 		d->un.s.num_mem = j;
1171 		this->nmixers++;
1172 	}
1173 
1174 	/* if the codec has more than one DAC group, the first is analog
1175 	 * and the second is digital.
1176 	 */
1177 	if (this->dacs.ngroups > 1) {
1178 		MIXER_REG_PROLOG;
1179 		strlcpy(d->label.name, AudioNmode, sizeof(d->label.name));
1180 		d->type = AUDIO_MIXER_ENUM;
1181 		d->mixer_class = AZ_CLASS_OUTPUT;
1182 		m->target = MI_TARGET_DAC;
1183 		m->nid = this->audiofunc;
1184 		d->un.e.member[0].ord = 0;
1185 		strlcpy(d->un.e.member[0].label.name, "analog",
1186 		    MAX_AUDIO_DEV_LEN);
1187 		d->un.e.member[1].ord = 1;
1188 		strlcpy(d->un.e.member[1].label.name, "digital",
1189 		    MAX_AUDIO_DEV_LEN);
1190 		d->un.e.num_mem = 2;
1191 		this->nmixers++;
1192 	}
1193 
1194 	/* if the codec has more than one ADC group, the first is analog
1195 	 * and the second is digital.
1196 	 */
1197 	if (this->adcs.ngroups > 1) {
1198 		MIXER_REG_PROLOG;
1199 		strlcpy(d->label.name, AudioNmode, sizeof(d->label.name));
1200 		d->type = AUDIO_MIXER_ENUM;
1201 		d->mixer_class = AZ_CLASS_RECORD;
1202 		m->target = MI_TARGET_ADC;
1203 		m->nid = this->audiofunc;
1204 		d->un.e.member[0].ord = 0;
1205 		strlcpy(d->un.e.member[0].label.name, "analog",
1206 		    MAX_AUDIO_DEV_LEN);
1207 		d->un.e.member[1].ord = 1;
1208 		strlcpy(d->un.e.member[1].label.name, "digital",
1209 		    MAX_AUDIO_DEV_LEN);
1210 		d->un.e.num_mem = 2;
1211 		this->nmixers++;
1212 	}
1213 
1214 	azalia_mixer_fix_indexes(this);
1215 	azalia_mixer_default(this);
1216 	return 0;
1217 }
1218 
1219 void
1220 azalia_devinfo_offon(mixer_devinfo_t *d)
1221 {
1222 	d->type = AUDIO_MIXER_ENUM;
1223 	d->un.e.num_mem = 2;
1224 	d->un.e.member[0].ord = 0;
1225 	strlcpy(d->un.e.member[0].label.name, AudioNoff, MAX_AUDIO_DEV_LEN);
1226 	d->un.e.member[1].ord = 1;
1227 	strlcpy(d->un.e.member[1].label.name, AudioNon, MAX_AUDIO_DEV_LEN);
1228 }
1229 
1230 int
1231 azalia_mixer_ensure_capacity(codec_t *this, size_t newsize)
1232 {
1233 	size_t newmax;
1234 	void *newbuf;
1235 
1236 	if (this->maxmixers >= newsize)
1237 		return 0;
1238 	newmax = this->maxmixers + 10;
1239 	if (newmax < newsize)
1240 		newmax = newsize;
1241 	newbuf = malloc(sizeof(mixer_item_t) * newmax, M_DEVBUF, M_NOWAIT | M_ZERO);
1242 	if (newbuf == NULL) {
1243 		printf("%s: out of memory in %s\n", XNAME(this), __func__);
1244 		return ENOMEM;
1245 	}
1246 	bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t));
1247 	free(this->mixers, M_DEVBUF);
1248 	this->mixers = newbuf;
1249 	this->maxmixers = newmax;
1250 	return 0;
1251 }
1252 
1253 int
1254 azalia_mixer_fix_indexes(codec_t *this)
1255 {
1256 	int i;
1257 	mixer_devinfo_t *d;
1258 
1259 	for (i = 0; i < this->nmixers; i++) {
1260 		d = &this->mixers[i].devinfo;
1261 #ifdef DIAGNOSTIC
1262 		if (d->index != 0 && d->index != i)
1263 			printf("%s: index mismatch %d %d\n", __func__,
1264 			    d->index, i);
1265 #endif
1266 		d->index = i;
1267 		if (d->prev == 0)
1268 			d->prev = AUDIO_MIXER_LAST;
1269 		if (d->next == 0)
1270 			d->next = AUDIO_MIXER_LAST;
1271 	}
1272 	return 0;
1273 }
1274 
1275 int
1276 azalia_mixer_default(codec_t *this)
1277 {
1278 	widget_t *w;
1279 	mixer_item_t *m;
1280 	mixer_ctrl_t mc;
1281 	int i, j, tgt, cap, err;
1282 
1283 	/* unmute all */
1284 	for (i = 0; i < this->nmixers; i++) {
1285 		m = &this->mixers[i];
1286 		if (!IS_MI_TARGET_INAMP(m->target) &&
1287 		    m->target != MI_TARGET_OUTAMP)
1288 			continue;
1289 		if (m->devinfo.type != AUDIO_MIXER_ENUM)
1290 			continue;
1291 		bzero(&mc, sizeof(mc));
1292 		mc.dev = i;
1293 		mc.type = AUDIO_MIXER_ENUM;
1294 		azalia_mixer_set(this, m->nid, m->target, &mc);
1295 	}
1296 
1297 	/* set unextreme volume */
1298 	for (i = 0; i < this->nmixers; i++) {
1299 		m = &this->mixers[i];
1300 		if (!IS_MI_TARGET_INAMP(m->target) &&
1301 		    m->target != MI_TARGET_OUTAMP)
1302 			continue;
1303 		if (m->devinfo.type != AUDIO_MIXER_VALUE)
1304 			continue;
1305 		bzero(&mc, sizeof(mc));
1306 		mc.dev = i;
1307 		mc.type = AUDIO_MIXER_VALUE;
1308 		mc.un.value.num_channels = 1;
1309 		mc.un.value.level[0] = AUDIO_MAX_GAIN / 2;
1310 		if (WIDGET_CHANNELS(&this->w[m->nid]) == 2) {
1311 			mc.un.value.num_channels = 2;
1312 			mc.un.value.level[1] = mc.un.value.level[0];
1313 		}
1314 		azalia_mixer_set(this, m->nid, m->target, &mc);
1315 	}
1316 
1317 	/* unmute all */
1318 	for (i = 0; i < this->nmixers; i++) {
1319 		m = &this->mixers[i];
1320 		if (m->target != MI_TARGET_MUTESET)
1321 			continue;
1322 		if (m->devinfo.type != AUDIO_MIXER_SET)
1323 			continue;
1324 		bzero(&mc, sizeof(mc));
1325 		mc.dev = i;
1326 		mc.type = AUDIO_MIXER_SET;
1327 		if (!azalia_widget_enabled(this, m->nid)) {
1328 			DPRINTF(("%s: invalid set nid\n", __func__));
1329 			return EINVAL;
1330 		}
1331 		w = &this->w[m->nid];
1332 		for (j = 0; j < w->nconnections; j++) {
1333 			if (!azalia_widget_enabled(this, w->connections[j]))
1334 				continue;
1335 			if (w->nid == this->input_mixer &&
1336 			    w->connections[j] == this->mic)
1337 				continue;
1338 			mc.un.mask |= 1 << j;
1339 		}
1340 		azalia_mixer_set(this, m->nid, m->target, &mc);
1341 	}
1342 
1343 	/* make sure default connection is valid */
1344 	for (i = 0; i < this->nmixers; i++) {
1345 		m = &this->mixers[i];
1346 		if (m->target != MI_TARGET_CONNLIST)
1347 			continue;
1348 
1349 		azalia_mixer_get(this, m->nid, m->target, &mc);
1350 		for (j = 0; j < m->devinfo.un.e.num_mem; j++) {
1351 			if (mc.un.ord == m->devinfo.un.e.member[j].ord)
1352 				break;
1353 		}
1354 		if (j >= m->devinfo.un.e.num_mem) {
1355 			bzero(&mc, sizeof(mc));
1356 			mc.dev = i;
1357 			mc.type = AUDIO_MIXER_ENUM;
1358 			mc.un.ord = m->devinfo.un.e.member[0].ord;
1359 		}
1360 		azalia_mixer_set(this, m->nid, m->target, &mc);
1361 	}
1362 
1363 	/* get default value for play group master */
1364 	for (i = 0; i < this->playvols.nslaves; i++) {
1365 		if (!(this->playvols.cur & (1 << i)))
1366  			continue;
1367 		w = &this->w[this->playvols.slaves[i]];
1368 		if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)))
1369 			continue;
1370 		mc.type = AUDIO_MIXER_VALUE;
1371 		tgt = MI_TARGET_OUTAMP;
1372 		azalia_mixer_get(this, w->nid, tgt, &mc);
1373 		this->playvols.vol_l = mc.un.value.level[0];
1374 		this->playvols.vol_r = mc.un.value.level[0];
1375 		break;
1376  	}
1377 	this->playvols.mute = 0;
1378 
1379 	/* get default value for record group master */
1380 	for (i = 0; i < this->recvols.nslaves; i++) {
1381 		if (!(this->recvols.cur & (1 << i)))
1382 			continue;
1383 		w = &this->w[this->recvols.slaves[i]];
1384 		mc.type = AUDIO_MIXER_VALUE;
1385 		tgt = MI_TARGET_OUTAMP;
1386 		cap = w->outamp_cap;
1387 		if (w->type == COP_AWTYPE_PIN_COMPLEX ||
1388 		    w->type == COP_AWTYPE_AUDIO_INPUT) {
1389 			tgt = 0;
1390 			cap = w->inamp_cap;
1391  		}
1392 		if (!(COP_AMPCAP_NUMSTEPS(cap)))
1393 			continue;
1394 		azalia_mixer_get(this, w->nid, tgt, &mc);
1395 		this->recvols.vol_l = mc.un.value.level[0];
1396 		this->recvols.vol_r = mc.un.value.level[0];
1397 		break;
1398  	}
1399 	this->recvols.mute = 0;
1400 
1401 	err = azalia_codec_enable_unsol(this);
1402 	if (err)
1403 		return(err);
1404 
1405 	return 0;
1406 }
1407 
1408 int
1409 azalia_codec_enable_unsol(codec_t *this)
1410 {
1411 	widget_t *w;
1412 	uint32_t result;
1413 	int i, err;
1414 
1415 	/* jack sense */
1416 	for (i = 0; i < this->nsense_pins; i++) {
1417 		if (this->spkr_muters & (1 << i)) {
1418 			azalia_comresp(this, this->sense_pins[i],
1419 			    CORB_SET_UNSOLICITED_RESPONSE,
1420 			    CORB_UNSOL_ENABLE | AZ_TAG_SPKR, NULL);
1421 		}
1422 	}
1423 	if (this->spkr_muters != 0)
1424 		azalia_unsol_event(this, AZ_TAG_SPKR);
1425 
1426 	/* volume knob */
1427 	if (this->playvols.master != this->audiofunc) {
1428 
1429 		w = &this->w[this->playvols.master];
1430 		err = azalia_comresp(this, w->nid, CORB_GET_VOLUME_KNOB,
1431 		    0, &result);
1432 		if (err) {
1433 			DPRINTF(("%s: get volume knob error\n", __func__));
1434 			return err;
1435 		}
1436 
1437 		/* current level */
1438 		this->playvols.hw_step = CORB_VKNOB_VOLUME(result);
1439 		this->playvols.hw_nsteps = COP_VKCAP_NUMSTEPS(w->d.volume.cap);
1440 
1441 		/* indirect mode */
1442 		result &= ~(CORB_VKNOB_DIRECT);
1443 		err = azalia_comresp(this, w->nid, CORB_SET_VOLUME_KNOB,
1444 		    result, NULL);
1445 		if (err) {
1446 			DPRINTF(("%s: set volume knob error\n", __func__));
1447 			/* XXX If there was an error setting indirect
1448 			 * mode, do not return an error.  However, do not
1449 			 * enable unsolicited responses either.  Most
1450 			 * likely the volume knob doesn't work right.
1451 			 * Perhaps it's simply not wired/enabled.
1452 			 */
1453 			return 0;
1454 		}
1455 
1456 		/* enable unsolicited responses */
1457 		result = CORB_UNSOL_ENABLE | AZ_TAG_PLAYVOL;
1458 		err = azalia_comresp(this, w->nid,
1459 		    CORB_SET_UNSOLICITED_RESPONSE, result, NULL);
1460 		if (err) {
1461 			DPRINTF(("%s: set vknob unsol resp error\n", __func__));
1462 			return err;
1463 		}
1464 	}
1465 
1466 	return 0;
1467 }
1468 
1469 int
1470 azalia_mixer_delete(codec_t *this)
1471 {
1472 	if (this->mixers != NULL) {
1473 		free(this->mixers, M_DEVBUF);
1474 		this->mixers = NULL;
1475 	}
1476 	return 0;
1477 }
1478 
1479 /**
1480  * @param mc	mc->type must be set by the caller before the call
1481  */
1482 int
1483 azalia_mixer_get(const codec_t *this, nid_t nid, int target,
1484     mixer_ctrl_t *mc)
1485 {
1486 	uint32_t result, cap, value;
1487 	nid_t n;
1488 	int i, err;
1489 
1490 	if (mc->type == AUDIO_MIXER_CLASS) {
1491 		return(0);
1492 	}
1493 
1494 	/* inamp mute */
1495 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
1496 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1497 		    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1498 		    MI_TARGET_INAMP(target), &result);
1499 		if (err)
1500 			return err;
1501 		mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
1502 	}
1503 
1504 	/* inamp gain */
1505 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
1506 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1507 		      CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1508 		      MI_TARGET_INAMP(target), &result);
1509 		if (err)
1510 			return err;
1511 		mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1512 		    nid, target, CORB_GAGM_GAIN(result));
1513 		if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR ||
1514 		    this->w[nid].type == COP_AWTYPE_AUDIO_MIXER) {
1515 			n = this->w[nid].connections[MI_TARGET_INAMP(target)];
1516 			if (!azalia_widget_enabled(this, n)) {
1517 				DPRINTF(("%s: nid %2.2x invalid index %d\n",
1518 				   __func__, nid,  MI_TARGET_INAMP(target)));
1519 				n = nid;
1520 			}
1521 		} else
1522 			n = nid;
1523 		mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n]);
1524 		if (mc->un.value.num_channels == 2) {
1525 			err = azalia_comresp(this, nid,
1526 			    CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1527 			    CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1528 			    &result);
1529 			if (err)
1530 				return err;
1531 			mc->un.value.level[1] = azalia_mixer_from_device_value
1532 			    (this, nid, target, CORB_GAGM_GAIN(result));
1533 		}
1534 	}
1535 
1536 	/* outamp mute */
1537 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
1538 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1539 		    CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
1540 		if (err)
1541 			return err;
1542 		mc->un.ord = result & CORB_GAGM_MUTE ? 1 : 0;
1543 	}
1544 
1545 	/* outamp gain */
1546 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
1547 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1548 		      CORB_GAGM_OUTPUT | CORB_GAGM_LEFT | 0, &result);
1549 		if (err)
1550 			return err;
1551 		mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1552 		    nid, target, CORB_GAGM_GAIN(result));
1553 		mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid]);
1554 		if (mc->un.value.num_channels == 2) {
1555 			err = azalia_comresp(this, nid,
1556 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1557 			    CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT | 0, &result);
1558 			if (err)
1559 				return err;
1560 			mc->un.value.level[1] = azalia_mixer_from_device_value
1561 			    (this, nid, target, CORB_GAGM_GAIN(result));
1562 		}
1563 	}
1564 
1565 	/* selection */
1566 	else if (target == MI_TARGET_CONNLIST) {
1567 		err = azalia_comresp(this, nid,
1568 		    CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
1569 		if (err)
1570 			return err;
1571 		result = CORB_CSC_INDEX(result);
1572 		if (!azalia_widget_enabled(this,
1573 		    this->w[nid].connections[result]))
1574 			mc->un.ord = -1;
1575 		else
1576 			mc->un.ord = result;
1577 	}
1578 
1579 	/* pin I/O */
1580 	else if (target == MI_TARGET_PINDIR) {
1581 		err = azalia_comresp(this, nid,
1582 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1583 		if (err)
1584 			return err;
1585 
1586 		value = result;
1587 		if (!(result & (CORB_PWC_INPUT | CORB_PWC_OUTPUT)))
1588 			mc->un.ord = 0;
1589 		else if (result & CORB_PWC_OUTPUT)
1590 			mc->un.ord = 1;
1591 		else {
1592 			cap = COP_PINCAP_VREF(this->w[nid].d.pin.cap);
1593 			result &= CORB_PWC_VREF_MASK;
1594 			if (result == CORB_PWC_VREF_GND)
1595 				mc->un.ord = 3;
1596 			else if (result == CORB_PWC_VREF_50)
1597 				mc->un.ord = 4;
1598 			else if (result == CORB_PWC_VREF_80)
1599 				mc->un.ord = 5;
1600 			else if (result == CORB_PWC_VREF_100)
1601 				mc->un.ord = 6;
1602 			else
1603 				mc->un.ord = 2;
1604 		}
1605 	}
1606 
1607 	/* pin headphone-boost */
1608 	else if (target == MI_TARGET_PINBOOST) {
1609 		err = azalia_comresp(this, nid,
1610 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1611 		if (err)
1612 			return err;
1613 		mc->un.ord = result & CORB_PWC_HEADPHONE ? 1 : 0;
1614 	}
1615 
1616 	/* DAC group selection */
1617 	else if (target == MI_TARGET_DAC) {
1618 		mc->un.ord = this->dacs.cur;
1619 	}
1620 
1621 	/* ADC selection */
1622 	else if (target == MI_TARGET_ADC) {
1623 		mc->un.ord = this->adcs.cur;
1624 	}
1625 
1626 	/* S/PDIF */
1627 	else if (target == MI_TARGET_SPDIF) {
1628 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
1629 		    0, &result);
1630 		if (err)
1631 			return err;
1632 		mc->un.mask = result & 0xff & ~(CORB_DCC_DIGEN | CORB_DCC_NAUDIO);
1633 	} else if (target == MI_TARGET_SPDIF_CC) {
1634 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
1635 		    0, &result);
1636 		if (err)
1637 			return err;
1638 		mc->un.value.num_channels = 1;
1639 		mc->un.value.level[0] = CORB_DCC_CC(result);
1640 	}
1641 
1642 	/* EAPD */
1643 	else if (target == MI_TARGET_EAPD) {
1644 		err = azalia_comresp(this, nid, CORB_GET_EAPD_BTL_ENABLE,
1645 		    0, &result);
1646 		if (err)
1647 			return err;
1648 		mc->un.ord = result & CORB_EAPD_EAPD ? 1 : 0;
1649 	}
1650 
1651 	/* sense pin */
1652 	else if (target == MI_TARGET_PINSENSE) {
1653 		err = azalia_comresp(this, nid, CORB_GET_PIN_SENSE,
1654 		    0, &result);
1655 		if (err)
1656 			return err;
1657 		mc->un.ord = result & CORB_PS_PRESENCE ? 1 : 0;
1658 	}
1659 
1660 	/* mute set */
1661 	else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) {
1662 		const widget_t *w;
1663 
1664 		if (!azalia_widget_enabled(this, nid)) {
1665 			DPRINTF(("%s: invalid muteset nid\n"));
1666 			return EINVAL;
1667 		}
1668 		w = &this->w[nid];
1669 		mc->un.mask = 0;
1670 		for (i = 0; i < w->nconnections; i++) {
1671 			if (!azalia_widget_enabled(this, w->connections[i]))
1672 				continue;
1673 			err = azalia_comresp(this, nid,
1674 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1675 			    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1676 			    MI_TARGET_INAMP(i), &result);
1677 			if (err)
1678 				return err;
1679 			mc->un.mask |= (result & CORB_GAGM_MUTE) ? 0 : (1 << i);
1680 		}
1681 	}
1682 
1683 	/* mixer set - show all connections */
1684 	else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) {
1685 		const widget_t *w;
1686 
1687 		if (!azalia_widget_enabled(this, nid)) {
1688 			DPRINTF(("%s: invalid mixerset nid\n"));
1689 			return EINVAL;
1690 		}
1691 		w = &this->w[nid];
1692 		mc->un.mask = 0;
1693 		for (i = 0; i < w->nconnections; i++) {
1694 			if (!azalia_widget_enabled(this, w->connections[i]))
1695 				continue;
1696 			mc->un.mask |= (1 << i);
1697 		}
1698 	}
1699 
1700 	else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
1701 
1702 		if (nid == this->speaker) {
1703 			mc->un.mask = this->spkr_muters;
1704 		} else {
1705 			DPRINTF(("%s: invalid senseset nid\n"));
1706 			return EINVAL;
1707 		}
1708 	}
1709 
1710 	else if (target == MI_TARGET_PLAYVOL) {
1711 
1712 		if (mc->type == AUDIO_MIXER_VALUE) {
1713 			mc->un.value.num_channels = 2;
1714 			mc->un.value.level[0] = this->playvols.vol_l;
1715 			mc->un.value.level[1] = this->playvols.vol_r;
1716 
1717 		} else if (mc->type == AUDIO_MIXER_ENUM) {
1718 			mc->un.ord = this->playvols.mute;
1719 
1720 		} else if (mc->type == AUDIO_MIXER_SET) {
1721 			mc->un.mask = this->playvols.cur;
1722 
1723 		} else {
1724 			DPRINTF(("%s: invalid outmaster mixer type\n"));
1725 			return EINVAL;
1726 		}
1727 	}
1728 
1729 	else if (target == MI_TARGET_RECVOL) {
1730 
1731 		if (mc->type == AUDIO_MIXER_VALUE) {
1732 			mc->un.value.num_channels = 2;
1733 			mc->un.value.level[0] = this->recvols.vol_l;
1734 			mc->un.value.level[1] = this->recvols.vol_r;
1735 
1736 		} else if (mc->type == AUDIO_MIXER_ENUM) {
1737 			mc->un.ord = this->recvols.mute;
1738 
1739 		} else if (mc->type == AUDIO_MIXER_SET) {
1740 			mc->un.mask = this->recvols.cur;
1741 
1742 		} else {
1743 			DPRINTF(("%s: invalid inmaster mixer type\n"));
1744 			return EINVAL;
1745 		}
1746 	}
1747 
1748 	else {
1749 		DPRINTF(("%s: internal error in %s: target=%x\n",
1750 		    XNAME(this), __func__, target));
1751 		return -1;
1752 	}
1753 	return 0;
1754 }
1755 
1756 int
1757 azalia_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc)
1758 {
1759 	uint32_t result, value;
1760 	int i, err;
1761 
1762 	if (mc->type == AUDIO_MIXER_CLASS) {
1763 		return(0);
1764 	}
1765 
1766 	/* inamp mute */
1767 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_ENUM) {
1768 		/* set stereo mute separately to keep each gain value */
1769 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1770 		    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1771 		    MI_TARGET_INAMP(target), &result);
1772 		if (err)
1773 			return err;
1774 		value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1775 		    (target << CORB_AGM_INDEX_SHIFT) |
1776 		    CORB_GAGM_GAIN(result);
1777 		if (mc->un.ord)
1778 			value |= CORB_AGM_MUTE;
1779 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1780 		    value, &result);
1781 		if (err)
1782 			return err;
1783 		if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1784 			err = azalia_comresp(this, nid,
1785 			    CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1786 			    CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1787 			    &result);
1788 			if (err)
1789 				return err;
1790 			value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1791 			    (target << CORB_AGM_INDEX_SHIFT) |
1792 			    CORB_GAGM_GAIN(result);
1793 			if (mc->un.ord)
1794 				value |= CORB_AGM_MUTE;
1795 			err = azalia_comresp(this, nid,
1796 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1797 			if (err)
1798 				return err;
1799 		}
1800 	}
1801 
1802 	/* inamp gain */
1803 	else if (IS_MI_TARGET_INAMP(target) && mc->type == AUDIO_MIXER_VALUE) {
1804 		if (mc->un.value.num_channels < 1)
1805 			return EINVAL;
1806 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1807 		      CORB_GAGM_INPUT | CORB_GAGM_LEFT |
1808 		      MI_TARGET_INAMP(target), &result);
1809 		if (err)
1810 			return err;
1811 		value = azalia_mixer_to_device_value(this, nid, target,
1812 		    mc->un.value.level[0]);
1813 		value = CORB_AGM_INPUT | CORB_AGM_LEFT |
1814 		    (target << CORB_AGM_INDEX_SHIFT) |
1815 		    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1816 		    (value & CORB_AGM_GAIN_MASK);
1817 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1818 		    value, &result);
1819 		if (err)
1820 			return err;
1821 		if (mc->un.value.num_channels >= 2 &&
1822 		    WIDGET_CHANNELS(&this->w[nid]) == 2) {
1823 			err = azalia_comresp(this, nid,
1824 			      CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_INPUT |
1825 			      CORB_GAGM_RIGHT | MI_TARGET_INAMP(target),
1826 			      &result);
1827 			if (err)
1828 				return err;
1829 			value = azalia_mixer_to_device_value(this, nid, target,
1830 			    mc->un.value.level[1]);
1831 			value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
1832 			    (target << CORB_AGM_INDEX_SHIFT) |
1833 			    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1834 			    (value & CORB_AGM_GAIN_MASK);
1835 			err = azalia_comresp(this, nid,
1836 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1837 			if (err)
1838 				return err;
1839 		}
1840 	}
1841 
1842 	/* outamp mute */
1843 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
1844 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1845 		    CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1846 		if (err)
1847 			return err;
1848 		value = CORB_AGM_OUTPUT | CORB_AGM_LEFT | CORB_GAGM_GAIN(result);
1849 		if (mc->un.ord)
1850 			value |= CORB_AGM_MUTE;
1851 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1852 		    value, &result);
1853 		if (err)
1854 			return err;
1855 		if (WIDGET_CHANNELS(&this->w[nid]) == 2) {
1856 			err = azalia_comresp(this, nid,
1857 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
1858 			    CORB_GAGM_OUTPUT | CORB_GAGM_RIGHT, &result);
1859 			if (err)
1860 				return err;
1861 			value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1862 			    CORB_GAGM_GAIN(result);
1863 			if (mc->un.ord)
1864 				value |= CORB_AGM_MUTE;
1865 			err = azalia_comresp(this, nid,
1866 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1867 			if (err)
1868 				return err;
1869 		}
1870 	}
1871 
1872 	/* outamp gain */
1873 	else if (target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_VALUE) {
1874 		if (mc->un.value.num_channels < 1)
1875 			return EINVAL;
1876 		err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE,
1877 		      CORB_GAGM_OUTPUT | CORB_GAGM_LEFT, &result);
1878 		if (err)
1879 			return err;
1880 		value = azalia_mixer_to_device_value(this, nid, target,
1881 		    mc->un.value.level[0]);
1882 		value = CORB_AGM_OUTPUT | CORB_AGM_LEFT |
1883 		    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1884 		    (value & CORB_AGM_GAIN_MASK);
1885 		err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE,
1886 		    value, &result);
1887 		if (err)
1888 			return err;
1889 		if (mc->un.value.num_channels >= 2 &&
1890 		    WIDGET_CHANNELS(&this->w[nid]) == 2) {
1891 			err = azalia_comresp(this, nid,
1892 			      CORB_GET_AMPLIFIER_GAIN_MUTE, CORB_GAGM_OUTPUT |
1893 			      CORB_GAGM_RIGHT, &result);
1894 			if (err)
1895 				return err;
1896 			value = azalia_mixer_to_device_value(this, nid, target,
1897 			    mc->un.value.level[1]);
1898 			value = CORB_AGM_OUTPUT | CORB_AGM_RIGHT |
1899 			    (result & CORB_GAGM_MUTE ? CORB_AGM_MUTE : 0) |
1900 			    (value & CORB_AGM_GAIN_MASK);
1901 			err = azalia_comresp(this, nid,
1902 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
1903 			if (err)
1904 				return err;
1905 		}
1906 	}
1907 
1908 	/* selection */
1909 	else if (target == MI_TARGET_CONNLIST) {
1910 		if (mc->un.ord < 0 ||
1911 		    mc->un.ord >= this->w[nid].nconnections ||
1912 		    !azalia_widget_enabled(this,
1913 		    this->w[nid].connections[mc->un.ord]))
1914 			return EINVAL;
1915 		err = azalia_comresp(this, nid,
1916 		    CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
1917 		if (err)
1918 			return err;
1919 	}
1920 
1921 	/* pin I/O */
1922 	else if (target == MI_TARGET_PINDIR) {
1923 
1924 		err = azalia_comresp(this, nid,
1925 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1926 		if (err)
1927 			return err;
1928 
1929 		value = result;
1930 		value &= ~(CORB_PWC_VREF_MASK);
1931 		if (mc->un.ord == 0) {
1932 			value &= ~(CORB_PWC_OUTPUT | CORB_PWC_INPUT);
1933 		} else if (mc->un.ord == 1) {
1934 			value &= ~CORB_PWC_INPUT;
1935 			value |= CORB_PWC_OUTPUT;
1936 			if (this->qrks & AZ_QRK_WID_OVREF50)
1937 				value |= CORB_PWC_VREF_50;
1938 		} else {
1939 			value &= ~CORB_PWC_OUTPUT;
1940 			value |= CORB_PWC_INPUT;
1941 
1942 			if (mc->un.ord == 3)
1943 				value |= CORB_PWC_VREF_GND;
1944 			if (mc->un.ord == 4)
1945 				value |= CORB_PWC_VREF_50;
1946 			if (mc->un.ord == 5)
1947 				value |= CORB_PWC_VREF_80;
1948 			if (mc->un.ord == 6)
1949 				value |= CORB_PWC_VREF_100;
1950 		}
1951 		err = azalia_comresp(this, nid,
1952 		    CORB_SET_PIN_WIDGET_CONTROL, value, &result);
1953 		if (err)
1954 			return err;
1955 
1956 		/* Run the unsolicited response handler for speaker mute
1957 		 * since it depends on pin direction.
1958 		 */
1959 		for (i = 0; i < this->nsense_pins; i++) {
1960 			if (this->sense_pins[i] == nid)
1961 				break;
1962 		}
1963 		if (i < this->nsense_pins) {
1964 			azalia_unsol_event(this, AZ_TAG_SPKR);
1965 		}
1966 	}
1967 
1968 	/* pin headphone-boost */
1969 	else if (target == MI_TARGET_PINBOOST) {
1970 		if (mc->un.ord >= 2)
1971 			return EINVAL;
1972 		err = azalia_comresp(this, nid,
1973 		    CORB_GET_PIN_WIDGET_CONTROL, 0, &result);
1974 		if (err)
1975 			return err;
1976 		if (mc->un.ord == 0) {
1977 			result &= ~CORB_PWC_HEADPHONE;
1978 		} else {
1979 			result |= CORB_PWC_HEADPHONE;
1980 		}
1981 		err = azalia_comresp(this, nid,
1982 		    CORB_SET_PIN_WIDGET_CONTROL, result, &result);
1983 		if (err)
1984 			return err;
1985 	}
1986 
1987 	/* DAC group selection */
1988 	else if (target == MI_TARGET_DAC) {
1989 		if (this->running)
1990 			return EBUSY;
1991 		if (mc->un.ord >= this->dacs.ngroups)
1992 			return EINVAL;
1993 		if (mc->un.ord != this->dacs.cur)
1994 			return azalia_codec_construct_format(this,
1995 			    mc->un.ord, this->adcs.cur);
1996 		else
1997 			return 0;
1998 	}
1999 
2000 	/* ADC selection */
2001 	else if (target == MI_TARGET_ADC) {
2002 		if (this->running)
2003 			return EBUSY;
2004 		if (mc->un.ord >= this->adcs.ngroups)
2005 			return EINVAL;
2006 		if (mc->un.ord != this->adcs.cur)
2007 			return azalia_codec_construct_format(this,
2008 			    this->dacs.cur, mc->un.ord);
2009 		else
2010 			return 0;
2011 	}
2012 
2013 	/* S/PDIF */
2014 	else if (target == MI_TARGET_SPDIF) {
2015 		err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL,
2016 		    0, &result);
2017 		result &= CORB_DCC_DIGEN | CORB_DCC_NAUDIO;
2018 		result |= mc->un.mask & 0xff & ~CORB_DCC_DIGEN;
2019 		err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L,
2020 		    result, NULL);
2021 		if (err)
2022 			return err;
2023 	} else if (target == MI_TARGET_SPDIF_CC) {
2024 		if (mc->un.value.num_channels != 1)
2025 			return EINVAL;
2026 		if (mc->un.value.level[0] > 127)
2027 			return EINVAL;
2028 		err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_H,
2029 		    mc->un.value.level[0], NULL);
2030 		if (err)
2031 			return err;
2032 	}
2033 
2034 	/* EAPD */
2035 	else if (target == MI_TARGET_EAPD) {
2036 		if (mc->un.ord >= 2)
2037 			return EINVAL;
2038 		err = azalia_comresp(this, nid,
2039 		    CORB_GET_EAPD_BTL_ENABLE, 0, &result);
2040 		if (err)
2041 			return err;
2042 		result &= 0xff;
2043 		if (mc->un.ord == 0) {
2044 			result &= ~CORB_EAPD_EAPD;
2045 		} else {
2046 			result |= CORB_EAPD_EAPD;
2047 		}
2048 		err = azalia_comresp(this, nid,
2049 		    CORB_SET_EAPD_BTL_ENABLE, result, &result);
2050 		if (err)
2051 			return err;
2052 	}
2053 
2054 	else if (target == MI_TARGET_PINSENSE) {
2055 		/* do nothing, control is read only */
2056 	}
2057 
2058 	else if (target == MI_TARGET_MUTESET && mc->type == AUDIO_MIXER_SET) {
2059 		const widget_t *w;
2060 
2061 		if (!azalia_widget_enabled(this, nid)) {
2062 			DPRINTF(("%s: invalid muteset nid\n"));
2063 			return EINVAL;
2064 		}
2065 		w = &this->w[nid];
2066 		for (i = 0; i < w->nconnections; i++) {
2067 			if (!azalia_widget_enabled(this, w->connections[i]))
2068 				continue;
2069 
2070 			/* We have to set stereo mute separately
2071 			 * to keep each gain value.
2072 			 */
2073 			err = azalia_comresp(this, nid,
2074 			    CORB_GET_AMPLIFIER_GAIN_MUTE,
2075 			    CORB_GAGM_INPUT | CORB_GAGM_LEFT |
2076 			    MI_TARGET_INAMP(i), &result);
2077 			if (err)
2078 				return err;
2079 			value = CORB_AGM_INPUT | CORB_AGM_LEFT |
2080 			    (i << CORB_AGM_INDEX_SHIFT) |
2081 			    CORB_GAGM_GAIN(result);
2082 			if ((mc->un.mask & (1 << i)) == 0)
2083 				value |= CORB_AGM_MUTE;
2084 			err = azalia_comresp(this, nid,
2085 			    CORB_SET_AMPLIFIER_GAIN_MUTE, value, &result);
2086 			if (err)
2087 				return err;
2088 
2089 			if (WIDGET_CHANNELS(w) == 2) {
2090 				err = azalia_comresp(this, nid,
2091 				    CORB_GET_AMPLIFIER_GAIN_MUTE,
2092 				    CORB_GAGM_INPUT | CORB_GAGM_RIGHT |
2093 				    MI_TARGET_INAMP(i), &result);
2094 				if (err)
2095 					return err;
2096 				value = CORB_AGM_INPUT | CORB_AGM_RIGHT |
2097 				    (i << CORB_AGM_INDEX_SHIFT) |
2098 				    CORB_GAGM_GAIN(result);
2099 				if ((mc->un.mask & (1 << i)) == 0)
2100 					value |= CORB_AGM_MUTE;
2101 				err = azalia_comresp(this, nid,
2102 				    CORB_SET_AMPLIFIER_GAIN_MUTE,
2103 				    value, &result);
2104 				if (err)
2105 					return err;
2106 			}
2107 		}
2108 	}
2109 
2110 	else if (target == MI_TARGET_MIXERSET && mc->type == AUDIO_MIXER_SET) {
2111 		/* do nothing, control is read only */
2112 	}
2113 
2114 	else if (target == MI_TARGET_SENSESET && mc->type == AUDIO_MIXER_SET) {
2115 
2116 		if (nid == this->speaker) {
2117 			this->spkr_muters = mc->un.mask;
2118 			azalia_unsol_event(this, AZ_TAG_SPKR);
2119 		} else {
2120 			DPRINTF(("%s: invalid senseset nid\n"));
2121 			return EINVAL;
2122 		}
2123 	}
2124 
2125 	else if (target == MI_TARGET_PLAYVOL) {
2126 
2127 		const widget_t *w;
2128 		mixer_ctrl_t mc2;
2129 
2130 		if (mc->type == AUDIO_MIXER_VALUE) {
2131 			if (mc->un.value.num_channels != 2)
2132 				return EINVAL;
2133 			this->playvols.vol_l = mc->un.value.level[0];
2134 			this->playvols.vol_r = mc->un.value.level[1];
2135 			for (i = 0; i < this->playvols.nslaves; i++) {
2136 				if (!(this->playvols.cur & (1 << i)))
2137 					continue;
2138 				w = &this->w[this->playvols.slaves[i]];
2139 				if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)))
2140 					continue;
2141 
2142 				/* don't change volume if muted */
2143 				if (w->outamp_cap & COP_AMPCAP_MUTE) {
2144 					mc2.type = AUDIO_MIXER_ENUM;
2145 					azalia_mixer_get(this, w->nid,
2146 					    MI_TARGET_OUTAMP, &mc2);
2147 					if (mc2.un.ord)
2148 						continue;
2149 				}
2150 				mc2.type = AUDIO_MIXER_VALUE;
2151 				mc2.un.value.num_channels = WIDGET_CHANNELS(w);
2152 				mc2.un.value.level[0] = this->playvols.vol_l;
2153 				mc2.un.value.level[1] = this->playvols.vol_r;
2154 				err = azalia_mixer_set(this, w->nid,
2155 				    MI_TARGET_OUTAMP, &mc2);
2156 				if (err) {
2157 					DPRINTF(("%s: out slave %2.2x vol\n",
2158 					    __func__, w->nid));
2159 					return err;
2160 				}
2161 			}
2162 		} else if (mc->type == AUDIO_MIXER_ENUM) {
2163 			if (mc->un.ord != 0 && mc->un.ord != 1)
2164 				return EINVAL;
2165 			this->playvols.mute = mc->un.ord;
2166 			for (i = 0; i < this->playvols.nslaves; i++) {
2167 				if (!(this->playvols.cur & (1 << i)))
2168 					continue;
2169 				w = &this->w[this->playvols.slaves[i]];
2170 				if (!(w->outamp_cap & COP_AMPCAP_MUTE))
2171 					continue;
2172 				if (this->spkr_muted == 1 &&
2173 				    ((this->spkr_mute_method ==
2174 				    AZ_SPKR_MUTE_SPKR_MUTE &&
2175 				    (w->nid == this->speaker ||
2176 				    w->nid == this->speaker2)) ||
2177 				    (this->spkr_mute_method ==
2178 				    AZ_SPKR_MUTE_DAC_MUTE &&
2179 				    w->nid == this->spkr_dac))) {
2180 					continue;
2181 				}
2182 				mc2.type = AUDIO_MIXER_ENUM;
2183 				mc2.un.ord = this->playvols.mute;
2184 				err = azalia_mixer_set(this, w->nid,
2185 				    MI_TARGET_OUTAMP, &mc2);
2186 				if (err) {
2187 					DPRINTF(("%s: out slave %2.2x mute\n",
2188 					    __func__, w->nid));
2189 					return err;
2190 				}
2191 			}
2192 
2193 		} else if (mc->type == AUDIO_MIXER_SET) {
2194 			this->playvols.cur =
2195 			    (mc->un.mask & this->playvols.mask);
2196 
2197 		} else {
2198 			DPRINTF(("%s: invalid output master mixer type\n"));
2199 			return EINVAL;
2200 		}
2201 	}
2202 
2203 	else if (target == MI_TARGET_RECVOL) {
2204 
2205 		const widget_t *w;
2206 		mixer_ctrl_t mc2;
2207 		uint32_t cap;
2208 		int tgt;
2209 
2210 		if (mc->type == AUDIO_MIXER_VALUE) {
2211 			if (mc->un.value.num_channels != 2)
2212 				return EINVAL;
2213 			this->recvols.vol_l = mc->un.value.level[0];
2214 			this->recvols.vol_r = mc->un.value.level[1];
2215 			for (i = 0; i < this->recvols.nslaves; i++) {
2216 				if (!(this->recvols.cur & (1 << i)))
2217 					continue;
2218 				w = &this->w[this->recvols.slaves[i]];
2219 				tgt = MI_TARGET_OUTAMP;
2220 				cap = w->outamp_cap;
2221 				if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2222 				    w->type == COP_AWTYPE_PIN_COMPLEX) {
2223 					tgt = 0;
2224 					cap = w->inamp_cap;
2225 				}
2226 				if (!(COP_AMPCAP_NUMSTEPS(cap)))
2227 					continue;
2228 				mc2.type = AUDIO_MIXER_VALUE;
2229 				mc2.un.value.num_channels = WIDGET_CHANNELS(w);
2230 				mc2.un.value.level[0] = this->recvols.vol_l;
2231 				mc2.un.value.level[1] = this->recvols.vol_r;
2232 				err = azalia_mixer_set(this, w->nid,
2233 				    tgt, &mc2);
2234 				if (err) {
2235 					DPRINTF(("%s: in slave %2.2x vol\n",
2236 					    __func__, w->nid));
2237 					return err;
2238 				}
2239 			}
2240 		} else if (mc->type == AUDIO_MIXER_ENUM) {
2241 			if (mc->un.ord != 0 && mc->un.ord != 1)
2242 				return EINVAL;
2243 			this->recvols.mute = mc->un.ord;
2244 			for (i = 0; i < this->recvols.nslaves; i++) {
2245 				if (!(this->recvols.cur & (1 << i)))
2246 					continue;
2247 				w = &this->w[this->recvols.slaves[i]];
2248 				tgt = MI_TARGET_OUTAMP;
2249 				cap = w->outamp_cap;
2250 				if (w->type == COP_AWTYPE_AUDIO_INPUT ||
2251 				    w->type == COP_AWTYPE_PIN_COMPLEX) {
2252 					tgt = 0;
2253 					cap = w->inamp_cap;
2254 				}
2255 				if (!(cap & COP_AMPCAP_MUTE))
2256 					continue;
2257 				mc2.type = AUDIO_MIXER_ENUM;
2258 				mc2.un.ord = this->recvols.mute;
2259 				err = azalia_mixer_set(this, w->nid,
2260 				    tgt, &mc2);
2261 				if (err) {
2262 					DPRINTF(("%s: out slave %2.2x mute\n",
2263 					    __func__, w->nid));
2264 					return err;
2265 				}
2266 			}
2267 
2268 		} else if (mc->type == AUDIO_MIXER_SET) {
2269 			this->recvols.cur = (mc->un.mask & this->recvols.mask);
2270 
2271 		} else {
2272 			DPRINTF(("%s: invalid input master mixer type\n"));
2273 			return EINVAL;
2274 		}
2275 	}
2276 
2277 	else {
2278 		DPRINTF(("%s: internal error in %s: target=%x\n",
2279 		    XNAME(this), __func__, target));
2280 		return -1;
2281 	}
2282 	return 0;
2283 }
2284 
2285 u_char
2286 azalia_mixer_from_device_value(const codec_t *this, nid_t nid, int target,
2287     uint32_t dv)
2288 {
2289 	uint32_t steps;
2290 	int max_gain, ctloff;
2291 
2292 	if (IS_MI_TARGET_INAMP(target)) {
2293 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
2294 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap);
2295 	} else if (target == MI_TARGET_OUTAMP) {
2296 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
2297 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap);
2298 	} else {
2299 		DPRINTF(("%s: unknown target: %d\n", __func__, target));
2300 		steps = 255;
2301 	}
2302 	dv -= ctloff;
2303 	if (dv <= 0 || steps == 0)
2304 		return(AUDIO_MIN_GAIN);
2305 	max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps;
2306 	if (dv >= steps)
2307 		return(max_gain);
2308 	return(dv * max_gain / steps);
2309 }
2310 
2311 uint32_t
2312 azalia_mixer_to_device_value(const codec_t *this, nid_t nid, int target,
2313     u_char uv)
2314 {
2315 	uint32_t steps;
2316 	int max_gain, ctloff;
2317 
2318 	if (IS_MI_TARGET_INAMP(target)) {
2319 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap);
2320 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap);
2321 	} else if (target == MI_TARGET_OUTAMP) {
2322 		steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap);
2323 		ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap);
2324 	} else {
2325 		DPRINTF(("%s: unknown target: %d\n", __func__, target));
2326 		steps = 255;
2327 	}
2328 	if (uv <= AUDIO_MIN_GAIN || steps == 0)
2329 		return(ctloff);
2330 	max_gain = AUDIO_MAX_GAIN - AUDIO_MAX_GAIN % steps;
2331 	if (uv >= max_gain)
2332 		return(steps + ctloff);
2333 	return(uv * steps / max_gain + ctloff);
2334 }
2335 
2336 int
2337 azalia_gpio_unmute(codec_t *this, int pin)
2338 {
2339 	uint32_t data, mask, dir;
2340 
2341 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DATA, 0, &data);
2342 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK, 0, &mask);
2343 	azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION, 0, &dir);
2344 
2345 	data |= 1 << pin;
2346 	mask |= 1 << pin;
2347 	dir |= 1 << pin;
2348 
2349 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK, mask, NULL);
2350 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION, dir, NULL);
2351 	DELAY(1000);
2352 	azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DATA, data, NULL);
2353 
2354 	return 0;
2355 }
2356 
2357 void
2358 azalia_ampcap_ov(widget_t *w, int type, int offset, int steps, int size,
2359    int ctloff, int mute)
2360 {
2361 	uint32_t cap;
2362 
2363 	cap = (offset & 0x7f) | ((steps & 0x7f) << 8) |
2364 	    ((size & 0x7f) << 16) | ((ctloff & 0x7f) << 24) |
2365 	    (mute ? COP_AMPCAP_MUTE : 0);
2366 
2367 	if (type == COP_OUTPUT_AMPCAP) {
2368 		w->outamp_cap = cap;
2369 	} else if (type == COP_INPUT_AMPCAP) {
2370 		w->inamp_cap = cap;
2371 	}
2372 }
2373 
2374 void
2375 azalia_pin_config_ov(widget_t *w, int mask, int val)
2376 {
2377 	int bits, offset;
2378 
2379 	switch (mask) {
2380 	case CORB_CD_DEVICE_MASK:
2381 		bits = CORB_CD_DEVICE_BITS;
2382 		offset = CORB_CD_DEVICE_OFFSET;
2383 		break;
2384 	case CORB_CD_PORT_MASK:
2385 		bits = CORB_CD_PORT_BITS;
2386 		offset = CORB_CD_PORT_OFFSET;
2387 		break;
2388 	default:
2389 		return;
2390 	}
2391 	val &= bits;
2392 	w->d.pin.config &= ~(mask);
2393 	w->d.pin.config |= val << offset;
2394 	if (mask == CORB_CD_DEVICE_MASK)
2395 		w->d.pin.device = val;
2396 }
2397 
2398 int
2399 azalia_codec_gpio_quirks(codec_t *this)
2400 {
2401 	if (this->qrks & AZ_QRK_GPIO_POL_0) {
2402 		azalia_comresp(this, this->audiofunc,
2403 		    CORB_SET_GPIO_POLARITY, 0, NULL);
2404 	}
2405 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_0) {
2406 		azalia_gpio_unmute(this, 0);
2407 	}
2408 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_1) {
2409 		azalia_gpio_unmute(this, 1);
2410 	}
2411 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_2) {
2412 		azalia_gpio_unmute(this, 2);
2413 	}
2414 	if (this->qrks & AZ_QRK_GPIO_UNMUTE_3) {
2415 		azalia_gpio_unmute(this, 3);
2416 	}
2417 
2418 	return(0);
2419 }
2420 
2421 int
2422 azalia_codec_widget_quirks(codec_t *this, nid_t nid)
2423 {
2424 	widget_t *w;
2425 
2426 	w = &this->w[nid];
2427 
2428 	if (this->qrks & AZ_QRK_WID_BEEP_1D &&
2429 	    nid == 0x1d && w->enable == 0) {
2430 		azalia_pin_config_ov(w, CORB_CD_DEVICE_MASK, CORB_CD_BEEP);
2431 		azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED);
2432 		w->widgetcap |= COP_AWCAP_STEREO;
2433 		w->enable = 1;
2434 	}
2435 
2436 	if (this->qrks & AZ_QRK_WID_CDIN_1C &&
2437 	    nid == 0x1c && w->enable == 0 && w->d.pin.device == CORB_CD_CD) {
2438 		azalia_pin_config_ov(w, CORB_CD_PORT_MASK, CORB_CD_FIXED);
2439 		w->widgetcap |= COP_AWCAP_STEREO;
2440 		w->enable = 1;
2441 	}
2442 
2443 	if ((this->qrks & AZ_QRK_WID_AD1981_OAMP) &&
2444 	    ((nid == 0x05) || (nid == 0x06) || (nid == 0x07) ||
2445 	    (nid == 0x09) || (nid == 0x18))) {
2446 		azalia_ampcap_ov(w, COP_OUTPUT_AMPCAP, 31, 33, 6, 30, 1);
2447 	}
2448 
2449 	return(0);
2450 }
2451