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