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