1 /* $NetBSD: azalia_codec.c,v 1.76 2009/02/28 17:12:13 jmcneill Exp $ */
4 * Copyright (c) 2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.76 2009/02/28 17:12:13 jmcneill Exp $");
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/malloc.h>
39 #include <sys/systm.h>
40 #include <dev/pci/azalia.h>
43 # define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n))
45 # define MIXER_DELTA(n) (1)
47 #define AZ_CLASS_INPUT 0
48 #define AZ_CLASS_OUTPUT 1
49 #define AZ_CLASS_RECORD 2
50 #define AZ_CLASS_PLAYBACK 3
51 #define AZ_CLASS_MIXER 4
52 #define AzaliaCplayback "playback"
53 #define AzaliaCmixer "mix"
54 #define AzaliaNfront "front"
55 #define AzaliaNclfe "clfe"
56 #define AzaliaNside "side"
57 #define AzaliaNdigital "spdif"
58 #define ENUM_OFFON .un.e={2, {{{AudioNoff, 0}, 0}, {{AudioNon, 0}, 1}}}
59 #define ENUM_IO .un.e={2, {{{AudioNinput, 0}, 0}, {{AudioNoutput, 0}, 1}}}
60 #define ENUM_V .un.v={{ "", 0 }, 0, 0 }
61 #define AZ_MIXER_CLASSES \
62 {{AZ_CLASS_INPUT, {AudioCinputs, 0}, AUDIO_MIXER_CLASS, \
63 AZ_CLASS_INPUT, 0, 0, ENUM_V }, 0, 0, }, \
64 {{AZ_CLASS_OUTPUT, {AudioCoutputs, 0}, AUDIO_MIXER_CLASS, \
65 AZ_CLASS_OUTPUT, 0, 0, ENUM_V }, 0, 0, }, \
66 {{AZ_CLASS_RECORD, {AudioCrecord, 0}, AUDIO_MIXER_CLASS, \
67 AZ_CLASS_RECORD, 0, 0, ENUM_V }, 0, 0, }, \
68 {{AZ_CLASS_PLAYBACK, {AzaliaCplayback, 0}, AUDIO_MIXER_CLASS, \
69 AZ_CLASS_PLAYBACK, 0, 0, ENUM_V }, 0, 0, }, \
70 {{AZ_CLASS_MIXER, {AzaliaCmixer, 0}, AUDIO_MIXER_CLASS, \
71 AZ_CLASS_MIXER, 0, 0, ENUM_V }, 0, 0, }
72 #define AZ_MIXER_SPDIF(cl, nid) \
73 {{0, {AzaliaNdigital, 0}, AUDIO_MIXER_SET, cl, 0, 0, \
74 .un.s={6, {{{"v", 0}, CORB_DCC_V}, {{"vcfg", 0}, CORB_DCC_VCFG}, \
75 {{"pre", 0}, CORB_DCC_PRE}, {{"copy", 0}, CORB_DCC_COPY}, \
76 {{"pro", 0}, CORB_DCC_PRO}, {{"l", 0}, CORB_DCC_L}}}}, \
77 nid, MI_TARGET_SPDIF}, \
78 {{0, {AzaliaNdigital".cc", 0}, AUDIO_MIXER_VALUE, cl, 0, 0, \
79 .un.v={{"", 0}, 1, 1}}, nid, MI_TARGET_SPDIF_CC}
82 static int generic_codec_init_dacgroup(codec_t
*);
83 static int generic_codec_add_dacgroup(codec_t
*, int, uint32_t);
84 static int generic_codec_find_pin(const codec_t
*, int, int, uint32_t);
85 static int generic_codec_find_dac(const codec_t
*, int, int);
87 static int generic_mixer_init(codec_t
*);
88 static int generic_mixer_autoinit(codec_t
*);
89 static int generic_mixer_init_widget(const codec_t
*, widget_t
*, nid_t
);
91 static int generic_mixer_fix_indexes(codec_t
*);
92 static int generic_mixer_default(codec_t
*);
93 static int generic_mixer_pin_sense(codec_t
*);
94 static int generic_mixer_widget_name(const codec_t
*, widget_t
*);
95 static int generic_mixer_create_virtual(codec_t
*);
96 static int generic_mixer_delete(codec_t
*);
97 static void generic_mixer_cat_names
98 (char *, size_t, const char *, const char *, const char *);
99 static int generic_mixer_ensure_capacity(codec_t
*, size_t);
100 static int generic_mixer_get(const codec_t
*, nid_t
, int, mixer_ctrl_t
*);
101 static int generic_mixer_set(codec_t
*, nid_t
, int, const mixer_ctrl_t
*);
102 static int generic_mixer_pinctrl(codec_t
*, nid_t
, uint32_t);
103 static u_char generic_mixer_from_device_value
104 (const codec_t
*, nid_t
, int, uint32_t );
105 static uint32_t generic_mixer_to_device_value
106 (const codec_t
*, nid_t
, int, u_char
);
107 static uint32_t generic_mixer_max(const codec_t
*, nid_t
, int);
108 static bool generic_mixer_validate_value
109 (const codec_t
*, nid_t
, int, u_char
);
110 static int generic_set_port(codec_t
*, mixer_ctrl_t
*);
111 static int generic_get_port(codec_t
*, mixer_ctrl_t
*);
113 static int alc260_init_dacgroup(codec_t
*);
114 static int alc260_mixer_init(codec_t
*);
115 static int alc260_set_port(codec_t
*, mixer_ctrl_t
*);
116 static int alc260_get_port(codec_t
*, mixer_ctrl_t
*);
117 static int alc260_unsol_event(codec_t
*, int);
118 static int alc262_init_widget(const codec_t
*, widget_t
*, nid_t
);
119 static int alc268_init_dacgroup(codec_t
*);
120 static int alc662_init_dacgroup(codec_t
*);
121 static int alc861_init_dacgroup(codec_t
*);
122 static int alc861vdgr_init_dacgroup(codec_t
*);
123 static int alc880_init_dacgroup(codec_t
*);
124 static int alc880_mixer_init(codec_t
*);
125 static int alc882_init_dacgroup(codec_t
*);
126 static int alc882_mixer_init(codec_t
*);
127 static int alc882_set_port(codec_t
*, mixer_ctrl_t
*);
128 static int alc882_get_port(codec_t
*, mixer_ctrl_t
*);
129 static int alc883_init_dacgroup(codec_t
*);
130 static int alc883_mixer_init(codec_t
*);
131 static int alc885_init_dacgroup(codec_t
*);
132 static int alc888_init_dacgroup(codec_t
*);
133 static int alc888_init_widget(const codec_t
*, widget_t
*, nid_t
);
134 static int alc888_mixer_init(codec_t
*);
135 static int ad1981hd_init_widget(const codec_t
*, widget_t
*, nid_t
);
136 static int ad1981hd_mixer_init(codec_t
*);
137 static int ad1983_mixer_init(codec_t
*);
138 static int ad1983_unsol_event(codec_t
*, int);
139 static int ad1984_init_dacgroup(codec_t
*);
140 static int ad1984_init_widget(const codec_t
*, widget_t
*, nid_t
);
141 static int ad1984_mixer_init(codec_t
*);
142 static int ad1984_unsol_event(codec_t
*, int);
143 static int ad1986a_init_dacgroup(codec_t
*);
144 static int ad1986a_mixer_init(codec_t
*);
145 static int ad1988_init_dacgroup(codec_t
*);
146 static int cmi9880_init_dacgroup(codec_t
*);
147 static int cmi9880_mixer_init(codec_t
*);
148 static int stac9221_init_dacgroup(codec_t
*);
149 static int stac9221_mixer_init(codec_t
*);
150 static int stac9221_gpio_unmute(codec_t
*, int);
151 static int stac9200_mixer_init(codec_t
*);
152 static int stac9200_unsol_event(codec_t
*, int);
153 static int atihdmi_init_dacgroup(codec_t
*);
157 azalia_codec_init_vtbl(codec_t
*this)
162 * We can refer this->vid and this->subid.
164 DPRINTF(("%s: vid=%08x subid=%08x\n", __func__
, this->vid
, this->subid
));
167 this->init_dacgroup
= generic_codec_init_dacgroup
;
168 this->mixer_init
= generic_mixer_init
;
169 this->mixer_delete
= generic_mixer_delete
;
170 this->set_port
= generic_set_port
;
171 this->get_port
= generic_get_port
;
172 this->unsol_event
= NULL
;
176 this->name
= "ATI RS600 HDMI";
177 this->init_dacgroup
= atihdmi_init_dacgroup
;
180 this->name
= "ATI RS690/780 HDMI";
181 this->init_dacgroup
= atihdmi_init_dacgroup
;
184 this->name
= "ATI R600 HDMI";
185 this->init_dacgroup
= atihdmi_init_dacgroup
;
188 this->name
= "Realtek ALC260";
189 this->mixer_init
= alc260_mixer_init
;
190 this->init_dacgroup
= alc260_init_dacgroup
;
191 this->set_port
= alc260_set_port
;
192 this->unsol_event
= alc260_unsol_event
;
196 this->name
= "Realtek ALC262";
197 this->init_widget
= alc262_init_widget
;
200 this->name
= "Realtek ALC268";
201 this->init_dacgroup
= alc268_init_dacgroup
;
202 this->mixer_init
= generic_mixer_autoinit
;
203 this->init_widget
= generic_mixer_init_widget
;
206 this->name
= "Realtek ALC269";
207 this->mixer_init
= generic_mixer_autoinit
;
208 this->init_widget
= generic_mixer_init_widget
;
211 this->name
= "Realtek ALC662-GR";
212 this->init_dacgroup
= alc662_init_dacgroup
;
213 this->mixer_init
= generic_mixer_autoinit
;
214 this->init_widget
= generic_mixer_init_widget
;
217 this->name
= "Realtek ALC663";
218 this->init_dacgroup
= alc662_init_dacgroup
;
219 this->mixer_init
= generic_mixer_autoinit
;
220 this->init_widget
= generic_mixer_init_widget
;
223 this->name
= "Realtek ALC861";
224 this->init_dacgroup
= alc861_init_dacgroup
;
227 this->name
= "Realtek ALC861-VD-GR";
228 this->init_dacgroup
= alc861vdgr_init_dacgroup
;
231 this->name
= "Realtek ALC880";
232 this->init_dacgroup
= alc880_init_dacgroup
;
233 this->mixer_init
= alc880_mixer_init
;
236 this->name
= "Realtek ALC882";
237 this->init_dacgroup
= alc882_init_dacgroup
;
238 this->mixer_init
= alc882_mixer_init
;
239 this->get_port
= alc882_get_port
;
240 this->set_port
= alc882_set_port
;
243 /* ftp://209.216.61.149/pc/audio/ALC883_DataSheet_1.3.pdf */
244 this->name
= "Realtek ALC883";
245 this->init_dacgroup
= alc883_init_dacgroup
;
246 this->mixer_init
= alc883_mixer_init
;
247 this->get_port
= alc882_get_port
;
248 this->set_port
= alc882_set_port
;
251 this->name
= "Realtek ALC885";
252 this->init_dacgroup
= alc885_init_dacgroup
;
253 this->mixer_init
= generic_mixer_autoinit
;
254 this->init_widget
= generic_mixer_init_widget
;
257 this->name
= "Realtek ALC888";
258 this->init_dacgroup
= alc888_init_dacgroup
;
259 this->init_widget
= alc888_init_widget
;
260 this->mixer_init
= alc888_mixer_init
;
263 /* http://www.analog.com/en/prod/0,2877,AD1981HD,00.html */
264 this->name
= "Analog Devices AD1981HD";
265 this->init_widget
= ad1981hd_init_widget
;
266 this->mixer_init
= ad1981hd_mixer_init
;
269 /* http://www.analog.com/en/prod/0,2877,AD1983,00.html */
270 this->name
= "Analog Devices AD1983";
271 this->mixer_init
= ad1983_mixer_init
;
272 this->unsol_event
= ad1983_unsol_event
;
275 /* http://www.analog.com/en/prod/0,2877,AD1984,00.html */
276 this->name
= "Analog Devices AD1984";
277 this->init_dacgroup
= ad1984_init_dacgroup
;
278 this->init_widget
= ad1984_init_widget
;
279 this->mixer_init
= ad1984_mixer_init
;
280 this->unsol_event
= ad1984_unsol_event
;
283 /* http://www.analog.com/static/imported-files/data_sheets/AD1984A.pdf */
284 this->name
= "Analog Devices AD1984A";
285 this->init_dacgroup
= ad1984_init_dacgroup
;
286 this->init_widget
= ad1984_init_widget
;
287 this->mixer_init
= ad1984_mixer_init
;
288 this->unsol_event
= ad1984_unsol_event
;
291 /* http://www.analog.com/en/prod/0,2877,AD1986A,00.html */
292 this->name
= "Analog Devices AD1986A";
293 this->init_dacgroup
= ad1986a_init_dacgroup
;
294 this->mixer_init
= ad1986a_mixer_init
;
297 /* http://www.analog.com/en/prod/0,2877,AD1988A,00.html */
298 this->name
= "Analog Devices AD1988A";
299 this->init_dacgroup
= ad1988_init_dacgroup
;
302 /* http://www.analog.com/en/prod/0,2877,AD1988B,00.html */
303 this->name
= "Analog Devices AD1988B";
304 this->init_dacgroup
= ad1988_init_dacgroup
;
307 this->name
= "CMedia CMI9880";
308 this->init_dacgroup
= cmi9880_init_dacgroup
;
309 this->mixer_init
= cmi9880_mixer_init
;
312 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
313 this->name
= "Sigmatel STAC9230X";
316 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
317 this->name
= "Sigmatel STAC9230D";
320 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
321 this->name
= "Sigmatel STAC9229X";
324 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
325 this->name
= "Sigmatel STAC9229D";
328 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
329 this->name
= "Sigmatel STAC9228X";
332 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
333 this->name
= "Sigmatel STAC9228D";
336 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
337 this->name
= "Sigmatel STAC9227X";
340 /* http://www.idt.com/products/getDoc.cfm?docID=17122893 */
341 this->name
= "Sigmatel STAC9227D";
344 this->name
= "Sigmatel STAC9221";
345 this->init_dacgroup
= stac9221_init_dacgroup
;
346 this->mixer_init
= stac9221_mixer_init
;
349 this->name
= "Sigmatel STAC9221D";
350 this->init_dacgroup
= stac9221_init_dacgroup
;
353 /* http://www.idt.com/products/getDoc.cfm?docID=17812077 */
354 this->name
= "Sigmatel STAC9200";
355 this->mixer_init
= stac9200_mixer_init
;
356 this->unsol_event
= stac9200_unsol_event
;
359 /* http://www.idt.com/products/getDoc.cfm?docID=17812077 */
360 this->name
= "Sigmatel STAC9200D";
361 this->mixer_init
= stac9200_mixer_init
;
362 this->unsol_event
= stac9200_unsol_event
;
365 if (extra_size
> 0) {
366 this->extra
= malloc(sizeof(uint32_t) * extra_size
,
367 M_DEVBUF
, M_ZERO
| M_NOWAIT
);
368 if (this->extra
== NULL
) {
369 aprint_error_dev(this->dev
, "Not enough memory\n");
376 /* ----------------------------------------------------------------
377 * functions for generic codecs
378 * ---------------------------------------------------------------- */
381 generic_codec_init_dacgroup(codec_t
*this)
383 int i
, j
, assoc
, group
;
387 * [0] the lowest assoc DACs
388 * [1] the lowest assoc digital outputs
389 * [2] the 2nd assoc DACs
392 this->dacs
.ngroups
= 0;
393 for (assoc
= 0; assoc
< CORB_CD_ASSOCIATION_MAX
; assoc
++) {
394 generic_codec_add_dacgroup(this, assoc
, 0);
395 generic_codec_add_dacgroup(this, assoc
, COP_AWCAP_DIGITAL
);
398 /* find DACs which do not connect with any pins by default */
399 DPRINTF(("%s: find non-connected DACs\n", __func__
));
400 FOR_EACH_WIDGET(this, i
) {
403 if (this->w
[i
].type
!= COP_AWTYPE_AUDIO_OUTPUT
)
406 for (group
= 0; group
< this->dacs
.ngroups
; group
++) {
407 for (j
= 0; j
< this->dacs
.groups
[group
].nconv
; j
++) {
408 if (i
== this->dacs
.groups
[group
].conv
[j
]) {
410 group
= this->dacs
.ngroups
;
417 if (this->dacs
.ngroups
>= 32)
419 this->dacs
.groups
[this->dacs
.ngroups
].nconv
= 1;
420 this->dacs
.groups
[this->dacs
.ngroups
].conv
[0] = i
;
421 this->dacs
.ngroups
++;
426 this->adcs
.ngroups
= 0;
427 FOR_EACH_WIDGET(this, i
) {
428 if (this->w
[i
].type
!= COP_AWTYPE_AUDIO_INPUT
)
430 this->adcs
.groups
[this->adcs
.ngroups
].nconv
= 1;
431 this->adcs
.groups
[this->adcs
.ngroups
].conv
[0] = i
;
432 this->adcs
.ngroups
++;
433 if (this->adcs
.ngroups
>= 32)
441 generic_codec_add_dacgroup(codec_t
*this, int assoc
, uint32_t digital
)
443 int i
, j
, n
, dac
, seq
;
446 for (seq
= 0 ; seq
< CORB_CD_SEQUENCE_MAX
; seq
++) {
447 i
= generic_codec_find_pin(this, assoc
, seq
, digital
);
450 dac
= generic_codec_find_dac(this, i
, 0);
453 /* duplication check */
454 for (j
= 0; j
< n
; j
++) {
455 if (this->dacs
.groups
[this->dacs
.ngroups
].conv
[j
] == dac
)
458 if (j
< n
) /* this group already has <dac> */
460 this->dacs
.groups
[this->dacs
.ngroups
].conv
[n
++] = dac
;
461 DPRINTF(("%s: assoc=%d seq=%d ==> g=%d n=%d\n",
462 __func__
, assoc
, seq
, this->dacs
.ngroups
, n
-1));
464 if (n
<= 0) /* no such DACs */
466 this->dacs
.groups
[this->dacs
.ngroups
].nconv
= n
;
468 /* check if the same combination is already registered */
469 for (i
= 0; i
< this->dacs
.ngroups
; i
++) {
470 if (n
!= this->dacs
.groups
[i
].nconv
)
472 for (j
= 0; j
< n
; j
++) {
473 if (this->dacs
.groups
[this->dacs
.ngroups
].conv
[j
] !=
474 this->dacs
.groups
[i
].conv
[j
])
477 if (j
>= n
) /* matched */
480 /* found no equivalent group */
481 this->dacs
.ngroups
++;
486 generic_codec_find_pin(const codec_t
*this, int assoc
, int seq
, uint32_t digital
)
490 FOR_EACH_WIDGET(this, i
) {
491 if (this->w
[i
].type
!= COP_AWTYPE_PIN_COMPLEX
)
493 if ((this->w
[i
].d
.pin
.cap
& COP_PINCAP_OUTPUT
) == 0)
495 if ((this->w
[i
].widgetcap
& COP_AWCAP_DIGITAL
) != digital
)
497 if (this->w
[i
].d
.pin
.association
!= assoc
)
499 if (this->w
[i
].d
.pin
.sequence
== seq
) {
507 generic_codec_find_dac(const codec_t
*this, int index
, int depth
)
513 if (w
->type
== COP_AWTYPE_AUDIO_OUTPUT
) {
514 DPRINTF(("%s: DAC: nid=0x%x index=%d\n",
515 __func__
, w
->nid
, index
));
521 if (w
->selected
>= 0) {
522 j
= w
->connections
[w
->selected
];
523 if (VALID_WIDGET_NID(j
, this)) {
524 ret
= generic_codec_find_dac(this, j
, depth
);
526 DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
527 __func__
, w
->nid
, index
));
532 for (i
= 0; i
< w
->nconnections
; i
++) {
533 j
= w
->connections
[i
];
534 if (!VALID_WIDGET_NID(j
, this))
536 ret
= generic_codec_find_dac(this, j
, depth
);
538 DPRINTF(("%s: DAC path: nid=0x%x index=%d\n",
539 __func__
, w
->nid
, index
));
546 /* ----------------------------------------------------------------
547 * Generic mixer functions
548 * ---------------------------------------------------------------- */
550 #define GMIDPRINTF(x) do {} while (0/*CONSTCOND*/)
553 generic_mixer_init(codec_t
*this)
557 * audio output "dac%2.2x"
558 * audio input "adc%2.2x"
560 * selector "sel%2.2x"
565 this->maxmixers
= 10;
567 this->mixers
= malloc(sizeof(mixer_item_t
) * this->maxmixers
,
568 M_DEVBUF
, M_ZERO
| M_NOWAIT
);
569 if (this->mixers
== NULL
) {
570 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
574 /* register classes */
575 DPRINTF(("%s: register classes\n", __func__
));
576 m
= &this->mixers
[AZ_CLASS_INPUT
];
577 m
->devinfo
.index
= AZ_CLASS_INPUT
;
578 strlcpy(m
->devinfo
.label
.name
, AudioCinputs
,
579 sizeof(m
->devinfo
.label
.name
));
580 m
->devinfo
.type
= AUDIO_MIXER_CLASS
;
581 m
->devinfo
.mixer_class
= AZ_CLASS_INPUT
;
582 m
->devinfo
.next
= AUDIO_MIXER_LAST
;
583 m
->devinfo
.prev
= AUDIO_MIXER_LAST
;
586 m
= &this->mixers
[AZ_CLASS_OUTPUT
];
587 m
->devinfo
.index
= AZ_CLASS_OUTPUT
;
588 strlcpy(m
->devinfo
.label
.name
, AudioCoutputs
,
589 sizeof(m
->devinfo
.label
.name
));
590 m
->devinfo
.type
= AUDIO_MIXER_CLASS
;
591 m
->devinfo
.mixer_class
= AZ_CLASS_OUTPUT
;
592 m
->devinfo
.next
= AUDIO_MIXER_LAST
;
593 m
->devinfo
.prev
= AUDIO_MIXER_LAST
;
596 m
= &this->mixers
[AZ_CLASS_RECORD
];
597 m
->devinfo
.index
= AZ_CLASS_RECORD
;
598 strlcpy(m
->devinfo
.label
.name
, AudioCrecord
,
599 sizeof(m
->devinfo
.label
.name
));
600 m
->devinfo
.type
= AUDIO_MIXER_CLASS
;
601 m
->devinfo
.mixer_class
= AZ_CLASS_RECORD
;
602 m
->devinfo
.next
= AUDIO_MIXER_LAST
;
603 m
->devinfo
.prev
= AUDIO_MIXER_LAST
;
606 m
= &this->mixers
[AZ_CLASS_PLAYBACK
];
607 m
->devinfo
.index
= AZ_CLASS_PLAYBACK
;
608 strlcpy(m
->devinfo
.label
.name
, AzaliaCplayback
,
609 sizeof(m
->devinfo
.label
.name
));
610 m
->devinfo
.type
= AUDIO_MIXER_CLASS
;
611 m
->devinfo
.mixer_class
= AZ_CLASS_PLAYBACK
;
612 m
->devinfo
.next
= AUDIO_MIXER_LAST
;
613 m
->devinfo
.prev
= AUDIO_MIXER_LAST
;
616 m
= &this->mixers
[AZ_CLASS_MIXER
];
617 m
->devinfo
.index
= AZ_CLASS_MIXER
;
618 strlcpy(m
->devinfo
.label
.name
, AzaliaCmixer
,
619 sizeof(m
->devinfo
.label
.name
));
620 m
->devinfo
.type
= AUDIO_MIXER_CLASS
;
621 m
->devinfo
.mixer_class
= AZ_CLASS_MIXER
;
622 m
->devinfo
.next
= AUDIO_MIXER_LAST
;
623 m
->devinfo
.prev
= AUDIO_MIXER_LAST
;
626 this->nmixers
= AZ_CLASS_MIXER
+ 1;
628 #define MIXER_REG_PROLOG \
629 mixer_devinfo_t *d; \
630 err = generic_mixer_ensure_capacity(this, this->nmixers + 1); \
633 m = &this->mixers[this->nmixers]; \
637 FOR_EACH_WIDGET(this, i
) {
642 /* skip unconnected pins */
643 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
) {
645 (w
->d
.pin
.config
& CORB_CD_PORT_MASK
) >> 30;
646 if (conn
== 1) /* no physical connection */
651 if (w
->type
!= COP_AWTYPE_AUDIO_MIXER
&&
652 w
->type
!= COP_AWTYPE_POWER
&& w
->nconnections
>= 2) {
654 GMIDPRINTF(("%s: selector %s\n", __func__
, w
->name
));
655 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
656 "%s.source", w
->name
);
657 d
->type
= AUDIO_MIXER_ENUM
;
658 if (w
->type
== COP_AWTYPE_AUDIO_MIXER
)
659 d
->mixer_class
= AZ_CLASS_RECORD
;
660 else if (w
->type
== COP_AWTYPE_AUDIO_SELECTOR
)
661 d
->mixer_class
= AZ_CLASS_INPUT
;
663 d
->mixer_class
= AZ_CLASS_OUTPUT
;
664 m
->target
= MI_TARGET_CONNLIST
;
665 for (j
= 0, k
= 0; j
< w
->nconnections
&& k
< 32; j
++) {
668 if (!VALID_WIDGET_NID(w
->connections
[j
], this))
670 /* skip unconnected pins */
671 PIN_STATUS(&this->w
[w
->connections
[j
]],
675 GMIDPRINTF(("%s: selector %d=%s\n", __func__
, j
,
676 this->w
[w
->connections
[j
]].name
));
677 d
->un
.e
.member
[k
].ord
= j
;
678 strlcpy(d
->un
.e
.member
[k
].label
.name
,
679 this->w
[w
->connections
[j
]].name
,
688 if (w
->widgetcap
& COP_AWCAP_OUTAMP
&&
689 w
->outamp_cap
& COP_AMPCAP_MUTE
) {
691 GMIDPRINTF(("%s: output mute %s\n", __func__
, w
->name
));
692 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
694 d
->type
= AUDIO_MIXER_ENUM
;
695 if (w
->type
== COP_AWTYPE_AUDIO_MIXER
)
696 d
->mixer_class
= AZ_CLASS_MIXER
;
697 else if (w
->type
== COP_AWTYPE_AUDIO_SELECTOR
)
698 d
->mixer_class
= AZ_CLASS_OUTPUT
;
699 else if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
700 d
->mixer_class
= AZ_CLASS_OUTPUT
;
702 d
->mixer_class
= AZ_CLASS_INPUT
;
703 m
->target
= MI_TARGET_OUTAMP
;
705 d
->un
.e
.member
[0].ord
= 0;
706 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNoff
,
708 d
->un
.e
.member
[1].ord
= 1;
709 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNon
,
715 if (w
->widgetcap
& COP_AWCAP_OUTAMP
716 && COP_AMPCAP_NUMSTEPS(w
->outamp_cap
)) {
718 GMIDPRINTF(("%s: output gain %s\n", __func__
, w
->name
));
719 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
721 d
->type
= AUDIO_MIXER_VALUE
;
722 if (w
->type
== COP_AWTYPE_AUDIO_MIXER
)
723 d
->mixer_class
= AZ_CLASS_MIXER
;
724 else if (w
->type
== COP_AWTYPE_AUDIO_SELECTOR
)
725 d
->mixer_class
= AZ_CLASS_OUTPUT
;
726 else if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
727 d
->mixer_class
= AZ_CLASS_OUTPUT
;
729 d
->mixer_class
= AZ_CLASS_INPUT
;
730 m
->target
= MI_TARGET_OUTAMP
;
731 d
->un
.v
.num_channels
= WIDGET_CHANNELS(w
);
732 #ifdef MAX_VOLUME_255
733 d
->un
.v
.units
.name
[0] = 0;
735 snprintf(d
->un
.v
.units
.name
, sizeof(d
->un
.v
.units
.name
),
736 "0.25x%ddB", COP_AMPCAP_STEPSIZE(w
->outamp_cap
)+1);
739 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w
->outamp_cap
));
744 if (w
->widgetcap
& COP_AWCAP_INAMP
&&
745 w
->inamp_cap
& COP_AMPCAP_MUTE
) {
746 GMIDPRINTF(("%s: input mute %s\n", __func__
, w
->name
));
747 if (w
->type
!= COP_AWTYPE_AUDIO_SELECTOR
&&
748 w
->type
!= COP_AWTYPE_AUDIO_MIXER
) {
750 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
752 d
->type
= AUDIO_MIXER_ENUM
;
753 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
754 d
->mixer_class
= AZ_CLASS_OUTPUT
;
755 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
756 d
->mixer_class
= AZ_CLASS_RECORD
;
758 d
->mixer_class
= AZ_CLASS_INPUT
;
761 d
->un
.e
.member
[0].ord
= 0;
762 strlcpy(d
->un
.e
.member
[0].label
.name
,
763 AudioNoff
, MAX_AUDIO_DEV_LEN
);
764 d
->un
.e
.member
[1].ord
= 1;
765 strlcpy(d
->un
.e
.member
[1].label
.name
,
766 AudioNon
, MAX_AUDIO_DEV_LEN
);
771 for (j
= 0; j
< w
->nconnections
; j
++) {
773 if (!VALID_WIDGET_NID(w
->connections
[j
], this))
776 /* skip unconnected pins */
777 PIN_STATUS(&this->w
[w
->connections
[j
]],
782 GMIDPRINTF(("%s: input mute %s.%s\n", __func__
,
783 w
->name
, this->w
[w
->connections
[j
]].name
));
784 generic_mixer_cat_names(
786 sizeof(d
->label
.name
),
787 w
->name
, this->w
[w
->connections
[j
]].name
,
789 d
->type
= AUDIO_MIXER_ENUM
;
790 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
791 d
->mixer_class
= AZ_CLASS_OUTPUT
;
792 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
793 d
->mixer_class
= AZ_CLASS_RECORD
;
794 else if (w
->type
== COP_AWTYPE_AUDIO_MIXER
)
795 d
->mixer_class
= AZ_CLASS_MIXER
;
797 d
->mixer_class
= AZ_CLASS_INPUT
;
800 d
->un
.e
.member
[0].ord
= 0;
801 strlcpy(d
->un
.e
.member
[0].label
.name
,
802 AudioNoff
, MAX_AUDIO_DEV_LEN
);
803 d
->un
.e
.member
[1].ord
= 1;
804 strlcpy(d
->un
.e
.member
[1].label
.name
,
805 AudioNon
, MAX_AUDIO_DEV_LEN
);
812 if (w
->widgetcap
& COP_AWCAP_INAMP
813 && COP_AMPCAP_NUMSTEPS(w
->inamp_cap
)) {
814 GMIDPRINTF(("%s: input gain %s\n", __func__
, w
->name
));
815 if (w
->type
!= COP_AWTYPE_AUDIO_SELECTOR
&&
816 w
->type
!= COP_AWTYPE_AUDIO_MIXER
) {
818 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
820 d
->type
= AUDIO_MIXER_VALUE
;
821 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
822 d
->mixer_class
= AZ_CLASS_OUTPUT
;
823 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
824 d
->mixer_class
= AZ_CLASS_RECORD
;
826 d
->mixer_class
= AZ_CLASS_INPUT
;
828 d
->un
.v
.num_channels
= WIDGET_CHANNELS(w
);
829 #ifdef MAX_VOLUME_255
830 d
->un
.v
.units
.name
[0] = 0;
832 snprintf(d
->un
.v
.units
.name
,
833 sizeof(d
->un
.v
.units
.name
), "0.25x%ddB",
834 COP_AMPCAP_STEPSIZE(w
->inamp_cap
)+1);
837 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w
->inamp_cap
));
842 for (j
= 0; j
< w
->nconnections
; j
++) {
844 if (!VALID_WIDGET_NID(w
->connections
[j
], this))
846 /* skip unconnected pins */
847 PIN_STATUS(&this->w
[w
->connections
[j
]],
851 GMIDPRINTF(("%s: input gain %s.%s\n", __func__
,
852 w
->name
, this->w
[w
->connections
[j
]].name
));
853 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
855 this->w
[w
->connections
[j
]].name
);
856 d
->type
= AUDIO_MIXER_VALUE
;
857 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
858 d
->mixer_class
= AZ_CLASS_OUTPUT
;
859 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
860 d
->mixer_class
= AZ_CLASS_RECORD
;
861 else if (w
->type
== COP_AWTYPE_AUDIO_MIXER
)
862 d
->mixer_class
= AZ_CLASS_MIXER
;
864 d
->mixer_class
= AZ_CLASS_INPUT
;
866 d
->un
.v
.num_channels
= WIDGET_CHANNELS(w
);
867 #ifdef MAX_VOLUME_255
868 d
->un
.v
.units
.name
[0] = 0;
870 snprintf(d
->un
.v
.units
.name
,
871 sizeof(d
->un
.v
.units
.name
), "0.25x%ddB",
872 COP_AMPCAP_STEPSIZE(w
->inamp_cap
)+1);
875 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w
->inamp_cap
));
882 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
&&
883 w
->d
.pin
.cap
& COP_PINCAP_OUTPUT
&&
884 w
->d
.pin
.cap
& COP_PINCAP_INPUT
) {
886 GMIDPRINTF(("%s: pin dir %s\n", __func__
, w
->name
));
887 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
889 d
->type
= AUDIO_MIXER_ENUM
;
890 d
->mixer_class
= AZ_CLASS_OUTPUT
;
891 m
->target
= MI_TARGET_PINDIR
;
893 d
->un
.e
.member
[0].ord
= 0;
894 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNinput
,
896 d
->un
.e
.member
[1].ord
= 1;
897 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNoutput
,
902 /* pin headphone-boost */
903 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
&&
904 w
->d
.pin
.cap
& COP_PINCAP_HEADPHONE
) {
906 GMIDPRINTF(("%s: hpboost %s\n", __func__
, w
->name
));
907 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
908 "%s.boost", w
->name
);
909 d
->type
= AUDIO_MIXER_ENUM
;
910 d
->mixer_class
= AZ_CLASS_OUTPUT
;
911 m
->target
= MI_TARGET_PINBOOST
;
913 d
->un
.e
.member
[0].ord
= 0;
914 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNoff
,
916 d
->un
.e
.member
[1].ord
= 1;
917 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNon
,
922 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
&&
923 w
->d
.pin
.cap
& COP_PINCAP_EAPD
) {
925 GMIDPRINTF(("%s: eapd %s\n", __func__
, w
->name
));
926 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
928 d
->type
= AUDIO_MIXER_ENUM
;
929 d
->mixer_class
= AZ_CLASS_OUTPUT
;
930 m
->target
= MI_TARGET_EAPD
;
932 d
->un
.e
.member
[0].ord
= 0;
933 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNoff
,
935 d
->un
.e
.member
[1].ord
= 1;
936 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNon
,
941 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
&&
942 w
->d
.pin
.cap
& COP_PINCAP_BALANCE
) {
944 GMIDPRINTF(("%s: balance %s\n", __func__
, w
->name
));
945 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
946 "%s.balance", w
->name
);
947 d
->type
= AUDIO_MIXER_ENUM
;
948 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
949 d
->mixer_class
= AZ_CLASS_OUTPUT
;
950 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
951 d
->mixer_class
= AZ_CLASS_RECORD
;
953 d
->mixer_class
= AZ_CLASS_INPUT
;
954 m
->target
= MI_TARGET_BALANCE
;
956 d
->un
.e
.member
[0].ord
= 0;
957 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNoff
,
959 d
->un
.e
.member
[1].ord
= 1;
960 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNon
,
965 if (w
->widgetcap
& COP_AWCAP_LRSWAP
) {
967 GMIDPRINTF(("%s: lrswap %s\n", __func__
, w
->name
));
968 snprintf(d
->label
.name
, sizeof(d
->label
.name
),
969 "%s.lrswap", w
->name
);
970 d
->type
= AUDIO_MIXER_ENUM
;
971 if (w
->type
== COP_AWTYPE_PIN_COMPLEX
)
972 d
->mixer_class
= AZ_CLASS_OUTPUT
;
973 else if (w
->type
== COP_AWTYPE_AUDIO_INPUT
)
974 d
->mixer_class
= AZ_CLASS_RECORD
;
976 d
->mixer_class
= AZ_CLASS_INPUT
;
977 m
->target
= MI_TARGET_LRSWAP
;
979 d
->un
.e
.member
[0].ord
= 0;
980 strlcpy(d
->un
.e
.member
[0].label
.name
, AudioNoff
,
982 d
->un
.e
.member
[1].ord
= 1;
983 strlcpy(d
->un
.e
.member
[1].label
.name
, AudioNon
,
989 if (w
->type
== COP_AWTYPE_VOLUME_KNOB
&&
990 w
->d
.volume
.cap
& COP_VKCAP_DELTA
) {
992 GMIDPRINTF(("%s: volume knob %s\n", __func__
, w
->name
));
993 strlcpy(d
->label
.name
, w
->name
, sizeof(d
->label
.name
));
994 d
->type
= AUDIO_MIXER_VALUE
;
995 d
->mixer_class
= AZ_CLASS_OUTPUT
;
996 m
->target
= MI_TARGET_VOLUME
;
997 d
->un
.v
.num_channels
= 1;
998 d
->un
.v
.units
.name
[0] = 0;
1000 MIXER_DELTA(COP_VKCAP_NUMSTEPS(w
->d
.volume
.cap
));
1005 /* if the codec has multiple DAC groups, create "playback.mode" */
1006 if (this->dacs
.ngroups
> 1) {
1008 GMIDPRINTF(("%s: create playback.mode\n", __func__
));
1009 strlcpy(d
->label
.name
, AudioNmode
, sizeof(d
->label
.name
));
1010 d
->type
= AUDIO_MIXER_ENUM
;
1011 d
->mixer_class
= AZ_CLASS_PLAYBACK
;
1012 m
->target
= MI_TARGET_DAC
;
1013 for (i
= 0; i
< this->dacs
.ngroups
&& i
< 32; i
++) {
1014 d
->un
.e
.member
[i
].ord
= i
;
1015 for (j
= 0; j
< this->dacs
.groups
[i
].nconv
; j
++) {
1016 if (j
* 2 >= MAX_AUDIO_DEV_LEN
)
1018 snprintf(d
->un
.e
.member
[i
].label
.name
+ j
*2,
1019 MAX_AUDIO_DEV_LEN
- j
*2, "%2.2x",
1020 this->dacs
.groups
[i
].conv
[j
]);
1023 d
->un
.e
.num_mem
= i
;
1027 /* if the codec has multiple ADC groups, create "record.mode" */
1028 if (this->adcs
.ngroups
> 1) {
1030 GMIDPRINTF(("%s: create record.mode\n", __func__
));
1031 strlcpy(d
->label
.name
, AudioNmode
, sizeof(d
->label
.name
));
1032 d
->type
= AUDIO_MIXER_ENUM
;
1033 d
->mixer_class
= AZ_CLASS_RECORD
;
1034 m
->target
= MI_TARGET_ADC
;
1035 for (i
= 0; i
< this->adcs
.ngroups
&& i
< 32; i
++) {
1036 d
->un
.e
.member
[i
].ord
= i
;
1037 for (j
= 0; j
< this->adcs
.groups
[i
].nconv
; j
++) {
1038 if (j
* 2 >= MAX_AUDIO_DEV_LEN
)
1040 snprintf(d
->un
.e
.member
[i
].label
.name
+ j
*2,
1041 MAX_AUDIO_DEV_LEN
- j
*2, "%2.2x",
1042 this->adcs
.groups
[i
].conv
[j
]);
1045 d
->un
.e
.num_mem
= i
;
1049 generic_mixer_fix_indexes(this);
1050 generic_mixer_default(this);
1055 generic_mixer_cat_names(char *dst
, size_t dstsize
,
1056 const char *str1
, const char *str2
, const char *str3
)
1059 size_t len1
, len2
, len3
, total
;
1061 len1
= strlen(str1
);
1062 len2
= strlen(str2
);
1063 len3
= strlen(str3
);
1064 total
= len1
+ 1 + len2
+ 1 + len3
+ 1;
1065 if (total
- (len3
- 1) <= dstsize
) {
1066 snprintf(dst
, dstsize
, "%s.%s.%s", str1
, str2
, str3
);
1069 last2
= len2
> 2 ? str2
+ len2
- 2 : str2
;
1071 snprintf(dst
, dstsize
, "%s.%.2s%s.%s", str1
, str2
, last2
, str3
);
1074 snprintf(dst
, dstsize
, "%s.%s.%s", str1
, last2
, str3
);
1078 generic_mixer_ensure_capacity(codec_t
*this, size_t newsize
)
1083 if (this->maxmixers
>= newsize
)
1085 newmax
= this->maxmixers
+ 10;
1086 if (newmax
< newsize
)
1088 newbuf
= realloc(this->mixers
, sizeof(mixer_item_t
) * newmax
, M_DEVBUF
,
1090 if (newbuf
== NULL
) {
1091 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
1094 this->mixers
= newbuf
;
1095 /* realloc(9) doesn't clear expanded area even if M_ZERO. */
1096 memset(&this->mixers
[this->maxmixers
], 0,
1097 sizeof(mixer_item_t
) * (newmax
- this->maxmixers
));
1098 this->maxmixers
= newmax
;
1103 generic_mixer_fix_indexes(codec_t
*this)
1108 for (i
= 0; i
< this->nmixers
; i
++) {
1109 d
= &this->mixers
[i
].devinfo
;
1111 if (d
->index
!= 0 && d
->index
!= i
)
1112 aprint_error("%s: index mismatch %d %d\n", __func__
,
1117 d
->prev
= AUDIO_MIXER_LAST
;
1119 d
->next
= AUDIO_MIXER_LAST
;
1125 generic_mixer_default(codec_t
*this)
1130 DPRINTF(("%s: unmute\n", __func__
));
1131 for (i
= 0; i
< this->nmixers
; i
++) {
1134 m
= &this->mixers
[i
];
1135 if (!IS_MI_TARGET_INAMP(m
->target
) &&
1136 m
->target
!= MI_TARGET_OUTAMP
)
1138 if (m
->devinfo
.type
!= AUDIO_MIXER_ENUM
)
1141 mc
.type
= AUDIO_MIXER_ENUM
;
1143 generic_mixer_set(this, m
->nid
, m
->target
, &mc
);
1147 * For bidirectional pins, make the default `output'
1149 DPRINTF(("%s: process bidirectional pins\n", __func__
));
1150 for (i
= 0; i
< this->nmixers
; i
++) {
1153 m
= &this->mixers
[i
];
1154 if (m
->target
!= MI_TARGET_PINDIR
)
1157 mc
.type
= AUDIO_MIXER_ENUM
;
1158 mc
.un
.ord
= 1; /* output */
1159 generic_mixer_set(this, m
->nid
, m
->target
, &mc
);
1162 /* set unextreme volume */
1163 DPRINTF(("%s: set volume\n", __func__
));
1164 for (i
= 0; i
< this->nmixers
; i
++) {
1167 m
= &this->mixers
[i
];
1168 if (!IS_MI_TARGET_INAMP(m
->target
) &&
1169 m
->target
!= MI_TARGET_OUTAMP
&&
1170 m
->target
!= MI_TARGET_VOLUME
)
1172 if (m
->devinfo
.type
!= AUDIO_MIXER_VALUE
)
1175 mc
.type
= AUDIO_MIXER_VALUE
;
1176 mc
.un
.value
.num_channels
= 1;
1177 mc
.un
.value
.level
[0] = AUDIO_MAX_GAIN
/ 2;
1178 if (m
->target
!= MI_TARGET_VOLUME
&&
1179 WIDGET_CHANNELS(&this->w
[m
->nid
]) == 2) {
1180 mc
.un
.value
.num_channels
= 2;
1181 mc
.un
.value
.level
[1] = AUDIO_MAX_GAIN
/ 2;
1183 generic_mixer_set(this, m
->nid
, m
->target
, &mc
);
1190 generic_mixer_pin_sense(codec_t
*this)
1200 FOR_EACH_WIDGET(this, i
) {
1201 pintype_t pintype
= PIN_DIR_IN
;
1204 if (w
->type
!= COP_AWTYPE_PIN_COMPLEX
)
1206 if (!(w
->d
.pin
.cap
& COP_PINCAP_INPUT
))
1207 pintype
= PIN_DIR_OUT
;
1208 if (!(w
->d
.pin
.cap
& COP_PINCAP_OUTPUT
))
1209 pintype
= PIN_DIR_IN
;
1211 switch (w
->d
.pin
.device
) {
1212 case CORB_CD_LINEOUT
:
1213 case CORB_CD_SPEAKER
:
1214 case CORB_CD_HEADPHONE
:
1215 case CORB_CD_SPDIFOUT
:
1216 case CORB_CD_DIGITALOUT
:
1217 pintype
= PIN_DIR_OUT
;
1220 case CORB_CD_LINEIN
:
1221 pintype
= PIN_DIR_IN
;
1224 pintype
= PIN_DIR_MIC
;
1230 this->comresp(this, w
->nid
,
1231 CORB_SET_PIN_WIDGET_CONTROL
,
1232 CORB_PWC_INPUT
, NULL
);
1235 this->comresp(this, w
->nid
,
1236 CORB_SET_PIN_WIDGET_CONTROL
,
1237 CORB_PWC_OUTPUT
, NULL
);
1240 this->comresp(this, w
->nid
,
1241 CORB_SET_PIN_WIDGET_CONTROL
,
1242 CORB_PWC_INPUT
|CORB_PWC_VREF_80
, NULL
);
1246 if (w
->d
.pin
.cap
& COP_PINCAP_EAPD
) {
1250 err
= this->comresp(this, w
->nid
,
1251 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1255 result
|= CORB_EAPD_EAPD
;
1256 err
= this->comresp(this, w
->nid
,
1257 CORB_SET_EAPD_BTL_ENABLE
, result
, &result
);
1267 generic_mixer_widget_name(const codec_t
*this, widget_t
*w
)
1269 const char *name
= NULL
, *grossloc
= "", *geoloc
= "";
1270 uint8_t grosslocval
, geolocval
;
1272 if (w
->type
!= COP_AWTYPE_PIN_COMPLEX
)
1275 switch (w
->d
.pin
.device
) {
1276 case CORB_CD_LINEOUT
: name
= "lineout"; break;
1277 case CORB_CD_SPEAKER
: name
= "spkr"; break;
1278 case CORB_CD_HEADPHONE
: name
= "hp"; break;
1279 case CORB_CD_CD
: name
= AudioNcd
; break;
1280 case CORB_CD_SPDIFOUT
: name
= "spdifout"; break;
1281 case CORB_CD_DIGITALOUT
: name
= "digout"; break;
1282 case CORB_CD_MODEMLINE
: name
= "modemline"; break;
1283 case CORB_CD_MODEMHANDSET
: name
= "modemhset"; break;
1284 case CORB_CD_LINEIN
: name
= "linein"; break;
1285 case CORB_CD_AUX
: name
= AudioNaux
; break;
1286 case CORB_CD_MICIN
: name
= AudioNmicrophone
; break;
1287 case CORB_CD_TELEPHONY
: name
= "telephony"; break;
1288 case CORB_CD_SPDIFIN
: name
= "spdifin"; break;
1289 case CORB_CD_DIGITALIN
: name
= "digin"; break;
1290 case CORB_CD_DEVICE_OTHER
: name
= "reserved"; break;
1291 default: name
= "unused"; break;
1294 grosslocval
= ((w
->d
.pin
.config
& CORB_CD_LOCATION_MASK
) >> 24) & 0xf;
1295 geolocval
= (w
->d
.pin
.config
& CORB_CD_LOCATION_MASK
) >> 28;
1297 switch (geolocval
) {
1298 case 0x00: /* external on primary chassis */
1299 case 0x10: /* external on separate chassis */
1300 geoloc
= (geolocval
== 0x00 ? "" : "d");
1301 switch (grosslocval
) {
1302 case 0x00: grossloc
= ""; break; /* N/A */
1303 case 0x01: grossloc
= ""; break; /* rear */
1304 case 0x02: grossloc
= ".front"; break; /* front */
1305 case 0x03: grossloc
= ".left"; break; /* left */
1306 case 0x04: grossloc
= ".right"; break; /* right */
1307 case 0x05: grossloc
= ".top"; break; /* top */
1308 case 0x06: grossloc
= ".bottom"; break; /* bottom */
1309 case 0x07: grossloc
= ".rearpnl"; break; /* rear panel */
1310 case 0x08: grossloc
= ".drivebay"; break; /* drive bay */
1311 default: grossloc
= ""; break;
1316 switch (grosslocval
) {
1317 case 0x00: grossloc
= ""; break; /* N/A */
1318 case 0x07: grossloc
= ".riser"; break; /* riser */
1319 case 0x08: grossloc
= ".hdmi"; break; /* hdmi */
1320 default: grossloc
= ""; break;
1325 switch (grosslocval
) {
1326 case 0x00: grossloc
= ""; break; /* N/A */
1327 case 0x06: grossloc
= ".bottom"; break; /* bottom */
1328 case 0x07: grossloc
= ".lidin"; break; /* lid inside */
1329 case 0x08: grossloc
= ".lidout"; break; /* lid outside */
1330 default: grossloc
= ""; break;
1335 snprintf(w
->name
, sizeof(w
->name
), "%s%s%s", geoloc
, name
, grossloc
);
1340 generic_mixer_create_virtual(codec_t
*this)
1344 convgroup_t
*cgdac
= &this->dacs
.groups
[0];
1345 convgroup_t
*cgadc
= &this->adcs
.groups
[0];
1346 int i
, err
, mdac
, madc
, mmaster
;
1348 /* Clear mixer indexes, to make generic_mixer_fix_index happy */
1349 for (i
= 0; i
< this->nmixers
; i
++) {
1350 d
= &this->mixers
[i
].devinfo
;
1351 d
->index
= d
->prev
= d
->next
= 0;
1354 mdac
= madc
= mmaster
= -1;
1355 for (i
= 0; i
< this->nmixers
; i
++) {
1356 if (this->mixers
[i
].devinfo
.type
!= AUDIO_MIXER_VALUE
)
1358 if (mdac
< 0 && this->dacs
.ngroups
> 0 && cgdac
->nconv
> 0) {
1359 if (this->mixers
[i
].nid
== cgdac
->conv
[0])
1362 if (madc
< 0 && this->adcs
.ngroups
> 0 && cgadc
->nconv
> 0) {
1363 if (this->mixers
[i
].nid
== cgadc
->conv
[0])
1370 * no volume mixer found on the DAC; enumerate peer widgets
1371 * and try to find a volume mixer on them
1375 FOR_EACH_WIDGET(this, i
) {
1377 for (j
= 0; j
< w
->nconnections
; j
++)
1378 if (w
->connections
[j
] == cgdac
->conv
[0])
1381 if (j
== w
->nconnections
)
1384 for (j
= 0; j
< this->nmixers
; j
++) {
1385 if (this->mixers
[j
].devinfo
.type
!=
1388 if (this->mixers
[j
].nid
== w
->nid
) {
1400 err
= generic_mixer_ensure_capacity(this, this->nmixers
+ 1);
1403 m
= &this->mixers
[this->nmixers
];
1405 memcpy(m
, &this->mixers
[mmaster
], sizeof(*m
));
1406 d
->mixer_class
= AZ_CLASS_OUTPUT
;
1407 snprintf(d
->label
.name
, sizeof(d
->label
.name
), AudioNmaster
);
1410 err
= generic_mixer_ensure_capacity(this, this->nmixers
+ 1);
1413 m
= &this->mixers
[this->nmixers
];
1415 memcpy(m
, &this->mixers
[mdac
], sizeof(*m
));
1416 d
->mixer_class
= AZ_CLASS_INPUT
;
1417 snprintf(d
->label
.name
, sizeof(d
->label
.name
), AudioNdac
);
1422 err
= generic_mixer_ensure_capacity(this, this->nmixers
+ 1);
1425 m
= &this->mixers
[this->nmixers
];
1427 memcpy(m
, &this->mixers
[madc
], sizeof(*m
));
1428 d
->mixer_class
= AZ_CLASS_RECORD
;
1429 snprintf(d
->label
.name
, sizeof(d
->label
.name
), AudioNvolume
);
1433 generic_mixer_fix_indexes(this);
1439 generic_mixer_autoinit(codec_t
*this)
1441 generic_mixer_init(this);
1442 generic_mixer_create_virtual(this);
1443 generic_mixer_pin_sense(this);
1449 generic_mixer_init_widget(const codec_t
*this, widget_t
*w
, nid_t nid
)
1451 return generic_mixer_widget_name(this, w
);
1455 generic_mixer_delete(codec_t
*this)
1457 if (this->mixers
== NULL
)
1459 free(this->mixers
, M_DEVBUF
);
1460 this->mixers
= NULL
;
1465 * @param mc mc->type must be set by the caller before the call
1468 generic_mixer_get(const codec_t
*this, nid_t nid
, int target
, mixer_ctrl_t
*mc
)
1475 if (IS_MI_TARGET_INAMP(target
) && mc
->type
== AUDIO_MIXER_ENUM
) {
1476 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1477 CORB_GAGM_INPUT
| CORB_GAGM_LEFT
|
1478 MI_TARGET_INAMP(target
), &result
);
1481 mc
->un
.ord
= result
& CORB_GAGM_MUTE
? 1 : 0;
1485 else if (IS_MI_TARGET_INAMP(target
) && mc
->type
== AUDIO_MIXER_VALUE
) {
1486 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1487 CORB_GAGM_INPUT
| CORB_GAGM_LEFT
|
1488 MI_TARGET_INAMP(target
), &result
);
1491 mc
->un
.value
.level
[0] = generic_mixer_from_device_value(this,
1492 nid
, target
, CORB_GAGM_GAIN(result
));
1493 if (this->w
[nid
].type
== COP_AWTYPE_AUDIO_SELECTOR
||
1494 this->w
[nid
].type
== COP_AWTYPE_AUDIO_MIXER
) {
1495 n
= this->w
[nid
].connections
[MI_TARGET_INAMP(target
)];
1497 if (!VALID_WIDGET_NID(n
, this)) {
1498 DPRINTF(("%s: invalid target: nid=%d nconn=%d index=%d\n",
1499 __func__
, nid
, this->w
[nid
].nconnections
,
1500 MI_TARGET_INAMP(target
)));
1507 mc
->un
.value
.num_channels
= WIDGET_CHANNELS(&this->w
[n
]);
1508 if (mc
->un
.value
.num_channels
== 2) {
1509 err
= this->comresp(this, nid
,
1510 CORB_GET_AMPLIFIER_GAIN_MUTE
, CORB_GAGM_INPUT
|
1511 CORB_GAGM_RIGHT
| MI_TARGET_INAMP(target
),
1515 mc
->un
.value
.level
[1] = generic_mixer_from_device_value
1516 (this, nid
, target
, CORB_GAGM_GAIN(result
));
1521 else if (target
== MI_TARGET_OUTAMP
&& mc
->type
== AUDIO_MIXER_ENUM
) {
1522 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1523 CORB_GAGM_OUTPUT
| CORB_GAGM_LEFT
| 0, &result
);
1526 mc
->un
.ord
= result
& CORB_GAGM_MUTE
? 1 : 0;
1530 else if (target
== MI_TARGET_OUTAMP
&& mc
->type
== AUDIO_MIXER_VALUE
) {
1531 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1532 CORB_GAGM_OUTPUT
| CORB_GAGM_LEFT
| 0, &result
);
1535 mc
->un
.value
.level
[0] = generic_mixer_from_device_value(this,
1536 nid
, target
, CORB_GAGM_GAIN(result
));
1537 mc
->un
.value
.num_channels
= WIDGET_CHANNELS(&this->w
[nid
]);
1538 if (mc
->un
.value
.num_channels
== 2) {
1539 err
= this->comresp(this, nid
,
1540 CORB_GET_AMPLIFIER_GAIN_MUTE
,
1541 CORB_GAGM_OUTPUT
| CORB_GAGM_RIGHT
| 0, &result
);
1544 mc
->un
.value
.level
[1] = generic_mixer_from_device_value
1545 (this, nid
, target
, CORB_GAGM_GAIN(result
));
1550 else if (target
== MI_TARGET_CONNLIST
) {
1551 err
= this->comresp(this, nid
,
1552 CORB_GET_CONNECTION_SELECT_CONTROL
, 0, &result
);
1555 result
= CORB_CSC_INDEX(result
);
1556 if (!VALID_WIDGET_NID(this->w
[nid
].connections
[result
], this))
1559 mc
->un
.ord
= result
;
1563 else if (target
== MI_TARGET_PINDIR
) {
1564 err
= this->comresp(this, nid
,
1565 CORB_GET_PIN_WIDGET_CONTROL
, 0, &result
);
1568 mc
->un
.ord
= result
& CORB_PWC_OUTPUT
? 1 : 0;
1571 /* pin headphone-boost */
1572 else if (target
== MI_TARGET_PINBOOST
) {
1573 err
= this->comresp(this, nid
,
1574 CORB_GET_PIN_WIDGET_CONTROL
, 0, &result
);
1577 mc
->un
.ord
= result
& CORB_PWC_HEADPHONE
? 1 : 0;
1580 /* DAC group selection */
1581 else if (target
== MI_TARGET_DAC
) {
1582 mc
->un
.ord
= this->dacs
.cur
;
1586 else if (target
== MI_TARGET_ADC
) {
1587 mc
->un
.ord
= this->adcs
.cur
;
1591 else if (target
== MI_TARGET_VOLUME
) {
1592 err
= this->comresp(this, nid
, CORB_GET_VOLUME_KNOB
,
1596 mc
->un
.value
.level
[0] = generic_mixer_from_device_value(this,
1597 nid
, target
, CORB_VKNOB_VOLUME(result
));
1598 mc
->un
.value
.num_channels
= 1;
1602 else if (target
== MI_TARGET_SPDIF
) {
1603 err
= this->comresp(this, nid
, CORB_GET_DIGITAL_CONTROL
,
1607 mc
->un
.mask
= result
& 0xff & ~(CORB_DCC_DIGEN
| CORB_DCC_NAUDIO
);
1608 } else if (target
== MI_TARGET_SPDIF_CC
) {
1609 err
= this->comresp(this, nid
, CORB_GET_DIGITAL_CONTROL
,
1613 mc
->un
.value
.num_channels
= 1;
1614 mc
->un
.value
.level
[0] = CORB_DCC_CC(result
);
1618 else if (target
== MI_TARGET_EAPD
) {
1619 err
= this->comresp(this, nid
,
1620 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1623 mc
->un
.ord
= result
& CORB_EAPD_EAPD
? 1 : 0;
1627 else if (target
== MI_TARGET_BALANCE
) {
1628 err
= this->comresp(this, nid
,
1629 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1632 mc
->un
.ord
= result
& CORB_EAPD_BTL
? 1 : 0;
1636 else if (target
== MI_TARGET_LRSWAP
) {
1637 err
= this->comresp(this, nid
,
1638 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1641 mc
->un
.ord
= result
& CORB_EAPD_LRSWAP
? 1 : 0;
1645 aprint_error_dev(this->dev
, "internal error in %s: target=%x\n",
1653 generic_mixer_set(codec_t
*this, nid_t nid
, int target
, const mixer_ctrl_t
*mc
)
1655 uint32_t result
, value
;
1659 if (IS_MI_TARGET_INAMP(target
) && mc
->type
== AUDIO_MIXER_ENUM
) {
1660 /* We have to set stereo mute separately to keep each gain value. */
1661 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1662 CORB_GAGM_INPUT
| CORB_GAGM_LEFT
|
1663 MI_TARGET_INAMP(target
), &result
);
1666 value
= CORB_AGM_INPUT
| CORB_AGM_LEFT
|
1667 (target
<< CORB_AGM_INDEX_SHIFT
) |
1668 CORB_GAGM_GAIN(result
);
1670 value
|= CORB_AGM_MUTE
;
1671 err
= this->comresp(this, nid
, CORB_SET_AMPLIFIER_GAIN_MUTE
,
1675 if (WIDGET_CHANNELS(&this->w
[nid
]) == 2) {
1676 err
= this->comresp(this, nid
,
1677 CORB_GET_AMPLIFIER_GAIN_MUTE
, CORB_GAGM_INPUT
|
1678 CORB_GAGM_RIGHT
| MI_TARGET_INAMP(target
),
1682 value
= CORB_AGM_INPUT
| CORB_AGM_RIGHT
|
1683 (target
<< CORB_AGM_INDEX_SHIFT
) |
1684 CORB_GAGM_GAIN(result
);
1686 value
|= CORB_AGM_MUTE
;
1687 err
= this->comresp(this, nid
,
1688 CORB_SET_AMPLIFIER_GAIN_MUTE
, value
, &result
);
1695 else if (IS_MI_TARGET_INAMP(target
) && mc
->type
== AUDIO_MIXER_VALUE
) {
1696 if (mc
->un
.value
.num_channels
< 1)
1698 if (!generic_mixer_validate_value(this, nid
, target
,
1699 mc
->un
.value
.level
[0]))
1701 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1702 CORB_GAGM_INPUT
| CORB_GAGM_LEFT
|
1703 MI_TARGET_INAMP(target
), &result
);
1706 value
= generic_mixer_to_device_value(this, nid
, target
,
1707 mc
->un
.value
.level
[0]);
1708 value
= CORB_AGM_INPUT
| CORB_AGM_LEFT
|
1709 (target
<< CORB_AGM_INDEX_SHIFT
) |
1710 (result
& CORB_GAGM_MUTE
? CORB_AGM_MUTE
: 0) |
1711 (value
& CORB_AGM_GAIN_MASK
);
1712 err
= this->comresp(this, nid
, CORB_SET_AMPLIFIER_GAIN_MUTE
,
1716 if (mc
->un
.value
.num_channels
>= 2 &&
1717 WIDGET_CHANNELS(&this->w
[nid
]) == 2) {
1718 if (!generic_mixer_validate_value(this, nid
, target
,
1719 mc
->un
.value
.level
[1]))
1721 err
= this->comresp(this, nid
,
1722 CORB_GET_AMPLIFIER_GAIN_MUTE
, CORB_GAGM_INPUT
|
1723 CORB_GAGM_RIGHT
| MI_TARGET_INAMP(target
),
1727 value
= generic_mixer_to_device_value(this, nid
, target
,
1728 mc
->un
.value
.level
[1]);
1729 value
= CORB_AGM_INPUT
| CORB_AGM_RIGHT
|
1730 (target
<< CORB_AGM_INDEX_SHIFT
) |
1731 (result
& CORB_GAGM_MUTE
? CORB_AGM_MUTE
: 0) |
1732 (value
& CORB_AGM_GAIN_MASK
);
1733 err
= this->comresp(this, nid
,
1734 CORB_SET_AMPLIFIER_GAIN_MUTE
, value
, &result
);
1741 else if (target
== MI_TARGET_OUTAMP
&& mc
->type
== AUDIO_MIXER_ENUM
) {
1742 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1743 CORB_GAGM_OUTPUT
| CORB_GAGM_LEFT
, &result
);
1746 value
= CORB_AGM_OUTPUT
| CORB_AGM_LEFT
| CORB_GAGM_GAIN(result
);
1748 value
|= CORB_AGM_MUTE
;
1749 err
= this->comresp(this, nid
, CORB_SET_AMPLIFIER_GAIN_MUTE
,
1753 if (WIDGET_CHANNELS(&this->w
[nid
]) == 2) {
1754 err
= this->comresp(this, nid
,
1755 CORB_GET_AMPLIFIER_GAIN_MUTE
,
1756 CORB_GAGM_OUTPUT
| CORB_GAGM_RIGHT
, &result
);
1759 value
= CORB_AGM_OUTPUT
| CORB_AGM_RIGHT
|
1760 CORB_GAGM_GAIN(result
);
1762 value
|= CORB_AGM_MUTE
;
1763 err
= this->comresp(this, nid
,
1764 CORB_SET_AMPLIFIER_GAIN_MUTE
, value
, &result
);
1771 else if (target
== MI_TARGET_OUTAMP
&& mc
->type
== AUDIO_MIXER_VALUE
) {
1772 if (mc
->un
.value
.num_channels
< 1)
1774 if (!generic_mixer_validate_value(this, nid
, target
,
1775 mc
->un
.value
.level
[0]))
1777 err
= this->comresp(this, nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
1778 CORB_GAGM_OUTPUT
| CORB_GAGM_LEFT
, &result
);
1781 value
= generic_mixer_to_device_value(this, nid
, target
,
1782 mc
->un
.value
.level
[0]);
1783 value
= CORB_AGM_OUTPUT
| CORB_AGM_LEFT
|
1784 (result
& CORB_GAGM_MUTE
? CORB_AGM_MUTE
: 0) |
1785 (value
& CORB_AGM_GAIN_MASK
);
1786 err
= this->comresp(this, nid
, CORB_SET_AMPLIFIER_GAIN_MUTE
,
1790 if (mc
->un
.value
.num_channels
>= 2 &&
1791 WIDGET_CHANNELS(&this->w
[nid
]) == 2) {
1792 if (!generic_mixer_validate_value(this, nid
, target
,
1793 mc
->un
.value
.level
[1]))
1795 err
= this->comresp(this, nid
,
1796 CORB_GET_AMPLIFIER_GAIN_MUTE
, CORB_GAGM_OUTPUT
|
1797 CORB_GAGM_RIGHT
, &result
);
1800 value
= generic_mixer_to_device_value(this, nid
, target
,
1801 mc
->un
.value
.level
[1]);
1802 value
= CORB_AGM_OUTPUT
| CORB_AGM_RIGHT
|
1803 (result
& CORB_GAGM_MUTE
? CORB_AGM_MUTE
: 0) |
1804 (value
& CORB_AGM_GAIN_MASK
);
1805 err
= this->comresp(this, nid
,
1806 CORB_SET_AMPLIFIER_GAIN_MUTE
, value
, &result
);
1813 else if (target
== MI_TARGET_CONNLIST
) {
1814 if (mc
->un
.ord
< 0 ||
1815 mc
->un
.ord
>= this->w
[nid
].nconnections
||
1816 !VALID_WIDGET_NID(this->w
[nid
].connections
[mc
->un
.ord
], this))
1818 err
= this->comresp(this, nid
,
1819 CORB_SET_CONNECTION_SELECT_CONTROL
, mc
->un
.ord
, &result
);
1825 else if (target
== MI_TARGET_PINDIR
) {
1826 if (mc
->un
.ord
>= 2)
1828 if (mc
->un
.ord
== 0) {
1829 return generic_mixer_pinctrl(this, nid
, CORB_PWC_INPUT
);
1831 return generic_mixer_pinctrl(
1832 this, nid
, CORB_PWC_OUTPUT
);
1836 /* pin headphone-boost */
1837 else if (target
== MI_TARGET_PINBOOST
) {
1838 if (mc
->un
.ord
>= 2)
1840 err
= this->comresp(this, nid
,
1841 CORB_GET_PIN_WIDGET_CONTROL
, 0, &result
);
1844 if (mc
->un
.ord
== 0) {
1845 result
&= ~CORB_PWC_HEADPHONE
;
1847 result
|= CORB_PWC_HEADPHONE
;
1849 err
= this->comresp(this, nid
,
1850 CORB_SET_PIN_WIDGET_CONTROL
, result
, &result
);
1855 /* DAC group selection */
1856 else if (target
== MI_TARGET_DAC
) {
1859 if (mc
->un
.ord
>= this->dacs
.ngroups
)
1861 return azalia_codec_construct_format(this,
1862 mc
->un
.ord
, this->adcs
.cur
);
1866 else if (target
== MI_TARGET_ADC
) {
1869 if (mc
->un
.ord
>= this->adcs
.ngroups
)
1871 return azalia_codec_construct_format(this,
1872 this->dacs
.cur
, mc
->un
.ord
);
1876 else if (target
== MI_TARGET_VOLUME
) {
1877 if (mc
->un
.value
.num_channels
!= 1)
1879 if (!generic_mixer_validate_value(this, nid
,
1880 target
, mc
->un
.value
.level
[0]))
1882 value
= generic_mixer_to_device_value(this, nid
, target
,
1883 mc
->un
.value
.level
[0]) | CORB_VKNOB_DIRECT
;
1884 err
= this->comresp(this, nid
, CORB_SET_VOLUME_KNOB
,
1891 else if (target
== MI_TARGET_SPDIF
) {
1892 err
= this->comresp(this, nid
, CORB_GET_DIGITAL_CONTROL
,
1894 result
&= CORB_DCC_DIGEN
| CORB_DCC_NAUDIO
;
1895 result
|= mc
->un
.mask
& 0xff & ~CORB_DCC_DIGEN
;
1896 err
= this->comresp(this, nid
, CORB_SET_DIGITAL_CONTROL_L
,
1900 } else if (target
== MI_TARGET_SPDIF_CC
) {
1901 if (mc
->un
.value
.num_channels
!= 1)
1903 if (mc
->un
.value
.level
[0] > 127)
1905 err
= this->comresp(this, nid
, CORB_SET_DIGITAL_CONTROL_H
,
1906 mc
->un
.value
.level
[0], NULL
);
1912 else if (target
== MI_TARGET_EAPD
) {
1913 if (mc
->un
.ord
>= 2)
1915 err
= this->comresp(this, nid
,
1916 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1920 if (mc
->un
.ord
== 0) {
1921 result
&= ~CORB_EAPD_EAPD
;
1923 result
|= CORB_EAPD_EAPD
;
1925 err
= this->comresp(this, nid
,
1926 CORB_SET_EAPD_BTL_ENABLE
, result
, &result
);
1932 else if (target
== MI_TARGET_BALANCE
) {
1933 if (mc
->un
.ord
>= 2)
1935 err
= this->comresp(this, nid
,
1936 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1940 if (mc
->un
.ord
== 0) {
1941 result
&= ~CORB_EAPD_BTL
;
1943 result
|= CORB_EAPD_BTL
;
1945 err
= this->comresp(this, nid
,
1946 CORB_SET_EAPD_BTL_ENABLE
, result
, &result
);
1952 else if (target
== MI_TARGET_LRSWAP
) {
1953 if (mc
->un
.ord
>= 2)
1955 err
= this->comresp(this, nid
,
1956 CORB_GET_EAPD_BTL_ENABLE
, 0, &result
);
1960 if (mc
->un
.ord
== 0) {
1961 result
&= ~CORB_EAPD_LRSWAP
;
1963 result
|= CORB_EAPD_LRSWAP
;
1965 err
= this->comresp(this, nid
,
1966 CORB_SET_EAPD_BTL_ENABLE
, result
, &result
);
1972 aprint_error_dev(this->dev
, "internal error in %s: target=%x\n",
1980 generic_mixer_pinctrl(codec_t
*this, nid_t nid
, uint32_t value
)
1985 err
= this->comresp(this, nid
, CORB_GET_PIN_WIDGET_CONTROL
, 0, &result
);
1988 result
&= ~(CORB_PWC_OUTPUT
| CORB_PWC_INPUT
);
1989 result
|= value
& (CORB_PWC_OUTPUT
| CORB_PWC_INPUT
);
1990 return this->comresp(this, nid
,
1991 CORB_SET_PIN_WIDGET_CONTROL
, result
, NULL
);
1995 generic_mixer_from_device_value(const codec_t
*this, nid_t nid
, int target
,
1998 #ifdef MAX_VOLUME_255
2001 if (IS_MI_TARGET_INAMP(target
))
2002 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].inamp_cap
);
2003 else if (target
== MI_TARGET_OUTAMP
)
2004 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].outamp_cap
);
2005 else if (target
== MI_TARGET_VOLUME
)
2006 dmax
= COP_VKCAP_NUMSTEPS(this->w
[nid
].d
.volume
.cap
);
2008 printf("unknown target: %d\n", target
);
2011 return dv
* MIXER_DELTA(dmax
);
2018 generic_mixer_to_device_value(const codec_t
*this, nid_t nid
, int target
,
2021 #ifdef MAX_VOLUME_255
2024 if (IS_MI_TARGET_INAMP(target
))
2025 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].inamp_cap
);
2026 else if (target
== MI_TARGET_OUTAMP
)
2027 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].outamp_cap
);
2028 else if (target
== MI_TARGET_VOLUME
)
2029 dmax
= COP_VKCAP_NUMSTEPS(this->w
[nid
].d
.volume
.cap
);
2031 printf("unknown target: %d\n", target
);
2034 return uv
/ MIXER_DELTA(dmax
);
2041 generic_mixer_max(const codec_t
*this, nid_t nid
,
2044 #ifdef MAX_VOLUME_255
2045 return AUDIO_MAX_GAIN
;
2049 if (IS_MI_TARGET_INAMP(target
))
2050 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].inamp_cap
);
2051 else if (target
== MI_TARGET_OUTAMP
)
2052 dmax
= COP_AMPCAP_NUMSTEPS(this->w
[nid
].outamp_cap
);
2053 else if (target
== MI_TARGET_VOLUME
)
2054 dmax
= COP_VKCAP_NUMSTEPS(this->w
[nid
].d
.volume
.cap
);
2060 generic_mixer_validate_value(const codec_t
*this, nid_t nid
,
2061 int target
, u_char uv
)
2063 #ifdef MAX_VOLUME_255
2066 return uv
<= generic_mixer_max(this, nid
, target
);
2071 generic_set_port(codec_t
*this, mixer_ctrl_t
*mc
)
2073 const mixer_item_t
*m
;
2075 if (mc
->dev
>= this->nmixers
)
2077 m
= &this->mixers
[mc
->dev
];
2078 if (mc
->type
!= m
->devinfo
.type
)
2080 if (mc
->type
== AUDIO_MIXER_CLASS
)
2081 return 0; /* nothing to do */
2082 return generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2086 generic_get_port(codec_t
*this, mixer_ctrl_t
*mc
)
2088 const mixer_item_t
*m
;
2090 if (mc
->dev
>= this->nmixers
)
2092 m
= &this->mixers
[mc
->dev
];
2093 mc
->type
= m
->devinfo
.type
;
2094 if (mc
->type
== AUDIO_MIXER_CLASS
)
2095 return 0; /* nothing to do */
2096 return generic_mixer_get(this, m
->nid
, m
->target
, mc
);
2100 /* ----------------------------------------------------------------
2103 * Fujitsu LOOX T70M/T
2104 * Internal Speaker: 0x10
2105 * Front Headphone: 0x14
2107 * ---------------------------------------------------------------- */
2109 #define ALC260_FUJITSU_ID 0x132610cf
2110 #define ALC260_EVENT_HP 0
2111 #define ALC260_EXTRA_MASTER 0
2112 static const mixer_item_t alc260_mixer_items
[] = {
2114 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2115 0, 0, .un
.v
={{"", 0}, 2, 3}}, 0x08, MI_TARGET_OUTAMP
}, /* and 0x09, 0x0a(mono) */
2116 {{0, {AudioNmaster
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2117 0, 0, ENUM_OFFON
}, 0x0f, MI_TARGET_OUTAMP
},
2118 {{0, {AudioNheadphone
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2119 0, 0, ENUM_OFFON
}, 0x10, MI_TARGET_OUTAMP
},
2120 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2121 0, 0, ENUM_OFFON
}, 0x10, MI_TARGET_PINBOOST
},
2122 {{0, {AudioNmono
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2123 0, 0, ENUM_OFFON
}, 0x11, MI_TARGET_OUTAMP
},
2124 {{0, {"mic1.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2125 0, 0, ENUM_OFFON
}, 0x12, MI_TARGET_OUTAMP
},
2126 {{0, {"mic1", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2127 0, 0, ENUM_IO
}, 0x12, MI_TARGET_PINDIR
},
2128 {{0, {"mic2.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2129 0, 0, ENUM_OFFON
}, 0x13, MI_TARGET_OUTAMP
},
2130 {{0, {"mic2", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2131 0, 0, ENUM_IO
}, 0x13, MI_TARGET_PINDIR
},
2132 {{0, {"line1.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2133 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
2134 {{0, {"line1", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2135 0, 0, ENUM_IO
}, 0x14, MI_TARGET_PINDIR
},
2136 {{0, {"line2.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2137 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
2138 {{0, {"line2", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2139 0, 0, ENUM_IO
}, 0x15, MI_TARGET_PINDIR
},
2141 {{0, {AudioNdac
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2142 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */
2143 {{0, {"mic1.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2144 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(0)},
2145 {{0, {"mic1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2146 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
2147 {{0, {"mic2.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2148 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(1)},
2149 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2150 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(1)},
2151 {{0, {"line1.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2152 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(2)},
2153 {{0, {"line1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2154 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(2)},
2155 {{0, {"line2.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2156 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(3)},
2157 {{0, {"line2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2158 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(3)},
2159 {{0, {AudioNcd
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2160 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(4)},
2161 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2162 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
2163 {{0, {AudioNspeaker
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2164 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(5)},
2165 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2166 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
2168 {{0, {"adc04.source", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2169 .un
.e
={5, {{{"mic1", 0}, 0}, {{"mic2", 0}, 1}, {{"line1", 0}, 2},
2170 {{"line2", 0}, 3}, {{AudioNcd
, 0}, 4}}}},
2171 0x04, MI_TARGET_CONNLIST
},
2172 {{0, {"adc04.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2173 ENUM_OFFON
}, 0x04, MI_TARGET_INAMP(0)},
2174 {{0, {"adc04", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
, 0, 0,
2175 .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
2176 {{0, {"adc05.source", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2177 .un
.e
={6, {{{"mic1", 0}, 0}, {{"mic2", 0}, 1}, {{"line1", 0}, 2},
2178 {{"line2", 0}, 3}, {{AudioNcd
, 0}, 4}, {{AudioNmixerout
, 0}, 5}}}},
2179 0x05, MI_TARGET_CONNLIST
},
2180 {{0, {"adc05.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2181 ENUM_OFFON
}, 0x05, MI_TARGET_INAMP(0)},
2182 {{0, {"adc05", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
, 0, 0,
2183 .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
2185 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
2186 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
2187 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2188 .un
.e
={3, {{{"adc04", 0}, 0}, {{"adc05", 0}, 1}, {{AzaliaNdigital
, 0}, 2}}}},
2192 static const mixer_item_t alc260_loox_mixer_items
[] = {
2195 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2196 0, 0, .un
.v
={{"", 0}, 2, 3}}, 0x08, MI_TARGET_OUTAMP
}, /* and 0x09, 0x0a(mono) */
2197 {{0, {AudioNmaster
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2198 0, 0, ENUM_OFFON
}, 0x10, MI_TARGET_OUTAMP
},
2199 {{0, {AudioNmaster
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2200 0, 0, ENUM_OFFON
}, 0x10, MI_TARGET_PINBOOST
},
2201 {{0, {AudioNheadphone
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2202 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
2203 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2204 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_PINBOOST
},
2206 {{0, {AudioNdac
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2207 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)}, /* and 0x09, 0x0a(mono) */
2208 {{0, {AudioNmicrophone
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2209 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(0)},
2210 {{0, {AudioNmicrophone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2211 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)},
2212 {{0, {AudioNcd
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2213 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(4)},
2214 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2215 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)},
2216 {{0, {AudioNspeaker
".mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2217 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(5)},
2218 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2219 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)},
2221 {{0, {"adc04.source", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2222 .un
.e
={2, {{{AudioNmicrophone
, 0}, 0}, {{AudioNcd
, 0}, 4}}}}, 0x04, MI_TARGET_CONNLIST
},
2223 {{0, {"adc04.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2224 ENUM_OFFON
}, 0x04, MI_TARGET_INAMP(0)},
2225 {{0, {"adc04", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
, 0, 0,
2226 .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)},
2227 {{0, {"adc05.source", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2228 .un
.e
={3, {{{AudioNmicrophone
, 0}, 0}, {{AudioNcd
, 0}, 4}, {{AudioNmixerout
, 0}, 5}}}},
2229 0x05, MI_TARGET_CONNLIST
},
2230 {{0, {"adc05.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2231 ENUM_OFFON
}, 0x05, MI_TARGET_INAMP(0)},
2232 {{0, {"adc05", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
, 0, 0,
2233 .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)},
2235 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
2236 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
2237 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2238 .un
.e
={3, {{{"adc04", 0}, 0}, {{"adc05", 0}, 1}, {{AzaliaNdigital
, 0}, 2}}}},
2243 alc260_mixer_init(codec_t
*this)
2245 const mixer_item_t
*mi
;
2249 switch (this->subid
) {
2250 case ALC260_FUJITSU_ID
:
2251 this->nmixers
= __arraycount(alc260_loox_mixer_items
);
2252 mi
= alc260_loox_mixer_items
;
2255 this->nmixers
= __arraycount(alc260_mixer_items
);
2256 mi
= alc260_mixer_items
;
2258 this->mixers
= malloc(sizeof(mixer_item_t
) * this->nmixers
,
2259 M_DEVBUF
, M_NOWAIT
);
2260 if (this->mixers
== NULL
) {
2261 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
2264 memcpy(this->mixers
, mi
, sizeof(mixer_item_t
) * this->nmixers
);
2265 generic_mixer_fix_indexes(this);
2266 generic_mixer_default(this);
2268 mc
.dev
= -1; /* no need for generic_mixer_set() */
2269 mc
.type
= AUDIO_MIXER_ENUM
;
2270 mc
.un
.ord
= 1; /* pindir: output */
2271 generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR
, &mc
); /* lineout */
2272 generic_mixer_set(this, 0x10, MI_TARGET_PINDIR
, &mc
); /* headphones */
2273 mc
.un
.ord
= 0; /* pindir: input */
2274 generic_mixer_set(this, 0x12, MI_TARGET_PINDIR
, &mc
); /* mic1 */
2275 generic_mixer_set(this, 0x13, MI_TARGET_PINDIR
, &mc
); /* mic2 */
2276 generic_mixer_set(this, 0x14, MI_TARGET_PINDIR
, &mc
); /* line1 */
2277 generic_mixer_set(this, 0x15, MI_TARGET_PINDIR
, &mc
); /* line2 */
2278 mc
.un
.ord
= 0; /* mute: off */
2279 generic_mixer_set(this, 0x08, MI_TARGET_INAMP(0), &mc
);
2280 generic_mixer_set(this, 0x08, MI_TARGET_INAMP(1), &mc
);
2281 generic_mixer_set(this, 0x09, MI_TARGET_INAMP(0), &mc
);
2282 generic_mixer_set(this, 0x09, MI_TARGET_INAMP(1), &mc
);
2283 generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(0), &mc
);
2284 generic_mixer_set(this, 0x0a, MI_TARGET_INAMP(1), &mc
);
2285 if (this->subid
== ALC260_FUJITSU_ID
) {
2286 mc
.un
.ord
= 1; /* pindir: output */
2287 generic_mixer_set(this, 0x14, MI_TARGET_PINDIR
, &mc
); /* line1 */
2288 mc
.un
.ord
= 4; /* connlist: cd */
2289 generic_mixer_set(this, 0x05, MI_TARGET_CONNLIST
, &mc
);
2290 /* setup a unsolicited event for the headphones */
2291 this->comresp(this, 0x14, CORB_SET_UNSOLICITED_RESPONSE
,
2292 CORB_UNSOL_ENABLE
| ALC260_EVENT_HP
, NULL
);
2293 this->extra
[ALC260_EXTRA_MASTER
] = 0; /* unmute */
2294 /* If the headphone presents, mute the internal speaker */
2295 this->comresp(this, 0x14, CORB_GET_PIN_SENSE
, 0, &value
);
2296 mc
.un
.ord
= value
& CORB_PS_PRESENCE
? 1 : 0;
2297 generic_mixer_set(this, 0x10, MI_TARGET_OUTAMP
, &mc
);
2298 this->get_port
= alc260_get_port
;
2304 alc260_init_dacgroup(codec_t
*this)
2306 static const convgroupset_t dacs
= {
2308 {{1, {0x02}}, /* analog 2ch */
2309 {1, {0x03}}}}; /* digital */
2310 static const convgroupset_t adcs
= {
2312 {{1, {0x04}}, /* analog 2ch */
2313 {1, {0x05}}, /* analog 2ch */
2314 {1, {0x06}}}}; /* digital */
2322 alc260_set_port(codec_t
*this, mixer_ctrl_t
*mc
)
2324 const mixer_item_t
*m
;
2329 if (mc
->dev
>= this->nmixers
)
2331 m
= &this->mixers
[mc
->dev
];
2332 if (mc
->type
!= m
->devinfo
.type
)
2334 if (mc
->type
== AUDIO_MIXER_CLASS
)
2336 if (m
->nid
== 0x08 && m
->target
== MI_TARGET_OUTAMP
) {
2337 DPRINTF(("%s: hook for outputs.master\n", __func__
));
2338 err
= generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2340 generic_mixer_set(this, 0x09, m
->target
, mc
);
2342 mc2
.un
.value
.num_channels
= 1;
2343 mc2
.un
.value
.level
[0] = (mc2
.un
.value
.level
[0]
2344 + mc2
.un
.value
.level
[1]) / 2;
2345 generic_mixer_set(this, 0x0a, m
->target
, &mc2
);
2348 } else if (m
->nid
== 0x08 && m
->target
== MI_TARGET_INAMP(0)) {
2349 DPRINTF(("%s: hook for inputs.dac.mute\n", __func__
));
2350 err
= generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2352 generic_mixer_set(this, 0x09, m
->target
, mc
);
2353 generic_mixer_set(this, 0x0a, m
->target
, mc
);
2356 } else if (m
->nid
== 0x04 &&
2357 m
->target
== MI_TARGET_CONNLIST
&&
2358 m
->devinfo
.un
.e
.num_mem
== 2) {
2359 if (1 <= mc
->un
.ord
&& mc
->un
.ord
<= 3)
2361 } else if (m
->nid
== 0x05 &&
2362 m
->target
== MI_TARGET_CONNLIST
&&
2363 m
->devinfo
.un
.e
.num_mem
== 3) {
2364 if (1 <= mc
->un
.ord
&& mc
->un
.ord
<= 3)
2366 } else if (this->subid
== ALC260_FUJITSU_ID
&& m
->nid
== 0x10 &&
2367 m
->target
== MI_TARGET_OUTAMP
) {
2368 if (mc
->un
.ord
!= 0 && mc
->un
.ord
!= 1)
2370 this->extra
[ALC260_EXTRA_MASTER
] = mc
->un
.ord
;
2371 err
= this->comresp(this, 0x14, CORB_GET_PIN_SENSE
, 0, &value
);
2374 if (!(value
& CORB_PS_PRESENCE
)) {
2375 return generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2379 return generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2383 alc260_get_port(codec_t
*this, mixer_ctrl_t
*mc
)
2385 const mixer_item_t
*m
;
2387 if (mc
->dev
>= this->nmixers
)
2389 m
= &this->mixers
[mc
->dev
];
2390 mc
->type
= m
->devinfo
.type
;
2391 if (mc
->type
== AUDIO_MIXER_CLASS
)
2393 if (this->subid
== ALC260_FUJITSU_ID
&& m
->nid
== 0x10 &&
2394 m
->target
== MI_TARGET_OUTAMP
) {
2395 mc
->un
.ord
= this->extra
[ALC260_EXTRA_MASTER
];
2398 return generic_mixer_get(this, m
->nid
, m
->target
, mc
);
2402 alc260_unsol_event(codec_t
*this, int tag
)
2409 case ALC260_EVENT_HP
:
2410 err
= this->comresp(this, 0x14, CORB_GET_PIN_SENSE
, 0, &value
);
2414 mc
.type
= AUDIO_MIXER_ENUM
;
2415 if (value
& CORB_PS_PRESENCE
) {
2416 DPRINTF(("%s: headphone has been inserted.\n", __func__
));
2417 mc
.un
.ord
= 1; /* mute */
2418 generic_mixer_set(this, 0x10, MI_TARGET_OUTAMP
, &mc
);
2420 DPRINTF(("%s: headphone has been pulled out.\n", __func__
));
2421 mc
.un
.ord
= this->extra
[ALC260_EXTRA_MASTER
];
2422 generic_mixer_set(this, 0x10, MI_TARGET_OUTAMP
, &mc
);
2426 printf("%s: unknown tag: %d\n", __func__
, tag
);
2431 /* ----------------------------------------------------------------
2433 * ---------------------------------------------------------------- */
2436 alc262_init_widget(const codec_t
*this, widget_t
*w
, nid_t nid
)
2440 strlcpy(w
->name
, AudioNmaster
, sizeof(w
->name
));
2447 /* ----------------------------------------------------------------
2449 * ---------------------------------------------------------------- */
2452 alc268_init_dacgroup(codec_t
*this)
2454 static const convgroupset_t dacs
= {
2456 {{2, {0x02, 0x03}}}}; /* analog 4ch */
2457 static const convgroupset_t adcs
= {
2459 {{2, {0x08, 0x07}}}}; /* analog 4ch */
2466 /* ----------------------------------------------------------------
2468 * ---------------------------------------------------------------- */
2471 alc662_init_dacgroup(codec_t
*this)
2473 static const convgroupset_t dacs
= {
2475 {{3, {0x02, 0x03, 0x04}}}}; /* analog 6ch */
2476 static const convgroupset_t adcs
= {
2478 {{2, {0x09, 0x08}}}}; /* analog 4ch */
2485 /* ----------------------------------------------------------------
2487 * ---------------------------------------------------------------- */
2490 alc861_init_dacgroup(codec_t
*this)
2492 static const convgroupset_t dacs
= {
2494 {{4, {0x03, 0x04, 0x05, 0x06}}, /* analog 8ch */
2495 {1, {0x07}}}}; /* digital */
2496 static const convgroupset_t adcs
= {
2498 {{1, {0x08}}}}; /* analog 2ch */
2505 /* ----------------------------------------------------------------
2506 * Realtek ALC861-VD-GR
2507 * ---------------------------------------------------------------- */
2510 alc861vdgr_init_dacgroup(codec_t
*this)
2512 static const convgroupset_t dacs
= {
2514 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
2515 {1, {0x06}}}}; /* digital */
2516 static const convgroupset_t adcs
= {
2518 {{1, {0x09}}}}; /* analog 2ch */
2525 /* ----------------------------------------------------------------
2527 * ---------------------------------------------------------------- */
2529 static const mixer_item_t alc880_mixer_items
[] = {
2532 {{0, {AudioNsurround
"."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2533 0, 0, .un
.e
={5, {{{"mic1", 0}, 0}, {{"mic2", 0}, 1}, {{"line1", 0}, 2},
2534 {{"line2", 0}, 3}, {{AudioNcd
, 0}, 4}}}}, 0x08, MI_TARGET_CONNLIST
},
2535 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2536 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)},
2537 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
2538 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x08, MI_TARGET_INAMP(0)},
2540 {{0, {AzaliaNfront
"."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2541 0, 0, .un
.e
={5, {{{"mic1", 0}, 0}, {{"mic2", 0}, 1}, {{"line1", 0}, 2},
2542 {{"line2", 0}, 3}, {{AudioNcd
, 0}, 4},
2543 {{AudioNmixerout
, 0}, 5}}}}, 0x09, MI_TARGET_CONNLIST
},
2544 {{0, {AzaliaNfront
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2545 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)},
2546 {{0, {AzaliaNfront
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
2547 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(35)}}, 0x09, MI_TARGET_INAMP(0)},
2549 {{0, {"mic1."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2550 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(0)},
2551 {{0, {"mic1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2552 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(0)},
2553 {{0, {"mic2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2554 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(1)},
2555 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2556 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(1)},
2557 {{0, {"line1."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2558 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(2)},
2559 {{0, {"line1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2560 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(2)},
2561 {{0, {"line2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2562 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(3)},
2563 {{0, {"line2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2564 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(3)},
2565 {{0, {AudioNcd
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2566 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(4)},
2567 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2568 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(4)},
2569 {{0, {AudioNspeaker
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2570 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(5)},
2571 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2572 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(65)}}, 0x0b, MI_TARGET_INAMP(5)},
2574 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2575 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x0c, MI_TARGET_OUTAMP
},
2576 {{0, {AzaliaNfront
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2577 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(0)},
2578 {{0, {AzaliaNfront
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2579 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(1)},
2580 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2581 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x0d, MI_TARGET_OUTAMP
},
2582 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2583 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x0e, MI_TARGET_OUTAMP
},
2584 {{0, {AzaliaNside
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2585 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x0f, MI_TARGET_OUTAMP
},
2586 #if 0 /* The followings are useless. */
2587 {{0, {AudioNsurround
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2588 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_INAMP(0)},
2589 {{0, {AudioNsurround
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2590 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_INAMP(1)},
2591 {{0, {AzaliaNclfe
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2592 0, 0, ENUM_OFFON
}, 0x0e, MI_TARGET_INAMP(0)},
2593 {{0, {AzaliaNclfe
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2594 0, 0, ENUM_OFFON
}, 0x0e, MI_TARGET_INAMP(1)},
2595 {{0, {AzaliaNside
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2596 0, 0, ENUM_OFFON
}, 0x0f, MI_TARGET_INAMP(0)},
2597 {{0, {AzaliaNside
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2598 0, 0, ENUM_OFFON
}, 0x0f, MI_TARGET_INAMP(1)},
2601 {{0, {AudioNmaster
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2602 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
2603 {{0, {AudioNmaster
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2604 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_PINBOOST
},
2605 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2606 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
2607 {{0, {AudioNsurround
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2608 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_PINBOOST
},
2609 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2610 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_OUTAMP
},
2611 {{0, {AzaliaNclfe
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2612 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_PINBOOST
},
2613 {{0, {AzaliaNside
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2614 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_OUTAMP
},
2615 {{0, {AzaliaNside
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2616 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_PINBOOST
},
2618 {{0, {"mic2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2619 0, 0, ENUM_OFFON
}, 0x19, MI_TARGET_OUTAMP
},
2620 {{0, {"mic2.boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2621 0, 0, ENUM_OFFON
}, 0x19, MI_TARGET_PINBOOST
},
2622 {{0, {"mic2.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2623 0, 0, ENUM_IO
}, 0x19, MI_TARGET_PINDIR
},
2624 {{0, {"line1."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2625 0, 0, ENUM_OFFON
}, 0x1a, MI_TARGET_OUTAMP
},
2626 {{0, {"line1.boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2627 0, 0, ENUM_OFFON
}, 0x1a, MI_TARGET_PINBOOST
},
2628 {{0, {"line1.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2629 0, 0, ENUM_IO
}, 0x1a, MI_TARGET_PINDIR
},
2630 {{0, {"line2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2631 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_OUTAMP
},
2632 {{0, {"line2.boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2633 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_PINBOOST
},
2634 {{0, {"line2.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2635 0, 0, ENUM_IO
}, 0x1b, MI_TARGET_PINDIR
},
2637 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
2638 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
2639 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2640 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_ADC
},
2644 alc880_mixer_init(codec_t
*this)
2648 this->nmixers
= __arraycount(alc880_mixer_items
);
2649 this->mixers
= malloc(sizeof(alc880_mixer_items
), M_DEVBUF
, M_NOWAIT
);
2650 if (this->mixers
== NULL
) {
2651 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
2654 memcpy(this->mixers
, alc880_mixer_items
, sizeof(alc880_mixer_items
));
2655 generic_mixer_fix_indexes(this);
2656 generic_mixer_default(this);
2659 mc
.type
= AUDIO_MIXER_ENUM
;
2660 mc
.un
.ord
= 0; /* mute: off */
2661 generic_mixer_set(this, 0x0c, MI_TARGET_INAMP(0), &mc
); /* dac->front */
2662 generic_mixer_set(this, 0x0c, MI_TARGET_INAMP(1), &mc
); /* mixer->front */
2663 generic_mixer_set(this, 0x0d, MI_TARGET_INAMP(0), &mc
); /* dac->surround */
2664 generic_mixer_set(this, 0x0e, MI_TARGET_INAMP(0), &mc
); /* dac->clfe */
2665 generic_mixer_set(this, 0x0f, MI_TARGET_INAMP(0), &mc
); /* dac->side */
2666 mc
.un
.ord
= 1; /* mute: on */
2667 generic_mixer_set(this, 0x0d, MI_TARGET_INAMP(1), &mc
); /* mixer->surround */
2668 generic_mixer_set(this, 0x0e, MI_TARGET_INAMP(1), &mc
); /* mixer->clfe */
2669 generic_mixer_set(this, 0x0f, MI_TARGET_INAMP(1), &mc
); /* mixer->side */
2670 mc
.un
.ord
= 1; /* pindir: output */
2671 generic_mixer_set(this, 0x14, MI_TARGET_PINDIR
, &mc
); /* front */
2672 generic_mixer_set(this, 0x15, MI_TARGET_PINDIR
, &mc
); /* surround */
2673 generic_mixer_set(this, 0x16, MI_TARGET_PINDIR
, &mc
); /* clfe */
2674 generic_mixer_set(this, 0x17, MI_TARGET_PINDIR
, &mc
); /* side */
2675 generic_mixer_set(this, 0x19, MI_TARGET_PINDIR
, &mc
); /* mic2 */
2676 generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR
, &mc
); /* line2 */
2677 mc
.un
.ord
= 0; /* pindir: input */
2678 generic_mixer_set(this, 0x18, MI_TARGET_PINDIR
, &mc
); /* mic1 */
2679 generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR
, &mc
); /* line1 */
2684 alc880_init_dacgroup(codec_t
*this)
2686 static const convgroupset_t dacs
= {
2688 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
2689 {1, {0x06}}}}; /* digital */
2690 static const convgroupset_t adcs
= {
2692 {{2, {0x08, 0x09}}, /* analog 4ch */
2693 {1, {0x0a}}}}; /* digital */
2700 /* ----------------------------------------------------------------
2702 * ---------------------------------------------------------------- */
2704 static const mixer_item_t alc882_mixer_items
[] = {
2707 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */
2708 {{0, {"mic1."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2709 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(0)},
2710 {{0, {"mic1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2711 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
2712 {{0, {"mic2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2713 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(1)},
2714 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2715 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
2716 {{0, {AudioNline
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2717 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(2)},
2718 {{0, {AudioNline
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2719 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
2720 {{0, {AudioNcd
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2721 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(4)},
2722 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2723 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
2724 {{0, {AudioNspeaker
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2725 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(5)},
2726 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2727 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
2729 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2730 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP
},
2731 {{0, {AudioNmaster
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2732 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
2733 {{0, {AudioNmaster
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2734 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_PINBOOST
},
2735 {{0, {AudioNheadphone
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2736 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_OUTAMP
},
2737 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2738 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_PINBOOST
},
2739 {{0, {AzaliaNfront
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2740 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(0)},
2741 {{0, {AzaliaNfront
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2742 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(1)},
2744 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2745 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP
},
2746 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2747 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
2748 {{0, {AudioNsurround
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2749 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_PINBOOST
},
2751 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2752 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP
},
2753 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2754 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_OUTAMP
},
2755 {{0, {AzaliaNclfe
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2756 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_PINBOOST
},
2758 {{0, {AzaliaNside
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
2759 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP
},
2760 {{0, {AzaliaNside
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2761 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_OUTAMP
},
2762 {{0, {AzaliaNside
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
2763 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_PINBOOST
},
2765 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17,0xb */
2766 #define ALC882_MIC1 0x001
2767 #define ALC882_MIC2 0x002
2768 #define ALC882_LINE 0x004
2769 #define ALC882_CD 0x010
2770 #define ALC882_BEEP 0x020
2771 #define ALC882_MIX 0x400
2772 #define ALC882_MASK 0x437
2773 {{0, {AzaliaNfront
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2774 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_INAMP(0)},
2775 {{0, {AzaliaNfront
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
2776 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x07, MI_TARGET_INAMP(0)},
2777 {{0, {AzaliaNfront
"."AudioNsource
, 0}, AUDIO_MIXER_SET
, AZ_CLASS_RECORD
,
2778 0, 0, .un
.s
={6, {{{"mic1", 0}, ALC882_MIC1
}, {{"mic2", 0}, ALC882_MIC2
},
2779 {{AudioNline
, 0}, ALC882_LINE
}, {{AudioNcd
, 0}, ALC882_CD
},
2780 {{AudioNspeaker
, 0}, ALC882_BEEP
},
2781 {{AudioNmixerout
, 0}, ALC882_MIX
}}}}, 0x24, -1},
2782 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2783 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)},
2784 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
2785 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
2786 {{0, {AudioNsurround
"."AudioNsource
, 0}, AUDIO_MIXER_SET
, AZ_CLASS_RECORD
,
2787 0, 0, .un
.s
={6, {{{"mic1", 0}, ALC882_MIC1
}, {{"mic2", 0}, ALC882_MIC2
},
2788 {{AudioNline
, 0}, ALC882_LINE
}, {{AudioNcd
, 0}, ALC882_CD
},
2789 {{AudioNspeaker
, 0}, ALC882_BEEP
},
2790 {{AudioNmixerout
, 0}, ALC882_MIX
}}}}, 0x23, -1},
2791 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
2792 0, 0, ENUM_OFFON
}, 0x09, MI_TARGET_INAMP(0)},
2793 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
2794 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
2795 {{0, {AzaliaNclfe
"."AudioNsource
, 0}, AUDIO_MIXER_SET
, AZ_CLASS_RECORD
,
2796 0, 0, .un
.s
={6, {{{"mic1", 0}, ALC882_MIC1
}, {{"mic2", 0}, ALC882_MIC2
},
2797 {{AudioNline
, 0}, ALC882_LINE
}, {{AudioNcd
, 0}, ALC882_CD
},
2798 {{AudioNspeaker
, 0}, ALC882_BEEP
},
2799 {{AudioNmixerout
, 0}, ALC882_MIX
}}}}, 0x22, -1},
2801 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
2802 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
2803 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
2804 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_ADC
},
2805 /* AZ_MIXER_SPDIF(AZ_CLASS_PLAYBACK, 0x06),*/
2809 alc882_mixer_init(codec_t
*this)
2813 this->nmixers
= __arraycount(alc882_mixer_items
);
2814 this->mixers
= malloc(sizeof(alc882_mixer_items
), M_DEVBUF
, M_NOWAIT
);
2815 if (this->mixers
== NULL
) {
2816 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
2819 memcpy(this->mixers
, alc882_mixer_items
, sizeof(alc882_mixer_items
));
2820 generic_mixer_fix_indexes(this);
2821 generic_mixer_default(this);
2824 mc
.type
= AUDIO_MIXER_ENUM
;
2825 mc
.un
.ord
= 1; /* pindir: output */
2826 generic_mixer_set(this, 0x14, MI_TARGET_PINDIR
, &mc
);
2827 generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR
, &mc
);
2828 generic_mixer_set(this, 0x15, MI_TARGET_PINDIR
, &mc
);
2829 generic_mixer_set(this, 0x16, MI_TARGET_PINDIR
, &mc
);
2830 generic_mixer_set(this, 0x17, MI_TARGET_PINDIR
, &mc
);
2831 mc
.un
.ord
= 0; /* [0] 0x0c */
2832 generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST
, &mc
);
2833 generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST
, &mc
);
2834 mc
.un
.ord
= 1; /* [1] 0x0d */
2835 generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST
, &mc
);
2836 mc
.un
.ord
= 2; /* [2] 0x0e */
2837 generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST
, &mc
);
2838 mc
.un
.ord
= 2; /* [3] 0x0fb */
2839 generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST
, &mc
);
2841 mc
.un
.ord
= 0; /* pindir: input */
2842 generic_mixer_set(this, 0x18, MI_TARGET_PINDIR
, &mc
);
2843 generic_mixer_set(this, 0x19, MI_TARGET_PINDIR
, &mc
);
2844 generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR
, &mc
);
2845 /* XXX: inamp for 18/19/1a */
2847 mc
.un
.ord
= 0; /* unmute */
2848 generic_mixer_set(this, 0x24, MI_TARGET_INAMP(0), &mc
);
2849 generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc
);
2850 generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc
);
2851 generic_mixer_set(this, 0x0d, MI_TARGET_INAMP(0), &mc
);
2852 generic_mixer_set(this, 0x0e, MI_TARGET_INAMP(0), &mc
);
2853 generic_mixer_set(this, 0x0f, MI_TARGET_INAMP(0), &mc
);
2854 mc
.un
.ord
= 1; /* mute */
2855 generic_mixer_set(this, 0x0d, MI_TARGET_INAMP(1), &mc
);
2856 generic_mixer_set(this, 0x0e, MI_TARGET_INAMP(1), &mc
);
2857 generic_mixer_set(this, 0x0f, MI_TARGET_INAMP(1), &mc
);
2862 alc882_init_dacgroup(codec_t
*this)
2864 #if 0 /* makes no sense to support for 0x25 node */
2865 static const convgroupset_t dacs
= {
2867 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
2868 {1, {0x06}}, /* digital */
2869 {1, {0x25}}}}; /* another analog */
2871 static const convgroupset_t dacs
= {
2873 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
2874 {1, {0x06}}}}; /* digital */
2876 static const convgroupset_t adcs
= {
2878 {{3, {0x07, 0x08, 0x09}}, /* analog 6ch */
2879 {1, {0x0a}}}}; /* digital */
2887 alc882_set_port(codec_t
*this, mixer_ctrl_t
*mc
)
2889 const mixer_item_t
*m
;
2894 if (mc
->dev
>= this->nmixers
)
2896 m
= &this->mixers
[mc
->dev
];
2897 if (mc
->type
!= m
->devinfo
.type
)
2899 if (mc
->type
== AUDIO_MIXER_CLASS
)
2901 if ((m
->nid
== 0x22 || m
->nid
== 0x23 || m
->nid
== 0x24)
2902 && m
->target
== -1) {
2903 DPRINTF(("%s: hook for record.*.source\n", __func__
));
2905 mc2
.type
= AUDIO_MIXER_ENUM
;
2907 mask
= mc
->un
.mask
& ALC882_MASK
;
2908 for (i
= 0; i
< this->w
[m
->nid
].nconnections
&& i
< 32; i
++) {
2909 mc2
.un
.ord
= (mask
& bit
) ? 0 : 1;
2910 err
= generic_mixer_set(this, m
->nid
,
2911 MI_TARGET_INAMP(i
), &mc2
);
2918 return generic_mixer_set(this, m
->nid
, m
->target
, mc
);
2922 alc882_get_port(codec_t
*this, mixer_ctrl_t
*mc
)
2924 const mixer_item_t
*m
;
2925 uint32_t mask
, bit
, result
;
2928 if (mc
->dev
>= this->nmixers
)
2930 m
= &this->mixers
[mc
->dev
];
2931 mc
->type
= m
->devinfo
.type
;
2932 if (mc
->type
== AUDIO_MIXER_CLASS
)
2934 if ((m
->nid
== 0x22 || m
->nid
== 0x23 || m
->nid
== 0x24)
2935 && m
->target
== -1) {
2936 DPRINTF(("%s: hook for record.*.source\n", __func__
));
2939 for (i
= 0; i
< this->w
[m
->nid
].nconnections
&& i
< 32; i
++) {
2940 err
= this->comresp(this, m
->nid
, CORB_GET_AMPLIFIER_GAIN_MUTE
,
2941 CORB_GAGM_INPUT
| CORB_GAGM_LEFT
|
2945 if ((result
& CORB_GAGM_MUTE
) == 0)
2949 mc
->un
.mask
= mask
& ALC882_MASK
;
2952 return generic_mixer_get(this, m
->nid
, m
->target
, mc
);
2955 /* ----------------------------------------------------------------
2957 * ALC882 without adc07 and mix24.
2958 * ---------------------------------------------------------------- */
2961 alc883_init_dacgroup(codec_t
*this)
2963 static const convgroupset_t dacs
= {
2965 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
2966 {1, {0x06}}}}; /* digital */
2967 /* don't support for 0x25 dac */
2968 static const convgroupset_t adcs
= {
2970 {{2, {0x08, 0x09}}, /* analog 4ch */
2971 {1, {0x0a}}}}; /* digital */
2978 static const mixer_item_t alc883_mixer_items
[] = {
2981 /* 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x14,0x15,0x16,0x17 */
2982 {{0, {"mic1."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2983 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(0)},
2984 {{0, {"mic1", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2985 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(0)},
2986 {{0, {"mic2."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2987 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(1)},
2988 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2989 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(1)},
2990 {{0, {AudioNline
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2991 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(2)},
2992 {{0, {AudioNline
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2993 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(2)},
2994 {{0, {AudioNcd
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2995 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(4)},
2996 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
2997 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(4)},
2998 {{0, {AudioNspeaker
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
2999 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_INAMP(5)},
3000 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3001 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_INAMP(5)},
3003 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3004 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0c, MI_TARGET_OUTAMP
},
3005 {{0, {AudioNmaster
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3006 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
3007 {{0, {AudioNmaster
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3008 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_PINBOOST
},
3009 {{0, {AudioNheadphone
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3010 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_OUTAMP
},
3011 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3012 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_PINBOOST
},
3013 {{0, {AzaliaNfront
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3014 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(0)},
3015 {{0, {AzaliaNfront
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3016 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_INAMP(1)},
3017 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3018 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0d, MI_TARGET_OUTAMP
},
3019 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3020 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
3021 {{0, {AudioNsurround
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3022 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_PINBOOST
},
3023 {{0, {AudioNsurround
".dac.mut", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3024 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_INAMP(0)},
3025 {{0, {AudioNsurround
".mixer.m", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3026 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_INAMP(1)},
3028 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3029 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0e, MI_TARGET_OUTAMP
},
3030 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3031 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_OUTAMP
},
3032 {{0, {AzaliaNclfe
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3033 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_PINBOOST
},
3034 {{0, {AzaliaNclfe
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3035 0, 0, ENUM_OFFON
}, 0x0e, MI_TARGET_INAMP(0)},
3036 {{0, {AzaliaNclfe
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3037 0, 0, ENUM_OFFON
}, 0x0e, MI_TARGET_INAMP(1)},
3039 {{0, {AzaliaNside
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3040 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0f, MI_TARGET_OUTAMP
},
3041 {{0, {AzaliaNside
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3042 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_OUTAMP
},
3043 {{0, {AzaliaNside
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3044 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_PINBOOST
},
3045 {{0, {AzaliaNside
".dac.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3046 0, 0, ENUM_OFFON
}, 0x0f, MI_TARGET_INAMP(0)},
3047 {{0, {AzaliaNside
".mixer.mute", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3048 0, 0, ENUM_OFFON
}, 0x0f, MI_TARGET_INAMP(1)},
3050 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3051 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)},
3052 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3053 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x08, MI_TARGET_INAMP(0)},
3054 {{0, {AudioNsurround
"."AudioNsource
, 0}, AUDIO_MIXER_SET
, AZ_CLASS_RECORD
,
3055 0, 0, .un
.s
={6, {{{"mic1", 0}, ALC882_MIC1
}, {{"mic2", 0}, ALC882_MIC2
},
3056 {{AudioNline
, 0}, ALC882_LINE
}, {{AudioNcd
, 0}, ALC882_CD
},
3057 {{AudioNspeaker
, 0}, ALC882_BEEP
},
3058 {{AudioNmixerout
, 0}, ALC882_MIX
}}}}, 0x23, -1},
3060 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3061 0, 0, ENUM_OFFON
}, 0x09, MI_TARGET_INAMP(0)},
3062 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3063 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x09, MI_TARGET_INAMP(0)},
3064 {{0, {AzaliaNclfe
"."AudioNsource
, 0}, AUDIO_MIXER_SET
, AZ_CLASS_RECORD
,
3065 0, 0, .un
.s
={6, {{{"mic1", 0}, ALC882_MIC1
}, {{"mic2", 0}, ALC882_MIC2
},
3066 {{AudioNline
, 0}, ALC882_LINE
}, {{AudioNcd
, 0}, ALC882_CD
},
3067 {{AudioNspeaker
, 0}, ALC882_BEEP
},
3068 {{AudioNmixerout
, 0}, ALC882_MIX
}}}}, 0x22, -1},
3070 {{0, {"usingdac", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
, 0, 0,
3071 .un
.e
={2, {{{"analog", 0}, 0}, {{"digital", 0}, 1}}}}, 0, MI_TARGET_DAC
},
3072 {{0, {"usingadc", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
, 0, 0,
3073 .un
.e
={2, {{{"analog", 0}, 0}, {{"digital", 0}, 1}}}}, 0, MI_TARGET_ADC
},
3077 alc883_mixer_init(codec_t
*this)
3081 this->nmixers
= __arraycount(alc883_mixer_items
);
3082 this->mixers
= malloc(sizeof(alc883_mixer_items
), M_DEVBUF
, M_NOWAIT
);
3083 if (this->mixers
== NULL
) {
3084 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
3087 memcpy(this->mixers
, alc883_mixer_items
, sizeof(alc883_mixer_items
));
3088 generic_mixer_fix_indexes(this);
3089 generic_mixer_default(this);
3092 mc
.type
= AUDIO_MIXER_ENUM
;
3093 mc
.un
.ord
= 1; /* pindir: output */
3094 generic_mixer_set(this, 0x14, MI_TARGET_PINDIR
, &mc
);
3095 generic_mixer_set(this, 0x1b, MI_TARGET_PINDIR
, &mc
);
3096 generic_mixer_set(this, 0x15, MI_TARGET_PINDIR
, &mc
);
3097 generic_mixer_set(this, 0x16, MI_TARGET_PINDIR
, &mc
);
3098 generic_mixer_set(this, 0x17, MI_TARGET_PINDIR
, &mc
);
3099 mc
.un
.ord
= 0; /* [0] 0x0c */
3100 generic_mixer_set(this, 0x14, MI_TARGET_CONNLIST
, &mc
);
3101 generic_mixer_set(this, 0x1b, MI_TARGET_CONNLIST
, &mc
);
3102 mc
.un
.ord
= 1; /* [1] 0x0d */
3103 generic_mixer_set(this, 0x15, MI_TARGET_CONNLIST
, &mc
);
3104 mc
.un
.ord
= 2; /* [2] 0x0e */
3105 generic_mixer_set(this, 0x16, MI_TARGET_CONNLIST
, &mc
);
3106 mc
.un
.ord
= 2; /* [3] 0x0fb */
3107 generic_mixer_set(this, 0x17, MI_TARGET_CONNLIST
, &mc
);
3109 mc
.un
.ord
= 0; /* pindir: input */
3110 generic_mixer_set(this, 0x18, MI_TARGET_PINDIR
, &mc
);
3111 generic_mixer_set(this, 0x19, MI_TARGET_PINDIR
, &mc
);
3112 generic_mixer_set(this, 0x1a, MI_TARGET_PINDIR
, &mc
);
3113 /* XXX: inamp for 18/19/1a */
3115 mc
.un
.ord
= 0; /* unmute */
3116 generic_mixer_set(this, 0x23, MI_TARGET_INAMP(1), &mc
);
3117 generic_mixer_set(this, 0x22, MI_TARGET_INAMP(2), &mc
);
3120 /* ----------------------------------------------------------------
3122 * ---------------------------------------------------------------- */
3125 alc885_init_dacgroup(codec_t
*this)
3127 static const convgroupset_t dacs
= {
3129 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
3130 {1, {0x06}}}}; /* digital */
3131 /* don't support for 0x25 dac */
3132 static const convgroupset_t adcs
= {
3134 {{3, {0x07, 0x08, 0x09}}, /* analog 6ch */
3135 {1, {0x0a}}}}; /* digital */
3142 /* ----------------------------------------------------------------
3144 * ---------------------------------------------------------------- */
3147 alc888_init_dacgroup(codec_t
*this)
3149 static const convgroupset_t dacs
= {
3151 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
3152 {1, {0x06}}}}; /* digital */
3153 /* don't support for 0x25 dac */
3154 /* ALC888S has another SPDIF-out 0x10 */
3155 static const convgroupset_t adcs
= {
3157 {{2, {0x08, 0x09}}, /* analog 4ch */
3158 {1, {0x0a}}}}; /* digital */
3166 alc888_init_widget(const codec_t
*this, widget_t
*w
, nid_t nid
)
3170 strlcpy(w
->name
, AudioNmaster
, sizeof(w
->name
));
3177 alc888_mixer_init(codec_t
*this)
3179 mixer_item_t
*m
, *mdac
= NULL
;
3183 err
= generic_mixer_init(this);
3187 /* Clear mixer indexes, to make generic_mixer_fix_indexes happy */
3188 for (i
= 0; i
< this->nmixers
; i
++) {
3189 d
= &this->mixers
[i
].devinfo
;
3190 d
->index
= d
->prev
= d
->next
= 0;
3193 /* We're looking for front l/r mixer, which we know is nid 0x0c */
3194 for (i
= 0; i
< this->nmixers
; i
++)
3195 if (this->mixers
[i
].nid
== 0x0c) {
3196 mdac
= &this->mixers
[i
];
3201 * ALC888 doesn't have a master mixer, so create a fake
3202 * inputs.dac that mirrors outputs.master
3204 err
= generic_mixer_ensure_capacity(this, this->nmixers
+ 1);
3208 m
= &this->mixers
[this->nmixers
];
3210 memcpy(m
, mdac
, sizeof(*m
));
3211 d
->mixer_class
= AZ_CLASS_INPUT
;
3212 snprintf(d
->label
.name
, sizeof(d
->label
.name
), AudioNdac
);
3216 /* Recreate mixer indexes and defaults after making a mess of things */
3217 generic_mixer_fix_indexes(this);
3218 generic_mixer_default(this);
3223 /* ----------------------------------------------------------------
3224 * Analog Devices AD1981HD
3225 * ---------------------------------------------------------------- */
3227 #define AD1981HD_THINKPAD 0x201017aa
3229 static const mixer_item_t ad1981hd_mixer_items
[] = {
3232 {{0, {AzaliaNdigital
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3233 0, 0, .un
.e
={2, {{{"os", 0}, 0}, {{"adc", 0}, 1}}}}, 0x02, MI_TARGET_CONNLIST
},
3235 {{0, {"lineout." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3236 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3237 0x05, MI_TARGET_CONNLIST
},
3238 {{0, {"lineout." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3239 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_OUTAMP
},
3240 {{0, {"lineout", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3241 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(63)}}, 0x05, MI_TARGET_OUTAMP
},
3242 {{0, {"lineout", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3243 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(3)}}, 0x05, MI_TARGET_INAMP(0)},
3244 {{0, {"lineout.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3245 0, 0, ENUM_IO
}, 0x05, MI_TARGET_PINDIR
},
3246 {{0, {"lineout.boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3247 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_PINBOOST
},
3248 {{0, {"lineout.eapd", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3249 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_EAPD
},
3251 {{0, {AudioNheadphone
".src", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3252 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3253 0x06, MI_TARGET_CONNLIST
},
3254 {{0, {AudioNheadphone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3255 0, 0, ENUM_OFFON
}, 0x06, MI_TARGET_OUTAMP
},
3256 {{0, {AudioNheadphone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3257 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(63)}}, 0x06, MI_TARGET_OUTAMP
},
3258 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3259 0, 0, ENUM_OFFON
}, 0x06, MI_TARGET_PINBOOST
},
3261 {{0, {AudioNmono
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3262 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_OUTAMP
},
3263 {{0, {AudioNmono
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3264 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(63)}}, 0x07, MI_TARGET_OUTAMP
},
3266 {{0, {AudioNmicrophone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3267 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(3)}}, 0x08, MI_TARGET_INAMP(0)},
3269 {{0, {"linein." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3270 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3271 0x09, MI_TARGET_CONNLIST
},
3272 {{0, {"linein." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3273 0, 0, ENUM_OFFON
}, 0x09, MI_TARGET_OUTAMP
},
3274 {{0, {"linein", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3275 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(63)}}, 0x09, MI_TARGET_OUTAMP
},
3276 {{0, {"linein", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3277 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(3)}}, 0x09, MI_TARGET_INAMP(0)},
3278 {{0, {"linein.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3279 0, 0, ENUM_IO
}, 0x09, MI_TARGET_PINDIR
},
3281 {{0, {AudioNmono
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3282 0, 0, .un
.e
={6, {{{AudioNdac
, 0}, 0}, {{"mixedmic", 0}, 1},
3283 {{"linein", 0}, 2}, {{AudioNmixerout
, 0}, 3},
3284 {{"lineout", 0}, 4}, {{"mic2", 0}, 5}}}},
3285 0x0b, MI_TARGET_CONNLIST
},
3287 {{0, {"beep." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3288 0, 0, .un
.e
={2, {{{"digitalbeep", 0}, 0}, {{"beep", 0}, 1}}}},
3289 0x0d, MI_TARGET_CONNLIST
},
3290 {{0, {"beep." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3291 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_OUTAMP
},
3292 {{0, {"beep", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3293 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(15)}}, 0x0d, MI_TARGET_OUTAMP
},
3295 {{0, {AudioNdac
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3296 0, 0, ENUM_OFFON
}, 0x11, MI_TARGET_OUTAMP
},
3297 {{0, {AudioNdac
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3298 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP
},
3300 {{0, {AudioNmicrophone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3301 0, 0, ENUM_OFFON
}, 0x12, MI_TARGET_OUTAMP
},
3302 {{0, {AudioNmicrophone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3303 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x12, MI_TARGET_OUTAMP
},
3305 {{0, {"linein." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3306 0, 0, ENUM_OFFON
}, 0x13, MI_TARGET_OUTAMP
},
3307 {{0, {"linein", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3308 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x13, MI_TARGET_OUTAMP
},
3310 {{0, {AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3311 0, 0, .un
.e
={8, {{{"mixedmic", 0}, 0}, {{"linein", 0}, 1},
3312 {{AudioNmixerout
, 0}, 2}, {{AudioNmono
, 0}, 3},
3313 {{AudioNcd
, 0}, 4}, {{"lineout", 0}, 5},
3314 {{"mic2", 0}, 6}, {{AudioNaux
, 0}, 7}}}},
3315 0x15, MI_TARGET_CONNLIST
},
3316 {{0, {AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3317 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
3318 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3319 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(15)}}, 0x15, MI_TARGET_OUTAMP
},
3321 {{0, {"mic2." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3322 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3323 0x18, MI_TARGET_CONNLIST
},
3324 {{0, {"mic2." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3325 0, 0, ENUM_OFFON
}, 0x18, MI_TARGET_OUTAMP
},
3326 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3327 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(63)}}, 0x18, MI_TARGET_OUTAMP
},
3328 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3329 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(3)}}, 0x18, MI_TARGET_INAMP(0)},
3330 {{0, {"mic2.dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3331 0, 0, ENUM_IO
}, 0x18, MI_TARGET_PINDIR
},
3333 {{0, {"lineout." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3334 0, 0, ENUM_OFFON
}, 0x1a, MI_TARGET_OUTAMP
},
3335 {{0, {"lineout", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3336 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1a, MI_TARGET_OUTAMP
},
3338 {{0, {AudioNaux
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3339 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_OUTAMP
},
3340 {{0, {AudioNaux
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3341 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1b, MI_TARGET_OUTAMP
},
3343 {{0, {"mic2." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3344 0, 0, ENUM_OFFON
}, 0x1c, MI_TARGET_OUTAMP
},
3345 {{0, {"mic2", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3346 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1c, MI_TARGET_OUTAMP
},
3348 {{0, {AudioNcd
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3349 0, 0, ENUM_OFFON
}, 0x1d, MI_TARGET_OUTAMP
},
3350 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3351 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1d, MI_TARGET_OUTAMP
},
3353 {{0, {"mixedmic.mute1", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3354 0, 0, ENUM_OFFON
}, 0x1e, MI_TARGET_OUTAMP
},
3355 {{0, {"mixedmic.mute2", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3356 0, 0, ENUM_OFFON
}, 0x1f, MI_TARGET_OUTAMP
},
3358 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
3359 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
3363 ad1981hd_init_widget(const codec_t
*this, widget_t
*w
, nid_t nid
)
3367 strlcpy(w
->name
, AudioNline
"out", sizeof(w
->name
));
3370 strlcpy(w
->name
, "hp", sizeof(w
->name
));
3373 strlcpy(w
->name
, AudioNmono
, sizeof(w
->name
));
3376 strlcpy(w
->name
, AudioNmicrophone
, sizeof(w
->name
));
3379 strlcpy(w
->name
, AudioNline
"in", sizeof(w
->name
));
3382 strlcpy(w
->name
, "beep", sizeof(w
->name
));
3385 strlcpy(w
->name
, AudioNaux
, sizeof(w
->name
));
3388 strlcpy(w
->name
, AudioNmicrophone
"2", sizeof(w
->name
));
3391 strlcpy(w
->name
, AudioNcd
, sizeof(w
->name
));
3394 strlcpy(w
->name
, AudioNcd
, sizeof(w
->name
));
3401 ad1981hd_mixer_init(codec_t
*this)
3405 this->nmixers
= __arraycount(ad1981hd_mixer_items
);
3406 this->mixers
= malloc(sizeof(ad1981hd_mixer_items
), M_DEVBUF
, M_NOWAIT
);
3407 if (this->mixers
== NULL
) {
3408 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
3411 memcpy(this->mixers
, ad1981hd_mixer_items
, sizeof(ad1981hd_mixer_items
));
3412 generic_mixer_fix_indexes(this);
3413 generic_mixer_default(this);
3415 if (this->subid
== AD1981HD_THINKPAD
) {
3417 mc
.type
= AUDIO_MIXER_ENUM
;
3419 generic_mixer_set(this, 0x09, MI_TARGET_PINDIR
, &mc
);
3420 generic_mixer_set(this, 0x05, MI_TARGET_EAPD
, &mc
);
3421 mc
.type
= AUDIO_MIXER_VALUE
;
3422 mc
.un
.value
.num_channels
= 2;
3423 mc
.un
.value
.level
[0] = AUDIO_MAX_GAIN
;
3424 mc
.un
.value
.level
[1] = AUDIO_MAX_GAIN
;
3425 generic_mixer_set(this, 0x1a, MI_TARGET_VOLUME
, &mc
);
3430 /* ----------------------------------------------------------------
3431 * Analog Devices AD1983
3432 * ---------------------------------------------------------------- */
3434 static const mixer_item_t ad1983_mixer_items
[] = {
3437 {{0, {AzaliaNdigital
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3438 0, 0, .un
.e
={2, {{{"os", 0}, 0}, {{"adc", 0}, 1}}}}, 0x02, MI_TARGET_CONNLIST
},
3440 {{0, {AudioNspeaker
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3441 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3442 0x05, MI_TARGET_CONNLIST
},
3443 {{0, {AudioNspeaker
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3444 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_OUTAMP
},
3445 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3446 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x05, MI_TARGET_OUTAMP
},
3448 {{0, {AudioNheadphone
".src", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3449 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3450 0x06, MI_TARGET_CONNLIST
},
3451 {{0, {AudioNheadphone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3452 0, 0, ENUM_OFFON
}, 0x06, MI_TARGET_OUTAMP
},
3453 {{0, {AudioNheadphone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3454 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(64)}}, 0x06, MI_TARGET_OUTAMP
},
3455 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3456 0, 0, ENUM_OFFON
}, 0x06, MI_TARGET_PINBOOST
},
3458 {{0, {AudioNmono
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3459 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_OUTAMP
},
3460 {{0, {AudioNmono
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3461 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(64)}}, 0x07, MI_TARGET_OUTAMP
},
3463 {{0, {AudioNmono
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3464 0, 0, .un
.e
={4, {{{AudioNdac
, 0}, 0}, {{AudioNmicrophone
, 0}, 1},
3465 {{AudioNline
, 0}, 2}, {{AudioNmixerout
, 0}, 3}}}},
3466 0x0b, MI_TARGET_CONNLIST
},
3468 {{0, {AudioNmicrophone
"." AudioNpreamp
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3469 0, 0, ENUM_OFFON
}, 0x0c, MI_TARGET_OUTAMP
},
3470 {{0, {AudioNmicrophone
"." AudioNpreamp
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3471 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(4)}}, 0x0c, MI_TARGET_OUTAMP
},
3472 {{0, {AudioNmicrophone
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3473 0, 0, .un
.e
={2, {{{AudioNmicrophone
, 0}, 0}, {{AudioNline
, 0}, 1}}}},
3474 0x0c, MI_TARGET_CONNLIST
},
3476 {{0, {AudioNline
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3477 0, 0, .un
.e
={2, {{{AudioNline
, 0}, 0}, {{AudioNmicrophone
, 0}, 1}}}},
3478 0x0d, MI_TARGET_CONNLIST
},
3480 {{0, {"beep." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3481 0, 0, ENUM_OFFON
}, 0x10, MI_TARGET_OUTAMP
},
3482 {{0, {"beep", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3483 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(16)}}, 0x10, MI_TARGET_OUTAMP
},
3485 {{0, {AudioNdac
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3486 0, 0, ENUM_OFFON
}, 0x11, MI_TARGET_OUTAMP
},
3487 {{0, {AudioNdac
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3488 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(32)}}, 0x11, MI_TARGET_OUTAMP
},
3490 {{0, {AudioNmicrophone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3491 0, 0, ENUM_OFFON
}, 0x12, MI_TARGET_OUTAMP
},
3492 {{0, {AudioNmicrophone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3493 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(32)}}, 0x12, MI_TARGET_OUTAMP
},
3495 {{0, {AudioNline
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3496 0, 0, ENUM_OFFON
}, 0x13, MI_TARGET_OUTAMP
},
3497 {{0, {AudioNline
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3498 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(32)}}, 0x13, MI_TARGET_OUTAMP
},
3500 {{0, {AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3501 0, 0, .un
.e
={4, {{{AudioNmicrophone
, 0}, 0}, {{AudioNline
, 0}, 1},
3502 {{AudioNmixerout
, 0}, 2}, {{AudioNmono
, 0}, 3}}}},
3503 0x14, MI_TARGET_CONNLIST
},
3504 {{0, {AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3505 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
3506 {{0, {AudioNvolume
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3507 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(16)}}, 0x14, MI_TARGET_OUTAMP
},
3509 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
3510 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
3514 ad1983_mixer_init(codec_t
*this)
3518 this->nmixers
= __arraycount(ad1983_mixer_items
);
3519 this->mixers
= malloc(sizeof(ad1983_mixer_items
), M_DEVBUF
, M_NOWAIT
);
3520 if (this->mixers
== NULL
) {
3521 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
3524 memcpy(this->mixers
, ad1983_mixer_items
, sizeof(ad1983_mixer_items
));
3525 generic_mixer_fix_indexes(this);
3526 generic_mixer_default(this);
3528 #define AD198X_EVENT_HP 1
3529 #define AD198X_EVENT_SPEAKER 2
3531 mc
.dev
= -1; /* no need for generic_mixer_set() */
3532 mc
.type
= AUDIO_MIXER_ENUM
;
3533 mc
.un
.ord
= 1; /* connlist: mixerout */
3534 generic_mixer_set(this, 0x05, MI_TARGET_CONNLIST
, &mc
);
3535 generic_mixer_set(this, 0x06, MI_TARGET_CONNLIST
, &mc
);
3536 mc
.un
.ord
= 3; /* connlist: mixerout */
3537 generic_mixer_set(this, 0x0b, MI_TARGET_CONNLIST
, &mc
);
3539 /* setup a unsolicited event for the headphones and speaker */
3540 this->comresp(this, 0x05, CORB_SET_UNSOLICITED_RESPONSE
,
3541 CORB_UNSOL_ENABLE
| AD198X_EVENT_SPEAKER
, NULL
);
3542 this->comresp(this, 0x06, CORB_SET_UNSOLICITED_RESPONSE
,
3543 CORB_UNSOL_ENABLE
| AD198X_EVENT_HP
, NULL
);
3544 ad1983_unsol_event(this, AD198X_EVENT_SPEAKER
);
3545 ad1983_unsol_event(this, AD198X_EVENT_HP
);
3550 ad1983_unsol_event(codec_t
*this, int tag
)
3557 mc
.type
= AUDIO_MIXER_ENUM
;
3560 case AD198X_EVENT_HP
:
3561 err
= this->comresp(this, 0x06, CORB_GET_PIN_SENSE
, 0, &value
);
3564 if (value
& CORB_PS_PRESENCE
) {
3565 DPRINTF(("%s: headphone has been inserted.\n", __func__
));
3566 mc
.un
.ord
= 1; /* mute */
3567 generic_mixer_set(this, 0x05, MI_TARGET_OUTAMP
, &mc
);
3568 generic_mixer_set(this, 0x07, MI_TARGET_OUTAMP
, &mc
);
3570 DPRINTF(("%s: headphone has been pulled out.\n", __func__
));
3571 mc
.un
.ord
= 0; /* unmute */
3572 generic_mixer_set(this, 0x05, MI_TARGET_OUTAMP
, &mc
);
3573 /* if no speaker unmute internal mono */
3574 err
= this->comresp(this, 0x05, CORB_GET_PIN_SENSE
, 0, &value
);
3577 if (!(value
& CORB_PS_PRESENCE
))
3578 generic_mixer_set(this, 0x07, MI_TARGET_OUTAMP
, &mc
);
3581 case AD198X_EVENT_SPEAKER
:
3582 err
= this->comresp(this, 0x05, CORB_GET_PIN_SENSE
, 0, &value
);
3585 if (value
& CORB_PS_PRESENCE
) {
3586 DPRINTF(("%s: speaker has been inserted.\n", __func__
));
3587 mc
.un
.ord
= 1; /* mute */
3588 generic_mixer_set(this, 0x07, MI_TARGET_OUTAMP
, &mc
);
3590 DPRINTF(("%s: speaker has been pulled out.\n", __func__
));
3591 /* if no headphones unmute internal mono */
3592 err
= this->comresp(this, 0x06, CORB_GET_PIN_SENSE
, 0, &value
);
3595 if (!(value
& CORB_PS_PRESENCE
)) {
3596 mc
.un
.ord
= 0; /* unmute */
3597 generic_mixer_set(this, 0x07, MI_TARGET_OUTAMP
, &mc
);
3602 printf("%s: unknown tag: %d\n", __func__
, tag
);
3607 /* ----------------------------------------------------------------
3608 * Analog Devices AD1984
3609 * ---------------------------------------------------------------- */
3611 #define AD1984_THINKPAD 0x20ac17aa
3612 #define AD1984_DELL_OPTIPLEX_755 0x02111028
3613 #define AD1984A_DELL_OPTIPLEX_760 0x027f1028
3616 ad1984_init_dacgroup(codec_t
*this)
3618 static const convgroupset_t dacs
= {
3620 {{2, {0x04, 0x03}}, /* analog 4ch */
3621 {1, {0x02}}}}; /* digital */
3622 static const convgroupset_t adcs
= {
3624 {{2, {0x08, 0x09}}, /* analog 4ch */
3625 {1, {0x06}}, /* digital */
3626 {1, {0x05}}}}; /* digital */
3633 ad1984_mixer_init(codec_t
*this)
3637 err
= generic_mixer_autoinit(this);
3641 if (this->subid
== AD1984_DELL_OPTIPLEX_755
||
3642 this->subid
== AD1984A_DELL_OPTIPLEX_760
) {
3643 /* setup a unsolicited event for the headphones and speaker */
3644 this->comresp(this, 0x12, CORB_SET_UNSOLICITED_RESPONSE
,
3645 CORB_UNSOL_ENABLE
| AD198X_EVENT_SPEAKER
, NULL
);
3646 this->comresp(this, 0x11, CORB_SET_UNSOLICITED_RESPONSE
,
3647 CORB_UNSOL_ENABLE
| AD198X_EVENT_HP
, NULL
);
3648 ad1984_unsol_event(this, AD198X_EVENT_SPEAKER
);
3649 ad1984_unsol_event(this, AD198X_EVENT_HP
);
3656 ad1984_init_widget(const codec_t
*this, widget_t
*w
, nid_t nid
)
3660 strlcpy(w
->name
, "hp", sizeof(w
->name
));
3663 strlcpy(w
->name
, "spkr", sizeof(w
->name
));
3666 strlcpy(w
->name
, AudioNaux
, sizeof(w
->name
));
3669 strlcpy(w
->name
, "adc08", sizeof(w
->name
));
3672 strlcpy(w
->name
, "adc09", sizeof(w
->name
));
3675 strlcpy(w
->name
, AudioNmono
"sel", sizeof(w
->name
));
3678 strlcpy(w
->name
, AudioNaux
"sel", sizeof(w
->name
));
3681 strlcpy(w
->name
, "beep", sizeof(w
->name
));
3684 strlcpy(w
->name
, AudioNmono
, sizeof(w
->name
));
3687 strlcpy(w
->name
, "hp" "sel", sizeof(w
->name
));
3690 strlcpy(w
->name
, "dock" "sel", sizeof(w
->name
));
3693 strlcpy(w
->name
, "dock", sizeof(w
->name
));
3696 strlcpy(w
->name
, "dock.pre", sizeof(w
->name
));
3699 return generic_mixer_init_widget(this, w
, nid
);
3706 ad1984_unsol_event(codec_t
*this, int tag
)
3713 mc
.type
= AUDIO_MIXER_ENUM
;
3716 case AD198X_EVENT_HP
:
3717 err
= this->comresp(this, 0x11, CORB_GET_PIN_SENSE
, 0, &value
);
3720 if (value
& CORB_PS_PRESENCE
) {
3721 DPRINTF(("%s: headphone has been inserted.\n", __func__
));
3722 mc
.un
.ord
= 1; /* mute */
3723 generic_mixer_set(this, 0x12, MI_TARGET_OUTAMP
, &mc
);
3724 generic_mixer_set(this, 0x13, MI_TARGET_OUTAMP
, &mc
);
3726 DPRINTF(("%s: headphone has been pulled out.\n", __func__
));
3727 mc
.un
.ord
= 0; /* unmute */
3728 generic_mixer_set(this, 0x12, MI_TARGET_OUTAMP
, &mc
);
3729 /* if no speaker unmute internal mono */
3730 err
= this->comresp(this, 0x12, CORB_GET_PIN_SENSE
, 0, &value
);
3733 if (!(value
& CORB_PS_PRESENCE
))
3734 generic_mixer_set(this, 0x13, MI_TARGET_OUTAMP
, &mc
);
3737 case AD198X_EVENT_SPEAKER
:
3738 err
= this->comresp(this, 0x12, CORB_GET_PIN_SENSE
, 0, &value
);
3741 if (value
& CORB_PS_PRESENCE
) {
3742 DPRINTF(("%s: speaker has been inserted.\n", __func__
));
3743 mc
.un
.ord
= 1; /* mute */
3744 generic_mixer_set(this, 0x13, MI_TARGET_OUTAMP
, &mc
);
3746 DPRINTF(("%s: speaker has been pulled out.\n", __func__
));
3747 /* if no headphones unmute internal mono */
3748 err
= this->comresp(this, 0x11, CORB_GET_PIN_SENSE
, 0, &value
);
3751 if (!(value
& CORB_PS_PRESENCE
)) {
3752 mc
.un
.ord
= 0; /* unmute */
3753 generic_mixer_set(this, 0x13, MI_TARGET_OUTAMP
, &mc
);
3758 printf("%s: unknown tag: %d\n", __func__
, tag
);
3763 /* ----------------------------------------------------------------
3764 * Analog Devices AD1986A
3765 * ---------------------------------------------------------------- */
3767 static const mixer_item_t ad1986a_mixer_items
[] = {
3770 {{0, {AzaliaNdigital
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3771 0, 0, .un
.e
={2, {{{"hdaudio", 0}, 0}, {{"recordout", 0}, 1}}}}, 0x02, MI_TARGET_CONNLIST
},
3774 /* fix to mixerout (default) */
3775 {{0, {AudioNheadphone
".src", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3776 0, 0, .un
.e
={3, {{{AudioNmixerout
, 0}, 0}, {{"surrounddac", 0}, 1},
3777 {{"clfedac", 0}, 2}}}}, 0x0a, MI_TARGET_CONNLIST
},
3779 {{0, {AudioNheadphone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3780 0, 0, ENUM_OFFON
}, 0x1a, MI_TARGET_OUTAMP
},
3781 {{0, {AudioNheadphone
"." "boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3782 0, 0, ENUM_OFFON
}, 0x1a, MI_TARGET_PINBOOST
},
3783 {{0, {AudioNheadphone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3784 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1a, MI_TARGET_OUTAMP
},
3787 /* fix to mixerout (default) */
3788 {{0, {AudioNline
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3789 0, 0, .un
.e
={2, {{{AudioNmixerout
, 0}, 0}, {{"surrounddac", 0}, 1}}}},
3790 0x0b, MI_TARGET_CONNLIST
},
3792 {{0, {AudioNline
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3793 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_OUTAMP
},
3794 {{0, {AudioNline
"." "boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3795 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_PINBOOST
},
3796 {{0, {AudioNline
"." "eapd", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3797 0, 0, ENUM_OFFON
}, 0x1b, MI_TARGET_EAPD
},
3798 {{0, {AudioNline
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3799 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1b, MI_TARGET_OUTAMP
},
3802 /* fix to the surround DAC (default) */
3803 {{0, {AudioNsurround
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3804 0, 0, .un
.e
={2, {{{"surrounddac", 0}, 0}, {{AudioNmixerout
, 0}, 1}}}},
3805 0x0c, MI_TARGET_CONNLIST
},
3807 {{0, {AudioNsurround
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3808 0, 0, ENUM_OFFON
}, 0x1c, MI_TARGET_OUTAMP
},
3810 {{0, {AudioNsurround
"." "dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3811 0, 0, ENUM_IO
}, 0x1c, MI_TARGET_PINDIR
},
3812 /* fix to maximum */
3813 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3814 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1c, MI_TARGET_OUTAMP
},
3816 {{0, {AudioNsurround
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3817 0, 0, ENUM_OFFON
}, 0x04, MI_TARGET_OUTAMP
},
3818 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3819 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x04, MI_TARGET_OUTAMP
},
3822 /* fix to the clfe DAC (default) */
3823 {{0, {AzaliaNclfe
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3824 0, 0, .un
.e
={2, {{{"clfedac", 0}, 0}, {{"mixeroutmono", 0}, 1}}}},
3825 0x0d, MI_TARGET_CONNLIST
},
3827 {{0, {AzaliaNclfe
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3828 0, 0, ENUM_OFFON
}, 0x1d, MI_TARGET_OUTAMP
},
3830 {{0, {AzaliaNclfe
"." "dir", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3831 0, 0, ENUM_IO
}, 0x1d, MI_TARGET_PINDIR
},
3832 /* fix to maximum */
3833 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3834 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1d, MI_TARGET_OUTAMP
},
3836 {{0, {AzaliaNclfe
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3837 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_OUTAMP
},
3838 {{0, {AzaliaNclfe
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3839 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x05, MI_TARGET_OUTAMP
},
3840 {{0, {AzaliaNclfe
"." "lrswap", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3841 0, 0, ENUM_OFFON
}, 0x1d, MI_TARGET_LRSWAP
},
3843 {{0, {AudioNmono
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3844 0, 0, .un
.e
={2, {{{AudioNmixerout
, 0}, 0}, {{AudioNmicrophone
, 0}, 1}}}},
3845 0x0e, MI_TARGET_CONNLIST
},
3846 {{0, {AudioNmono
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
3847 0, 0, ENUM_OFFON
}, 0x1e, MI_TARGET_OUTAMP
},
3848 {{0, {AudioNmono
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
3849 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x1e, MI_TARGET_OUTAMP
},
3852 {{0, {AudioNdac
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3853 0, 0, ENUM_OFFON
}, 0x03, MI_TARGET_OUTAMP
},
3854 {{0, {AudioNdac
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3855 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x03, MI_TARGET_OUTAMP
},
3858 /* 0x09: 5.1 -> Stereo Downmix */
3859 {{0, {"downmix" "." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3860 0, 0, ENUM_OFFON
}, 0x09, MI_TARGET_OUTAMP
},
3864 /* mic source is mic jack (default) */
3865 {{0, {AudioNmicrophone
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3866 0, 0, .un
.e
={8, {{{AudioNmicrophone
, 0}, 0}, {{AudioNline
, 0}, 1},
3867 {{AzaliaNclfe
, 0}, 2}, {{AzaliaNclfe
"2", 0}, 3},
3868 {{"micclfe", 0}, 4}, {{"micline", 0}, 5},
3869 {{"clfeline", 0}, 6}, {{"miclineclfe", 0}, 7}}}},
3870 0x0f, MI_TARGET_CONNLIST
},
3872 {{0, {AudioNmicrophone
"." "gain", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3873 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(3)}}, 0x0f, MI_TARGET_OUTAMP
},
3874 {{0, {AudioNmicrophone
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3875 0, 0, ENUM_OFFON
}, 0x13, MI_TARGET_OUTAMP
},
3876 {{0, {AudioNmicrophone
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3877 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x13, MI_TARGET_OUTAMP
},
3880 /* line source is line jack (default) */
3881 {{0, {AudioNline
"." AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3882 0, 0, .un
.e
={3, {{{AudioNline
, 0}, 0}, {{AudioNsurround
, 0}, 1},
3883 {{AudioNmicrophone
, 0}, 2}}}}, 0x10, MI_TARGET_CONNLIST
},
3885 {{0, {AudioNline
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3886 0, 0, ENUM_OFFON
}, 0x17, MI_TARGET_OUTAMP
},
3887 {{0, {AudioNline
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3888 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x17, MI_TARGET_OUTAMP
},
3890 {{0, {"phone" "." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3891 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
3892 {{0, {"phone", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3893 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x14, MI_TARGET_OUTAMP
},
3895 {{0, {AudioNcd
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3896 0, 0, ENUM_OFFON
}, 0x15, MI_TARGET_OUTAMP
},
3897 {{0, {AudioNcd
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3898 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x15, MI_TARGET_OUTAMP
},
3900 {{0, {AudioNaux
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3901 0, 0, ENUM_OFFON
}, 0x16, MI_TARGET_OUTAMP
},
3902 {{0, {AudioNaux
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3903 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x16, MI_TARGET_OUTAMP
},
3905 {{0, {AudioNspeaker
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
3906 0, 0, ENUM_OFFON
}, 0x18, MI_TARGET_OUTAMP
},
3907 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
3908 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(15)}}, 0x18, MI_TARGET_OUTAMP
},
3911 /* 0x11: inputs.sel11.source=sel0f [ sel0f mix2b ] XXXX
3912 inputs.sel11.lrswap=off [ off on ] XXXX */
3914 {{0, {AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3915 0, 0, .un
.e
={7, {{{AudioNmicrophone
, 0}, 0}, {{AudioNcd
, 0}, 1},
3916 {{AudioNaux
, 0}, 2}, {{AudioNline
, 0}, 3},
3917 {{AudioNmixerout
, 0}, 4}, {{"mixeroutmono", 0}, 5},
3918 {{"phone", 0}, 6}}}},
3919 0x12, MI_TARGET_CONNLIST
},
3920 {{0, {AudioNvolume
"." AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
3921 0, 0, ENUM_OFFON
}, 0x12, MI_TARGET_OUTAMP
},
3922 {{0, {AudioNvolume
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
3923 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(15)}}, 0x12, MI_TARGET_OUTAMP
},
3925 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
, 0, 0,
3926 .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}}, 0, MI_TARGET_DAC
},
3930 ad1986a_mixer_init(codec_t
*this)
3934 this->nmixers
= __arraycount(ad1986a_mixer_items
);
3935 this->mixers
= malloc(sizeof(ad1986a_mixer_items
), M_DEVBUF
, M_NOWAIT
);
3936 if (this->mixers
== NULL
) {
3937 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
3940 memcpy(this->mixers
, ad1986a_mixer_items
, sizeof(ad1986a_mixer_items
));
3941 generic_mixer_fix_indexes(this);
3942 generic_mixer_default(this);
3945 mc
.type
= AUDIO_MIXER_ENUM
;
3946 mc
.un
.ord
= 0; /* unmute */
3947 generic_mixer_set(this, 0x1c, MI_TARGET_OUTAMP
, &mc
);
3948 mc
.un
.ord
= 1; /* dir: output */
3949 generic_mixer_set(this, 0x1c, MI_TARGET_PINDIR
, &mc
);
3950 mc
.type
= AUDIO_MIXER_VALUE
;
3951 mc
.un
.value
.num_channels
= 2;
3952 mc
.un
.value
.level
[0] = AUDIO_MAX_GAIN
;
3953 mc
.un
.value
.level
[1] = AUDIO_MAX_GAIN
;
3954 generic_mixer_set(this, 0x1c, MI_TARGET_VOLUME
, &mc
);
3955 mc
.type
= AUDIO_MIXER_ENUM
;
3956 mc
.un
.ord
= 0; /* unmute */
3957 generic_mixer_set(this, 0x1d, MI_TARGET_OUTAMP
, &mc
);
3958 mc
.un
.ord
= 1; /* dir: output */
3959 generic_mixer_set(this, 0x1d, MI_TARGET_PINDIR
, &mc
);
3960 mc
.type
= AUDIO_MIXER_VALUE
;
3961 mc
.un
.value
.num_channels
= 2;
3962 mc
.un
.value
.level
[0] = AUDIO_MAX_GAIN
;
3963 mc
.un
.value
.level
[1] = AUDIO_MAX_GAIN
;
3964 generic_mixer_set(this, 0x1d, MI_TARGET_VOLUME
, &mc
);
3969 ad1986a_init_dacgroup(codec_t
*this)
3971 static const convgroupset_t dacs
= {
3973 {{6, {0x03, 0x04, 0x05}}, /* analog 6ch */
3974 {1, {0x02}}}}; /* digital */
3975 static const convgroupset_t adcs
= {
3977 {{1, {0x06}}}}; /* analog 2ch */
3984 /* ----------------------------------------------------------------
3985 * Analog Devices AD1988A/AD1988B
3986 * ---------------------------------------------------------------- */
3989 ad1988_init_dacgroup(codec_t
*this)
3991 static const convgroupset_t dacs
= {
3993 {{4, {0x04, 0x05, 0x06, 0x0a}}, /* analog 8ch */
3994 {1, {0x02}}, /* digital */
3995 {1, {0x03}}}}; /* another analog */
3996 static const convgroupset_t adcs
= {
3998 {{2, {0x08, 0x09, 0x0f}}, /* analog 6ch */
3999 {1, {0x07}}}}; /* digital */
4006 /* ----------------------------------------------------------------
4008 * ---------------------------------------------------------------- */
4010 static const mixer_item_t cmi9880_mixer_items
[] = {
4013 {{0, {AudioNmaster
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4014 0, 0, ENUM_OFFON
}, 0x03, MI_TARGET_OUTAMP
},
4015 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4016 0, 0, ENUM_OFFON
}, 0x04, MI_TARGET_OUTAMP
},
4017 {{0, {AzaliaNclfe
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4018 0, 0, ENUM_OFFON
}, 0x05, MI_TARGET_OUTAMP
},
4019 {{0, {AzaliaNside
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4020 0, 0, ENUM_OFFON
}, 0x06, MI_TARGET_OUTAMP
},
4021 {{0, {AzaliaNdigital
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4022 0, 0, ENUM_OFFON
}, 0x07, MI_TARGET_OUTAMP
},
4024 {{0, {AzaliaNfront
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
4025 0, 0, ENUM_OFFON
}, 0x08, MI_TARGET_INAMP(0)},
4026 {{0, {AzaliaNfront
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
4027 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(30)}}, 0x08, MI_TARGET_INAMP(0)},
4028 {{0, {AzaliaNfront
"."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
4029 0, 0, .un
.e
={4, {{{AudioNmicrophone
, 0}, 5}, {{AudioNcd
, 0}, 6},
4030 {{"line1", 0}, 7}, {{"line2", 0}, 8}}}},
4031 0x08, MI_TARGET_CONNLIST
},
4032 {{0, {AudioNsurround
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
4033 0, 0, ENUM_OFFON
}, 0x09, MI_TARGET_INAMP(0)},
4034 {{0, {AudioNsurround
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_RECORD
,
4035 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(30)}}, 0x09, MI_TARGET_INAMP(0)},
4036 {{0, {AudioNsurround
"."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
4037 0, 0, .un
.e
={4, {{{AudioNmicrophone
, 0}, 5}, {{AudioNcd
, 0}, 6},
4038 {{"line1", 0}, 7}, {{"line2", 0}, 8}}}},
4039 0x09, MI_TARGET_CONNLIST
},
4041 {{0, {AudioNspeaker
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
4042 0, 0, ENUM_OFFON
}, 0x23, MI_TARGET_OUTAMP
},
4043 {{0, {AudioNspeaker
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_INPUT
,
4044 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(15)}}, 0x23, MI_TARGET_OUTAMP
}
4048 cmi9880_mixer_init(codec_t
*this)
4052 this->nmixers
= __arraycount(cmi9880_mixer_items
);
4053 this->mixers
= malloc(sizeof(cmi9880_mixer_items
), M_DEVBUF
, M_NOWAIT
);
4054 if (this->mixers
== NULL
) {
4055 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
4058 memcpy(this->mixers
, cmi9880_mixer_items
, sizeof(cmi9880_mixer_items
));
4059 generic_mixer_fix_indexes(this);
4060 generic_mixer_default(this);
4063 mc
.type
= AUDIO_MIXER_ENUM
;
4064 mc
.un
.ord
= 5; /* record.front.source=mic */
4065 generic_mixer_set(this, 0x08, MI_TARGET_CONNLIST
, &mc
);
4066 mc
.un
.ord
= 7; /* record.surround.source=line1 */
4067 generic_mixer_set(this, 0x09, MI_TARGET_CONNLIST
, &mc
);
4068 mc
.un
.ord
= 1; /* pindir: output */
4069 generic_mixer_set(this, 0x0b, MI_TARGET_PINDIR
, &mc
);
4070 generic_mixer_set(this, 0x0c, MI_TARGET_PINDIR
, &mc
);
4071 generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR
, &mc
);
4072 generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR
, &mc
);
4073 generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR
, &mc
);
4074 mc
.un
.ord
= 0; /* front DAC -> headphones */
4075 generic_mixer_set(this, 0x0f, MI_TARGET_CONNLIST
, &mc
);
4076 mc
.un
.ord
= 0; /* pindir: input */
4077 generic_mixer_set(this, 0x10, MI_TARGET_PINDIR
, &mc
); /* mic */
4078 generic_mixer_set(this, 0x13, MI_TARGET_PINDIR
, &mc
); /* SPDIF-in */
4079 generic_mixer_set(this, 0x1f, MI_TARGET_PINDIR
, &mc
); /* line1 */
4080 generic_mixer_set(this, 0x20, MI_TARGET_PINDIR
, &mc
); /* line2 */
4085 cmi9880_init_dacgroup(codec_t
*this)
4087 static const convgroupset_t dacs
= {
4089 {{4, {0x03, 0x04, 0x05, 0x06}}, /* analog 8ch */
4090 {1, {0x07}}}}; /* digital */
4091 static const convgroupset_t adcs
= {
4093 {{2, {0x08, 0x09}}, /* analog 4ch */
4094 {1, {0x0a}}}}; /* digital */
4101 /* ----------------------------------------------------------------
4102 * Sigmatel STAC9221 and STAC9221D
4103 * ---------------------------------------------------------------- */
4105 #define STAC9221_MAC 0x76808384
4108 stac9221_init_dacgroup(codec_t
*this)
4110 static const convgroupset_t dacs
= {
4112 {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */
4113 {1, {0x08}}, /* digital */
4114 {1, {0x1a}}}}; /* another digital? */
4115 static const convgroupset_t adcs
= {
4117 {{2, {0x06, 0x07}}, /* analog 4ch */
4118 {1, {0x09}}}}; /* digital */
4126 stac9221_mixer_init(codec_t
*this)
4130 err
= generic_mixer_init(this);
4133 if (this->subid
== STAC9221_MAC
) {
4134 stac9221_gpio_unmute(this, 0);
4135 stac9221_gpio_unmute(this, 1);
4141 stac9221_gpio_unmute(codec_t
*this, int pin
)
4143 uint32_t data
, mask
, dir
;
4145 this->comresp(this, this->audiofunc
, CORB_GET_GPIO_DATA
, 0, &data
);
4146 this->comresp(this, this->audiofunc
,
4147 CORB_GET_GPIO_ENABLE_MASK
, 0, &mask
);
4148 this->comresp(this, this->audiofunc
, CORB_GET_GPIO_DIRECTION
, 0, &dir
);
4149 data
&= ~(1 << pin
);
4152 this->comresp(this, this->audiofunc
, 0x7e7, 0, NULL
);
4153 this->comresp(this, this->audiofunc
,
4154 CORB_SET_GPIO_ENABLE_MASK
, mask
, NULL
);
4155 this->comresp(this, this->audiofunc
,
4156 CORB_SET_GPIO_DIRECTION
, dir
, NULL
);
4158 this->comresp(this, this->audiofunc
, CORB_SET_GPIO_DATA
, data
, NULL
);
4162 /* ----------------------------------------------------------------
4163 * Sigmatel STAC9200 and STAC9200D
4164 * ---------------------------------------------------------------- */
4166 static const mixer_item_t stac9200_mixer_items
[] = {
4169 {{0, {AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4170 0, 0, .un
.e
={3, {{{AudioNdac
, 0}, 0}, {{AzaliaNdigital
"-in", 0}, 1},
4171 {{"selector", 0}, 2}}}}, 0x07, MI_TARGET_CONNLIST
},
4172 {{0, {AzaliaNdigital
"."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4173 0, 0, .un
.e
={2, {{{AudioNdac
, 0}, 0}, {{"selector", 0}, 1}}}},
4174 0x09, MI_TARGET_CONNLIST
}, /* AudioNdac is not accurate name */
4175 {{0, {"selector."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4176 0, 0, ENUM_OFFON
}, 0x0a, MI_TARGET_OUTAMP
},
4177 {{0, {"selector", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
4178 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(15)}}, 0x0a, MI_TARGET_OUTAMP
},
4179 {{0, {AudioNmaster
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4180 0, 0, ENUM_OFFON
}, 0x0b, MI_TARGET_OUTAMP
},
4181 {{0, {AudioNmaster
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
4182 0, 0, .un
.v
={{"", 0}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_OUTAMP
},
4183 {{0, {"selector."AudioNsource
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_INPUT
,
4184 0, 0, .un
.e
={3, {{{"mic1", 0}, 0}, {{"mic2", 0}, 1}, {{AudioNcd
, 0}, 4}}}},
4185 0x0c, MI_TARGET_CONNLIST
},
4186 {{0, {AudioNheadphone
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4187 0, 0, ENUM_OFFON
}, 0x0d, MI_TARGET_PINBOOST
},
4188 {{0, {AudioNspeaker
".boost", 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4189 0, 0, ENUM_OFFON
}, 0x0e, MI_TARGET_PINBOOST
},
4190 {{0, {AudioNmono
"."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4191 0, 0, ENUM_OFFON
}, 0x11, MI_TARGET_OUTAMP
},
4192 {{0, {AudioNmono
, 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
4193 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP
},
4194 {{0, {"beep."AudioNmute
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_OUTPUT
,
4195 0, 0, ENUM_OFFON
}, 0x14, MI_TARGET_OUTAMP
},
4196 {{0, {"beep", 0}, AUDIO_MIXER_VALUE
, AZ_CLASS_OUTPUT
,
4197 0, 0, .un
.v
={{"", 0}, 1, MIXER_DELTA(3)}}, 0x14, MI_TARGET_OUTAMP
},
4198 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_PLAYBACK
,
4199 0, 0, .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}},
4201 {{0, {AudioNmode
, 0}, AUDIO_MIXER_ENUM
, AZ_CLASS_RECORD
,
4202 0, 0, .un
.e
={2, {{{"analog", 0}, 0}, {{AzaliaNdigital
, 0}, 1}}}},
4207 stac9200_mixer_init(codec_t
*this)
4212 this->nmixers
= __arraycount(stac9200_mixer_items
);
4213 this->mixers
= malloc(sizeof(stac9200_mixer_items
), M_DEVBUF
, M_NOWAIT
);
4214 if (this->mixers
== NULL
) {
4215 aprint_error_dev(this->dev
, "out of memory in %s\n", __func__
);
4218 memcpy(this->mixers
, stac9200_mixer_items
, sizeof(stac9200_mixer_items
));
4219 generic_mixer_fix_indexes(this);
4220 generic_mixer_default(this);
4222 mc
.dev
= -1; /* no need for generic_mixer_set() */
4223 mc
.type
= AUDIO_MIXER_ENUM
;
4224 mc
.un
.ord
= 1; /* pindir: output */
4225 generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR
, &mc
); /* headphones */
4226 generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR
, &mc
); /* speaker */
4227 mc
.un
.ord
= 0; /* pindir: input */
4228 generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR
, &mc
); /* mic2 */
4229 generic_mixer_set(this, 0x10, MI_TARGET_PINDIR
, &mc
); /* mic1 */
4230 mc
.type
= AUDIO_MIXER_VALUE
;
4231 mc
.un
.value
.num_channels
= 2;
4232 mc
.un
.value
.level
[0] = generic_mixer_max(this, 0x0c, MI_TARGET_OUTAMP
);
4233 mc
.un
.value
.level
[1] = mc
.un
.value
.level
[0];
4234 generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP
, &mc
);
4236 #define STAC9200_DELL_INSPIRON6400_ID 0x01bd1028
4237 #define STAC9200_DELL_INSPIRON9400_ID 0x01cd1028
4238 #define STAC9200_DELL_640M_ID 0x01d81028
4239 #define STAC9200_DELL_LATITUDE_D420_ID 0x01d61028
4240 #define STAC9200_DELL_LATITUDE_D430_ID 0x02011028
4242 #define STAC9200_EVENT_HP 0
4243 #define STAC9200_NID_HP 0x0d
4244 #define STAC9200_NID_SPEAKER 0x0e
4246 switch (this->subid
) {
4247 case STAC9200_DELL_INSPIRON6400_ID
:
4248 case STAC9200_DELL_INSPIRON9400_ID
:
4249 case STAC9200_DELL_640M_ID
:
4250 case STAC9200_DELL_LATITUDE_D420_ID
:
4251 case STAC9200_DELL_LATITUDE_D430_ID
:
4252 /* Does every DELL model have the same pin configuration?
4255 /* setup a unsolicited event for the headphones */
4256 this->comresp(this, STAC9200_NID_HP
, CORB_SET_UNSOLICITED_RESPONSE
,
4257 CORB_UNSOL_ENABLE
| STAC9200_EVENT_HP
, NULL
);
4258 /* If the headphone presents, mute the internal speaker */
4259 this->comresp(this, STAC9200_NID_HP
, CORB_GET_PIN_SENSE
, 0, &value
);
4260 if (value
& CORB_PS_PRESENCE
) {
4261 generic_mixer_pinctrl(this, STAC9200_NID_SPEAKER
, 0);
4263 generic_mixer_pinctrl(this,
4264 STAC9200_NID_SPEAKER
, CORB_PWC_OUTPUT
);
4274 stac9200_unsol_event(codec_t
*this, int tag
)
4280 case STAC9200_EVENT_HP
:
4281 err
= this->comresp(this, STAC9200_NID_HP
,
4282 CORB_GET_PIN_SENSE
, 0, &value
);
4285 if (value
& CORB_PS_PRESENCE
) {
4286 DPRINTF(("%s: headphone has been inserted.\n", __func__
));
4287 generic_mixer_pinctrl(this, STAC9200_NID_SPEAKER
, 0);
4289 DPRINTF(("%s: headphone has been pulled out.\n", __func__
));
4290 generic_mixer_pinctrl(this, STAC9200_NID_SPEAKER
, CORB_PWC_OUTPUT
);
4294 printf("%s: unknown tag: %d\n", __func__
, tag
);
4299 /* ----------------------------------------------------------------
4301 * ---------------------------------------------------------------- */
4304 atihdmi_init_dacgroup(codec_t
*this)
4306 static const convgroupset_t dacs
= {
4308 {{1, {0x02}}}}; /* digital */
4309 static const convgroupset_t adcs
= {
4311 {{0, {0x00}}}}; /* no recording */