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