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