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