Bug Summary

File:dev/pci/azalia_codec.c
Warning:line 1786, column 3
Value stored to 'value' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name azalia_codec.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/pci/azalia_codec.c
1/* $OpenBSD: azalia_codec.c,v 1.187 2021/10/07 14:11:32 robert Exp $ */
2/* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */
3
4/*-
5 * Copyright (c) 2005 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by TAMURA Kent
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/param.h>
34#include <sys/device.h>
35#include <sys/malloc.h>
36#include <sys/systm.h>
37#include <dev/pci/azalia.h>
38#include <dev/pci/pcireg.h>
39#include <dev/pci/pcidevs.h>
40
41#define XNAME(co)(((struct device *)co->az)->dv_xname) (((struct device *)co->az)->dv_xname)
42#define MIXER_DELTA(n)(255 / (n)) (AUDIO_MAX_GAIN255 / (n))
43
44int azalia_add_convgroup(codec_t *, convgroupset_t *,
45 struct io_pin *, int, nid_t *, int, uint32_t, uint32_t);
46
47int azalia_mixer_fix_indexes(codec_t *);
48int azalia_mixer_default(codec_t *);
49int azalia_mixer_ensure_capacity(codec_t *, size_t);
50u_char azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t );
51uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char);
52
53void azalia_devinfo_offon(mixer_devinfo_t *);
54void azalia_pin_config_ov(widget_t *, int, int);
55void azalia_ampcap_ov(widget_t *, int, int, int, int, int, int);
56int azalia_gpio_unmute(codec_t *, int);
57
58
59int
60azalia_codec_init_vtbl(codec_t *this)
61{
62 /**
63 * We can refer this->vid and this->subid.
64 */
65 this->name = NULL((void *)0);
66 this->qrks = AZ_QRK_NONE0x00000000;
67 switch (this->vid) {
68 case 0x10134206:
69 this->name = "Cirrus Logic CS4206";
70 if (this->subid == 0xcb8910de || /* APPLE_MBA3_1 */
71 this->subid == 0x72708086 || /* APPLE_MBA4_1 */
72 this->subid == 0xcb7910de) { /* APPLE_MBP5_5 */
73 this->qrks |= AZ_QRK_GPIO_UNMUTE_10x00000002 |
74 AZ_QRK_GPIO_UNMUTE_30x00000008;
75 }
76 break;
77 case 0x10134208:
78 this->name = "Cirrus Logic CS4208";
79 if (this->subid == 0x72708086) { /* APPLE_MBA6_1 */
80 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001 |
81 AZ_QRK_GPIO_UNMUTE_10x00000002;
82 }
83 break;
84 case 0x10ec0221:
85 this->name = "Realtek ALC221";
86 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
87 break;
88 case 0x10ec0225:
89 this->name = "Realtek ALC225";
90 break;
91 case 0x10ec0233:
92 case 0x10ec0235:
93 this->name = "Realtek ALC233";
94 break;
95 case 0x10ec0236:
96 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028)
97 this->name = "Realtek ALC3204";
98 else
99 this->name = "Realtek ALC236";
100 break;
101 case 0x10ec0255:
102 this->name = "Realtek ALC255";
103 break;
104 case 0x10ec0256:
105 this->name = "Realtek ALC256";
106 break;
107 case 0x10ec0257:
108 this->name = "Realtek ALC257";
109 break;
110 case 0x10ec0260:
111 this->name = "Realtek ALC260";
112 if (this->subid == 0x008f1025)
113 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
114 break;
115 case 0x10ec0262:
116 this->name = "Realtek ALC262";
117 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
118 break;
119 case 0x10ec0268:
120 this->name = "Realtek ALC268";
121 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
122 break;
123 case 0x10ec0269:
124 this->name = "Realtek ALC269";
125 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
126
127 /*
128 * Enable dock audio on Thinkpad docks
129 * 0x17aa : 0x21f3 = Thinkpad T430
130 * 0x17aa : 0x21f6 = Thinkpad T530
131 * 0x17aa : 0x21fa = Thinkpad X230
132 * 0x17aa : 0x21fb = Thinkpad T430s
133 * 0x17aa : 0x2203 = Thinkpad X230t
134 * 0x17aa : 0x2208 = Thinkpad T431s
135 */
136 if (this->subid == 0x21f317aa ||
137 this->subid == 0x21f617aa ||
138 this->subid == 0x21fa17aa ||
139 this->subid == 0x21fb17aa ||
140 this->subid == 0x220317aa ||
141 this->subid == 0x220817aa)
142 this->qrks |= AZ_QRK_WID_TPDOCK10x00010000;
143 break;
144 case 0x10ec0270:
145 this->name = "Realtek ALC270";
146 break;
147 case 0x10ec0272:
148 this->name = "Realtek ALC272";
149 break;
150 case 0x10ec0275:
151 this->name = "Realtek ALC275";
152 break;
153 case 0x10ec0280:
154 this->name = "Realtek ALC280";
155 break;
156 case 0x10ec0282:
157 this->name = "Realtek ALC282";
158 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
159 break;
160 case 0x10ec0283:
161 this->name = "Realtek ALC283";
162 break;
163 case 0x10ec0285:
164 this->name = "Realtek ALC285";
165 if (this->subid == 0x229217aa) {
166 /* Thinkpad X1 Carbon 7 */
167 this->qrks |= AZ_QRK_ROUTE_SPKR2_DAC0x01000000 |
168 AZ_QRK_WID_CLOSE_PCBEEP0x00080000;
169 } else if (this->subid == 0x22c017aa) {
170 /* Thinkpad X1 Extreme 3 */
171 this->qrks |= AZ_QRK_DOLBY_ATMOS0x02000000 |
172 AZ_QRK_ROUTE_SPKR2_DAC0x01000000;
173 }
174 break;
175 case 0x10ec0287:
176 this->name = "Realtek ALC287";
177 break;
178 case 0x10ec0292:
179 this->name = "Realtek ALC292";
180 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
181
182 /*
183 * Enable dock audio on Thinkpad docks
184 * 0x17aa : 0x220c = Thinkpad T440s
185 * 0x17aa : 0x220e = Thinkpad T440p
186 * 0x17aa : 0x2210 = Thinkpad T540p
187 * 0x17aa : 0x2212 = Thinkpad T440
188 * 0x17aa : 0x2214 = Thinkpad X240
189 * 0x17aa : 0x2226 = Thinkpad X250
190 * 0x17aa : 0x501e = Thinkpad L440
191 * 0x17aa : 0x5034 = Thinkpad T450
192 * 0x17aa : 0x5036 = Thinkpad T450s
193 * 0x17aa : 0x503c = Thinkpad L450
194 */
195 if (this->subid == 0x220c17aa ||
196 this->subid == 0x220e17aa ||
197 this->subid == 0x221017aa ||
198 this->subid == 0x221217aa ||
199 this->subid == 0x221417aa ||
200 this->subid == 0x222617aa ||
201 this->subid == 0x501e17aa ||
202 this->subid == 0x503417aa ||
203 this->subid == 0x503617aa ||
204 this->subid == 0x503c17aa)
205 this->qrks |= AZ_QRK_WID_TPDOCK20x00020000;
206 break;
207 case 0x10ec0293:
208 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028)
209 this->name = "Realtek ALC3235";
210 else
211 this->name = "Realtek ALC293";
212 break;
213 case 0x10ec0294:
214 this->name = "Realtek ALC294";
215 break;
216 case 0x10ec0295:
217 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028)
218 this->name = "Realtek ALC3254";
219 else
220 this->name = "Realtek ALC295";
221 break;
222 case 0x10ec0298:
223 this->name = "Realtek ALC298";
224 if (this->subid == 0x320019e5 ||
225 this->subid == 0x320119e5) /* Huawei Matebook X */
226 this->qrks |= AZ_QRK_DOLBY_ATMOS0x02000000;
227 break;
228 case 0x10ec0299:
229 this->name = "Realtek ALC299";
230 break;
231 case 0x10ec0660:
232 this->name = "Realtek ALC660";
233 if (this->subid == 0x13391043) { /* ASUS_G2K */
234 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
235 }
236 break;
237 case 0x10ec0662:
238 this->name = "Realtek ALC662";
239 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
240 break;
241 case 0x10ec0663:
242 this->name = "Realtek ALC663";
243 break;
244 case 0x10ec0668:
245 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028)
246 this->name = "Realtek ALC3661";
247 else
248 this->name = "Realtek ALC668";
249 break;
250 case 0x10ec0671:
251 this->name = "Realtek ALC671";
252 break;
253 case 0x10ec0700:
254 this->name = "Realtek ALC700";
255 break;
256 case 0x10ec0861:
257 this->name = "Realtek ALC861";
258 break;
259 case 0x10ec0880:
260 this->name = "Realtek ALC880";
261 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
262 if (this->subid == 0x19931043 || /* ASUS_M5200 */
263 this->subid == 0x13231043) { /* ASUS_A7M */
264 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
265 }
266 if (this->subid == 0x203d161f) { /* MEDION_MD95257 */
267 this->qrks |= AZ_QRK_GPIO_UNMUTE_10x00000002;
268 }
269 break;
270 case 0x10ec0882:
271 this->name = "Realtek ALC882";
272 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
273 if (this->subid == 0x13c21043 || /* ASUS_A7T */
274 this->subid == 0x19711043) { /* ASUS_W2J */
275 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
276 }
277 break;
278 case 0x10ec0883:
279 this->name = "Realtek ALC883";
280 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
281 if (this->subid == 0x00981025) { /* ACER_ID */
282 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001 |
283 AZ_QRK_GPIO_UNMUTE_10x00000002;
284 }
285 break;
286 case 0x10ec0885:
287 this->name = "Realtek ALC885";
288 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
289 if (this->subid == 0x00a1106b || /* APPLE_MB3 */
290 this->subid == 0xcb7910de || /* APPLE_MACMINI3_1 (line-in + hp) */
291 this->subid == 0x00a0106b || /* APPLE_MB3_1 */
292 this->subid == 0x00a3106b) { /* APPLE_MB4 */
293 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
294 }
295 if (this->subid == 0x00a1106b ||
296 this->subid == 0xcb7910de || /* APPLE_MACMINI3_1 (internal spkr) */
297 this->subid == 0x00a0106b)
298 this->qrks |= AZ_QRK_WID_OVREF500x00004000;
299 break;
300 case 0x10ec0887:
301 this->name = "Realtek ALC887";
302 break;
303 case 0x10ec0888:
304 this->name = "Realtek ALC888";
305 this->qrks |= AZ_QRK_WID_CDIN_1C0x00001000 | AZ_QRK_WID_BEEP_1D0x00002000;
306 break;
307 case 0x10ec0889:
308 this->name = "Realtek ALC889";
309 break;
310 case 0x10ec0892:
311 this->name = "Realtek ALC892";
312 break;
313 case 0x10ec0897:
314 this->name = "Realtek ALC897";
315 break;
316 case 0x10ec0900:
317 this->name = "Realtek ALC1150";
318 break;
319 case 0x10ec0b00:
320 this->name = "Realtek ALC1200";
321 break;
322 case 0x10ec1168:
323 case 0x10ec1220:
324 this->name = "Realtek ALC1220";
325 break;
326 case 0x11060398:
327 case 0x11061398:
328 case 0x11062398:
329 case 0x11063398:
330 case 0x11064398:
331 case 0x11065398:
332 case 0x11066398:
333 case 0x11067398:
334 this->name = "VIA VT1702";
335 break;
336 case 0x111d7603:
337 this->name = "IDT 92HD75B3/4";
338 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_HP0x103c)
339 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
340 break;
341 case 0x111d7604:
342 this->name = "IDT 92HD83C1X";
343 break;
344 case 0x111d7605:
345 this->name = "IDT 92HD81B1X";
346 break;
347 case 0x111d7608:
348 this->name = "IDT 92HD75B1/2";
349 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_HP0x103c)
350 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
351 break;
352 case 0x111d7674:
353 this->name = "IDT 92HD73D1";
354 break;
355 case 0x111d7675:
356 this->name = "IDT 92HD73C1"; /* aka 92HDW74C1 */
357 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028)
358 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
359 break;
360 case 0x111d7676:
361 this->name = "IDT 92HD73E1"; /* aka 92HDW74E1 */
362 break;
363 case 0x111d76b0:
364 this->name = "IDT 92HD71B8";
365 break;
366 case 0x111d76b2:
367 this->name = "IDT 92HD71B7";
368 if (PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_DELL0x1028 ||
369 PCI_VENDOR(this->subid)(((this->subid) >> 0) & 0xffff) == PCI_VENDOR_HP0x103c)
370 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
371 break;
372 case 0x111d76b6:
373 this->name = "IDT 92HD71B5";
374 break;
375 case 0x111d76d4:
376 this->name = "IDT 92HD83C1C";
377 break;
378 case 0x111d76d5:
379 this->name = "IDT 92HD81B1C";
380 break;
381 case 0x11d4184a:
382 this->name = "Analog Devices AD1884A";
383 break;
384 case 0x11d41882:
385 this->name = "Analog Devices AD1882";
386 break;
387 case 0x11d41883:
388 this->name = "Analog Devices AD1883";
389 break;
390 case 0x11d41884:
391 this->name = "Analog Devices AD1884";
392 break;
393 case 0x11d4194a:
394 this->name = "Analog Devices AD1984A";
395 break;
396 case 0x11d41981:
397 this->name = "Analog Devices AD1981HD";
398 this->qrks |= AZ_QRK_WID_AD1981_OAMP0x00008000;
399 break;
400 case 0x11d41983:
401 this->name = "Analog Devices AD1983";
402 break;
403 case 0x11d41984:
404 this->name = "Analog Devices AD1984";
405 break;
406 case 0x11d41988:
407 this->name = "Analog Devices AD1988A";
408 break;
409 case 0x11d4198b:
410 this->name = "Analog Devices AD1988B";
411 break;
412 case 0x11d4882a:
413 this->name = "Analog Devices AD1882A";
414 break;
415 case 0x11d4989a:
416 this->name = "Analog Devices AD1989A";
417 break;
418 case 0x11d4989b:
419 this->name = "Analog Devices AD1989B";
420 break;
421 case 0x14f15045:
422 this->name = "Conexant CX20549"; /* Venice */
423 break;
424 case 0x14f15047:
425 this->name = "Conexant CX20551"; /* Waikiki */
426 break;
427 case 0x14f15051:
428 this->name = "Conexant CX20561"; /* Hermosa */
429 break;
430 case 0x14f1506e:
431 this->name = "Conexant CX20590";
432 /*
433 * Enable dock audio on Thinkpad docks
434 * 0x17aa : 0x20f2 = Thinkpad T400
435 * 0x17aa : 0x215e = Thinkpad T410
436 * 0x17aa : 0x215f = Thinkpad T510
437 * 0x17aa : 0x21ce = Thinkpad T420
438 * 0x17aa : 0x21cf = Thinkpad T520
439 * 0x17aa : 0x21da = Thinkpad X220
440 * 0x17aa : 0x21db = Thinkpad X220t
441 */
442 if (this->subid == 0x20f217aa ||
443 this->subid == 0x215e17aa ||
444 this->subid == 0x215f17aa ||
445 this->subid == 0x21ce17aa ||
446 this->subid == 0x21cf17aa ||
447 this->subid == 0x21da17aa ||
448 this->subid == 0x21db17aa)
449 this->qrks |= AZ_QRK_WID_TPDOCK30x00040000;
450 break;
451 case 0x434d4980:
452 this->name = "CMedia CMI9880";
453 break;
454 case 0x83847612:
455 this->name = "Sigmatel STAC9230X";
456 break;
457 case 0x83847613:
458 this->name = "Sigmatel STAC9230D";
459 break;
460 case 0x83847614:
461 this->name = "Sigmatel STAC9229X";
462 break;
463 case 0x83847615:
464 this->name = "Sigmatel STAC9229D";
465 break;
466 case 0x83847616:
467 this->name = "Sigmatel STAC9228X";
468 if (this->subid == 0x02271028 || /* DELL_V1400 */
469 this->subid == 0x01f31028) { /* DELL_I1400 */
470 this->qrks |= AZ_QRK_GPIO_UNMUTE_20x00000004;
471 }
472 break;
473 case 0x83847617:
474 this->name = "Sigmatel STAC9228D";
475 break;
476 case 0x83847618:
477 this->name = "Sigmatel STAC9227X";
478 break;
479 case 0x83847619:
480 this->name = "Sigmatel STAC9227D";
481 break;
482 case 0x83847620:
483 this->name = "Sigmatel STAC9274";
484 break;
485 case 0x83847621:
486 this->name = "Sigmatel STAC9274D";
487 break;
488 case 0x83847626:
489 this->name = "Sigmatel STAC9271X";
490 break;
491 case 0x83847627:
492 this->name = "Sigmatel STAC9271D";
493 break;
494 case 0x83847632:
495 this->name = "Sigmatel STAC9202";
496 break;
497 case 0x83847634:
498 this->name = "Sigmatel STAC9250";
499 break;
500 case 0x83847636:
501 this->name = "Sigmatel STAC9251";
502 break;
503 case 0x83847638:
504 this->name = "IDT 92HD700X";
505 break;
506 case 0x83847639:
507 this->name = "IDT 92HD700D";
508 break;
509 case 0x83847645:
510 this->name = "IDT 92HD206X";
511 break;
512 case 0x83847646:
513 this->name = "IDT 92HD206D";
514 break;
515 case 0x83847661:
516 /* FALLTHROUGH */
517 case 0x83847662:
518 this->name = "Sigmatel STAC9225";
519 break;
520 case 0x83847680:
521 this->name = "Sigmatel STAC9220/1";
522 if (this->subid == 0x76808384) { /* APPLE_ID */
523 this->qrks |= AZ_QRK_GPIO_POL_00x00000100 | AZ_QRK_GPIO_UNMUTE_00x00000001 |
524 AZ_QRK_GPIO_UNMUTE_10x00000002;
525 }
526 break;
527 case 0x83847682:
528 /* FALLTHROUGH */
529 case 0x83847683:
530 this->name = "Sigmatel STAC9221D"; /* aka IDT 92HD202 */
531 break;
532 case 0x83847690:
533 this->name = "Sigmatel STAC9200"; /* aka IDT 92HD001 */
534 break;
535 case 0x83847691:
536 this->name = "Sigmatel STAC9200D";
537 break;
538 case 0x83847698:
539 this->name = "IDT 92HD005";
540 break;
541 case 0x83847699:
542 this->name = "IDT 92HD005D";
543 break;
544 case 0x838476a0:
545 this->name = "Sigmatel STAC9205X";
546 if (this->subid == 0x01f91028 || /* DELL_D630 */
547 this->subid == 0x02281028) { /* DELL_V1500 */
548 this->qrks |= AZ_QRK_GPIO_UNMUTE_00x00000001;
549 }
550 break;
551 case 0x838476a1:
552 this->name = "Sigmatel STAC9205D";
553 break;
554 case 0x838476a2:
555 this->name = "Sigmatel STAC9204X";
556 break;
557 case 0x838476a3:
558 this->name = "Sigmatel STAC9204D";
559 break;
560 }
561 return 0;
562}
563
564/* ----------------------------------------------------------------
565 * functions for generic codecs
566 * ---------------------------------------------------------------- */
567
568int
569azalia_widget_enabled(const codec_t *this, nid_t nid)
570{
571 if (!VALID_WIDGET_NID(nid, this)(nid == (this)->audiofunc || (nid >= (this)->wstart &&
nid < (this)->wend))
|| !this->w[nid].enable)
572 return 0;
573 return 1;
574}
575
576int
577azalia_init_dacgroup(codec_t *this)
578{
579 this->dacs.ngroups = 0;
580 if (this->na_dacs > 0)
581 azalia_add_convgroup(this, &this->dacs,
582 this->opins, this->nopins,
583 this->a_dacs, this->na_dacs,
584 COP_AWTYPE_AUDIO_OUTPUT0x0, 0);
585 if (this->na_dacs_d > 0)
586 azalia_add_convgroup(this, &this->dacs,
587 this->opins_d, this->nopins_d,
588 this->a_dacs_d, this->na_dacs_d,
589 COP_AWTYPE_AUDIO_OUTPUT0x0, COP_AWCAP_DIGITAL0x200);
590 this->dacs.cur = 0;
591
592 this->adcs.ngroups = 0;
593 if (this->na_adcs > 0)
594 azalia_add_convgroup(this, &this->adcs,
595 this->ipins, this->nipins,
596 this->a_adcs, this->na_adcs,
597 COP_AWTYPE_AUDIO_INPUT0x1, 0);
598 if (this->na_adcs_d > 0)
599 azalia_add_convgroup(this, &this->adcs,
600 this->ipins_d, this->nipins_d,
601 this->a_adcs_d, this->na_adcs_d,
602 COP_AWTYPE_AUDIO_INPUT0x1, COP_AWCAP_DIGITAL0x200);
603 this->adcs.cur = 0;
604
605 return 0;
606}
607
608int
609azalia_add_convgroup(codec_t *this, convgroupset_t *group,
610 struct io_pin *pins, int npins, nid_t *all_convs, int nall_convs,
611 uint32_t type, uint32_t digital)
612{
613 nid_t convs[HDA_MAX_CHANNELS16];
614 int nconvs;
615 nid_t conv;
616 int i, j, k;
617
618 nconvs = 0;
619
620 /* default pin connections */
621 for (i = 0; i < npins; i++) {
622 conv = pins[i].conv;
623 if (conv < 0)
624 continue;
625 for (j = 0; j < nconvs; j++) {
626 if (convs[j] == conv)
627 break;
628 }
629 if (j < nconvs)
630 continue;
631 convs[nconvs++] = conv;
632 if (nconvs >= nall_convs) {
633 goto done;
634 }
635 }
636 /* non-default connections */
637 for (i = 0; i < npins; i++) {
638 for (j = 0; j < nall_convs; j++) {
639 conv = all_convs[j];
640 for (k = 0; k < nconvs; k++) {
641 if (convs[k] == conv)
642 break;
643 }
644 if (k < nconvs)
645 continue;
646 if (type == COP_AWTYPE_AUDIO_OUTPUT0x0) {
647 k = azalia_codec_fnode(this, conv,
648 pins[i].nid, 0);
649 if (k < 0)
650 continue;
651 } else {
652 if (!azalia_widget_enabled(this, conv))
653 continue;
654 k = azalia_codec_fnode(this, pins[i].nid,
655 conv, 0);
656 if (k < 0)
657 continue;
658 }
659 convs[nconvs++] = conv;
660 if (nconvs >= nall_convs) {
661 goto done;
662 }
663 }
664 }
665 /* Make sure the speaker dac is part of the analog output convgroup
666 * or it won't get connected by azalia_codec_connect_stream().
667 */
668 if (type == COP_AWTYPE_AUDIO_OUTPUT0x0 && !digital &&
669 nconvs < nall_convs && this->spkr_dac != -1) {
670 for (i = 0; i < nconvs; i++)
671 if (convs[i] == this->spkr_dac)
672 break;
673 if (i == nconvs)
674 convs[nconvs++] = this->spkr_dac;
675 }
676done:
677 for (i = 0; i < nconvs; i++)
678 group->groups[group->ngroups].conv[i] = convs[i];
679 if (nconvs > 0) {
680 group->groups[group->ngroups].nconv = i;
681 group->ngroups++;
682 }
683
684 /* Disable converters that aren't in a convgroup. */
685 for (i = 0; i < nall_convs; i++) {
686 conv = all_convs[i];
687 for (j = 0; j < nconvs; j++)
688 if (convs[j] == conv)
689 break;
690 if (j == nconvs)
691 this->w[conv].enable = 0;
692 }
693
694 return 0;
695}
696
697int
698azalia_codec_fnode(codec_t *this, nid_t node, int index, int depth)
699{
700 const widget_t *w;
701 int i, ret;
702
703 w = &this->w[index];
704 if (w->nid == node) {
705 return index;
706 }
707 /* back at the beginning or a bad end */
708 if (depth > 0 &&
709 (w->type == COP_AWTYPE_PIN_COMPLEX0x4 ||
710 w->type == COP_AWTYPE_BEEP_GENERATOR0x7 ||
711 w->type == COP_AWTYPE_AUDIO_OUTPUT0x0 ||
712 w->type == COP_AWTYPE_AUDIO_INPUT0x1))
713 return -1;
714 if (++depth >= 10)
715 return -1;
716 for (i = 0; i < w->nconnections; i++) {
717 if (!azalia_widget_enabled(this, w->connections[i]))
718 continue;
719 ret = azalia_codec_fnode(this, node, w->connections[i], depth);
720 if (ret >= 0)
721 return ret;
722 }
723 return -1;
724}
725
726int
727azalia_unsol_event(codec_t *this, int tag)
728{
729 mixer_ctrl_t mc;
730 uint32_t result;
731 int i, err, vol, vol2;
732
733 err = 0;
734 tag = CORB_UNSOL_TAG(tag)(tag & 0x3f);
735 switch (tag) {
736 case AZ_TAG_SPKR0x01:
737 mc.type = AUDIO_MIXER_ENUM1;
738 vol = 0;
739 for (i = 0; !vol && !err && i < this->nsense_pins; i++) {
740 if (!(this->spkr_muters & (1 << i)))
741 continue;
742 err = azalia_comresp(this, this->sense_pins[i],
743 CORB_GET_PIN_WIDGET_CONTROL0xf07, 0, &result);
744 if (err || !(result & CORB_PWC_OUTPUT0x40))
745 continue;
746 err = azalia_comresp(this, this->sense_pins[i],
747 CORB_GET_PIN_SENSE0xf09, 0, &result);
748 if (!err && (result & CORB_PS_PRESENCE0x80000000))
749 vol = 1;
750 }
751 if (err)
752 break;
753 this->spkr_muted = vol;
754 switch(this->spkr_mute_method) {
755 case AZ_SPKR_MUTE_SPKR_MUTE1:
756 mc.un.ord = vol;
757 err = azalia_mixer_set(this, this->speaker,
758 MI_TARGET_OUTAMP0x100, &mc);
759 if (!err && this->speaker2 != -1 &&
760 (this->w[this->speaker2].widgetcap & COP_AWCAP_OUTAMP0x004) &&
761 (this->w[this->speaker2].outamp_cap & COP_AMPCAP_MUTE0x80000000))
762 err = azalia_mixer_set(this, this->speaker2,
763 MI_TARGET_OUTAMP0x100, &mc);
764 break;
765 case AZ_SPKR_MUTE_SPKR_DIR2:
766 mc.un.ord = vol ? 0 : 1;
767 err = azalia_mixer_set(this, this->speaker,
768 MI_TARGET_PINDIR0x102, &mc);
769 if (!err && this->speaker2 != -1 &&
770 (this->w[this->speaker2].d.pin.cap & COP_PINCAP_OUTPUT0x00000010) &&
771 (this->w[this->speaker2].d.pin.cap & COP_PINCAP_INPUT0x00000020))
772 err = azalia_mixer_set(this, this->speaker2,
773 MI_TARGET_PINDIR0x102, &mc);
774 break;
775 case AZ_SPKR_MUTE_DAC_MUTE3:
776 mc.un.ord = vol;
777 err = azalia_mixer_set(this, this->spkr_dac,
778 MI_TARGET_OUTAMP0x100, &mc);
779 break;
780 }
781 break;
782
783 case AZ_TAG_PLAYVOL0x02:
784 if (this->playvols.master == this->audiofunc)
785 return EINVAL22;
786 err = azalia_comresp(this, this->playvols.master,
787 CORB_GET_VOLUME_KNOB0xf0f, 0, &result);
788 if (err)
789 return err;
790
791 vol = CORB_VKNOB_VOLUME(result)(result & 0x7f) - this->playvols.hw_step;
792 vol2 = vol * (AUDIO_MAX_GAIN255 / this->playvols.hw_nsteps);
793 this->playvols.hw_step = CORB_VKNOB_VOLUME(result)(result & 0x7f);
794
795 vol = vol2 + this->playvols.vol_l;
796 if (vol < 0)
797 vol = 0;
798 else if (vol > AUDIO_MAX_GAIN255)
799 vol = AUDIO_MAX_GAIN255;
800 this->playvols.vol_l = vol;
801
802 vol = vol2 + this->playvols.vol_r;
803 if (vol < 0)
804 vol = 0;
805 else if (vol > AUDIO_MAX_GAIN255)
806 vol = AUDIO_MAX_GAIN255;
807 this->playvols.vol_r = vol;
808
809 mc.type = AUDIO_MIXER_VALUE3;
810 mc.un.value.num_channels = 2;
811 mc.un.value.level[0] = this->playvols.vol_l;
812 mc.un.value.level[1] = this->playvols.vol_r;
813 err = azalia_mixer_set(this, this->playvols.master,
814 MI_TARGET_PLAYVOL0x10d, &mc);
815 break;
816
817 default:
818 DPRINTF(("%s: unknown tag %d\n", __func__, tag))do {} while (0 );
819 break;
820 }
821
822 return err;
823}
824
825
826/* ----------------------------------------------------------------
827 * Generic mixer functions
828 * ---------------------------------------------------------------- */
829
830int
831azalia_mixer_init(codec_t *this)
832{
833 /*
834 * pin "<color>%2.2x"
835 * audio output "dac%2.2x"
836 * audio input "adc%2.2x"
837 * mixer "mixer%2.2x"
838 * selector "sel%2.2x"
839 */
840 const widget_t *w, *ww;
841 mixer_item_t *m;
842 int err, i, j, k, bits;
843
844 this->maxmixers = 10;
845 this->nmixers = 0;
846 this->mixers = mallocarray(this->maxmixers, sizeof(mixer_item_t),
847 M_DEVBUF2, M_NOWAIT0x0002 | M_ZERO0x0008);
848 if (this->mixers == NULL((void *)0)) {
849 printf("%s: out of memory in %s\n", XNAME(this)(((struct device *)this->az)->dv_xname), __func__);
850 return ENOMEM12;
851 }
852
853 /* register classes */
854 m = &this->mixers[AZ_CLASS_INPUT0];
855 m->devinfo.index = AZ_CLASS_INPUT0;
856 strlcpy(m->devinfo.label.name, AudioCinputs"inputs",
857 sizeof(m->devinfo.label.name));
858 m->devinfo.type = AUDIO_MIXER_CLASS0;
859 m->devinfo.mixer_class = AZ_CLASS_INPUT0;
860 m->devinfo.next = AUDIO_MIXER_LAST-1;
861 m->devinfo.prev = AUDIO_MIXER_LAST-1;
862 m->nid = 0;
863
864 m = &this->mixers[AZ_CLASS_OUTPUT1];
865 m->devinfo.index = AZ_CLASS_OUTPUT1;
866 strlcpy(m->devinfo.label.name, AudioCoutputs"outputs",
867 sizeof(m->devinfo.label.name));
868 m->devinfo.type = AUDIO_MIXER_CLASS0;
869 m->devinfo.mixer_class = AZ_CLASS_OUTPUT1;
870 m->devinfo.next = AUDIO_MIXER_LAST-1;
871 m->devinfo.prev = AUDIO_MIXER_LAST-1;
872 m->nid = 0;
873
874 m = &this->mixers[AZ_CLASS_RECORD2];
875 m->devinfo.index = AZ_CLASS_RECORD2;
876 strlcpy(m->devinfo.label.name, AudioCrecord"record",
877 sizeof(m->devinfo.label.name));
878 m->devinfo.type = AUDIO_MIXER_CLASS0;
879 m->devinfo.mixer_class = AZ_CLASS_RECORD2;
880 m->devinfo.next = AUDIO_MIXER_LAST-1;
881 m->devinfo.prev = AUDIO_MIXER_LAST-1;
882 m->nid = 0;
883
884 this->nmixers = AZ_CLASS_RECORD2 + 1;
885
886#define MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
\
887 mixer_devinfo_t *d; \
888 err = azalia_mixer_ensure_capacity(this, this->nmixers + 1); \
889 if (err) \
890 return err; \
891 m = &this->mixers[this->nmixers]; \
892 d = &m->devinfo; \
893 m->nid = i
894
895 FOR_EACH_WIDGET(this, i)for (i = (this)->wstart; i < (this)->wend; i++) {
896
897 w = &this->w[i];
898 if (!w->enable)
899 continue;
900
901 /* selector */
902 if (w->nconnections > 0 && w->type != COP_AWTYPE_AUDIO_MIXER0x2 &&
903 !(w->nconnections == 1 &&
904 azalia_widget_enabled(this, w->connections[0]) &&
905 strcmp(w->name, this->w[w->connections[0]].name) == 0) &&
906 w->nid != this->mic) {
907 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
908 snprintf(d->label.name, sizeof(d->label.name),
909 "%s_source", w->name);
910 d->type = AUDIO_MIXER_ENUM1;
911 if (w->mixer_class >= 0)
912 d->mixer_class = w->mixer_class;
913 else {
914 if (w->type == COP_AWTYPE_AUDIO_SELECTOR0x3)
915 d->mixer_class = AZ_CLASS_INPUT0;
916 else
917 d->mixer_class = AZ_CLASS_OUTPUT1;
918 }
919 m->target = MI_TARGET_CONNLIST0x101;
920 for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
921 if (!azalia_widget_enabled(this,
922 w->connections[j]))
923 continue;
924 d->un.e.member[k].ord = j;
925 strlcpy(d->un.e.member[k].label.name,
926 this->w[w->connections[j]].name,
927 MAX_AUDIO_DEV_LEN16);
928 k++;
929 }
930 d->un.e.num_mem = k;
931 this->nmixers++;
932 }
933
934 /* output mute */
935 if (w->widgetcap & COP_AWCAP_OUTAMP0x004 &&
936 w->outamp_cap & COP_AMPCAP_MUTE0x80000000 &&
937 w->nid != this->mic) {
938 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
939 snprintf(d->label.name, sizeof(d->label.name),
940 "%s_mute", w->name);
941 if (w->mixer_class >= 0)
942 d->mixer_class = w->mixer_class;
943 else {
944 if (w->type == COP_AWTYPE_AUDIO_MIXER0x2 ||
945 w->type == COP_AWTYPE_AUDIO_SELECTOR0x3 ||
946 w->type == COP_AWTYPE_PIN_COMPLEX0x4)
947 d->mixer_class = AZ_CLASS_OUTPUT1;
948 else
949 d->mixer_class = AZ_CLASS_INPUT0;
950 }
951 m->target = MI_TARGET_OUTAMP0x100;
952 azalia_devinfo_offon(d);
953 this->nmixers++;
954 }
955
956 /* output gain */
957 if (w->widgetcap & COP_AWCAP_OUTAMP0x004 &&
958 COP_AMPCAP_NUMSTEPS(w->outamp_cap)((w->outamp_cap >> 8) & 0x7f) &&
959 w->nid != this->mic) {
960 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
961 snprintf(d->label.name, sizeof(d->label.name),
962 "%s", w->name);
963 d->type = AUDIO_MIXER_VALUE3;
964 if (w->mixer_class >= 0)
965 d->mixer_class = w->mixer_class;
966 else {
967 if (w->type == COP_AWTYPE_AUDIO_MIXER0x2 ||
968 w->type == COP_AWTYPE_AUDIO_SELECTOR0x3 ||
969 w->type == COP_AWTYPE_PIN_COMPLEX0x4)
970 d->mixer_class = AZ_CLASS_OUTPUT1;
971 else
972 d->mixer_class = AZ_CLASS_INPUT0;
973 }
974 m->target = MI_TARGET_OUTAMP0x100;
975 d->un.v.num_channels = WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1);
976 d->un.v.units.name[0] = 0;
977 d->un.v.delta =
978 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap))(255 / (((w->outamp_cap >> 8) & 0x7f)));
979 this->nmixers++;
980 }
981
982 /* input mute */
983 if (w->widgetcap & COP_AWCAP_INAMP0x002 &&
984 w->inamp_cap & COP_AMPCAP_MUTE0x80000000 &&
985 w->nid != this->speaker &&
986 w->nid != this->speaker2) {
987 if (w->type != COP_AWTYPE_AUDIO_MIXER0x2) {
988 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
989 snprintf(d->label.name, sizeof(d->label.name),
990 "%s_mute", w->name);
991 if (w->mixer_class >= 0)
992 d->mixer_class = w->mixer_class;
993 else
994 d->mixer_class = AZ_CLASS_INPUT0;
995 m->target = 0;
996 azalia_devinfo_offon(d);
997 this->nmixers++;
998 } else {
999 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1000 snprintf(d->label.name, sizeof(d->label.name),
1001 "%s_source", w->name);
1002 m->target = MI_TARGET_MUTESET0x10a;
1003 d->type = AUDIO_MIXER_SET2;
1004 if (w->mixer_class >= 0)
1005 d->mixer_class = w->mixer_class;
1006 else
1007 d->mixer_class = AZ_CLASS_INPUT0;
1008 for (j = 0, k = 0;
1009 j < w->nconnections && k < 32; j++) {
1010 if (!azalia_widget_enabled(this,
1011 w->connections[j]))
1012 continue;
1013 if (w->connections[j] == this->speaker ||
1014 w->connections[j] == this->speaker2)
1015 continue;
1016 d->un.s.member[k].mask = 1 << j;
1017 strlcpy(d->un.s.member[k].label.name,
1018 this->w[w->connections[j]].name,
1019 MAX_AUDIO_DEV_LEN16);
1020 k++;
1021 }
1022 d->un.s.num_mem = k;
1023 if (k != 0)
1024 this->nmixers++;
1025 }
1026 }
1027
1028 /* input gain */
1029 if (w->widgetcap & COP_AWCAP_INAMP0x002 &&
1030 COP_AMPCAP_NUMSTEPS(w->inamp_cap)((w->inamp_cap >> 8) & 0x7f) &&
1031 w->nid != this->speaker &&
1032 w->nid != this->speaker2) {
1033 if (w->type != COP_AWTYPE_AUDIO_SELECTOR0x3 &&
1034 w->type != COP_AWTYPE_AUDIO_MIXER0x2) {
1035 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1036 snprintf(d->label.name, sizeof(d->label.name),
1037 "%s", w->name);
1038 d->type = AUDIO_MIXER_VALUE3;
1039 if (w->mixer_class >= 0)
1040 d->mixer_class = w->mixer_class;
1041 else
1042 d->mixer_class = AZ_CLASS_INPUT0;
1043 m->target = 0;
1044 d->un.v.num_channels = WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1);
1045 d->un.v.units.name[0] = 0;
1046 d->un.v.delta =
1047 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap))(255 / (((w->inamp_cap >> 8) & 0x7f)));
1048 this->nmixers++;
1049 } else {
1050 for (j = 0; j < w->nconnections; j++) {
1051 if (!azalia_widget_enabled(this,
1052 w->connections[j]))
1053 continue;
1054 if (w->connections[j] == this->speaker ||
1055 w->connections[j] == this->speaker2)
1056 continue;
1057 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1058 snprintf(d->label.name,
1059 sizeof(d->label.name), "%s_%s",
1060 w->name,
1061 this->w[w->connections[j]].name);
1062 d->type = AUDIO_MIXER_VALUE3;
1063 if (w->mixer_class >= 0)
1064 d->mixer_class = w->mixer_class;
1065 else
1066 d->mixer_class = AZ_CLASS_INPUT0;
1067 m->target = j;
1068 d->un.v.num_channels = WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1);
1069 d->un.v.units.name[0] = 0;
1070 d->un.v.delta =
1071 MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap))(255 / (((w->inamp_cap >> 8) & 0x7f)));
1072 this->nmixers++;
1073 }
1074 }
1075 }
1076
1077 /* hardcoded mixer inputs */
1078 if (w->type == COP_AWTYPE_AUDIO_MIXER0x2 &&
1079 !(w->widgetcap & COP_AWCAP_INAMP0x002)) {
1080 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1081 snprintf(d->label.name, sizeof(d->label.name),
1082 "%s_source", w->name);
1083 m->target = MI_TARGET_MIXERSET0x10f;
1084 d->type = AUDIO_MIXER_SET2;
1085 if (w->mixer_class >= 0)
1086 d->mixer_class = w->mixer_class;
1087 else
1088 d->mixer_class = AZ_CLASS_INPUT0;
1089 for (j = 0, k = 0;
1090 j < w->nconnections && k < 32; j++) {
1091 if (!azalia_widget_enabled(this,
1092 w->connections[j]))
1093 continue;
1094 if (w->connections[j] == this->speaker ||
1095 w->connections[j] == this->speaker2)
1096 continue;
1097 d->un.s.member[k].mask = 1 << j;
1098 strlcpy(d->un.s.member[k].label.name,
1099 this->w[w->connections[j]].name,
1100 MAX_AUDIO_DEV_LEN16);
1101 k++;
1102 }
1103 d->un.s.num_mem = k;
1104 if (k != 0)
1105 this->nmixers++;
1106 }
1107
1108 /* pin direction */
1109 if (w->type == COP_AWTYPE_PIN_COMPLEX0x4 &&
1110 ((w->d.pin.cap & COP_PINCAP_OUTPUT0x00000010 &&
1111 w->d.pin.cap & COP_PINCAP_INPUT0x00000020) ||
1112 COP_PINCAP_VREF(w->d.pin.cap)((w->d.pin.cap >> 8) & 0xff) > 1)) {
1113
1114 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1115 snprintf(d->label.name, sizeof(d->label.name),
1116 "%s_dir", w->name);
1117 d->type = AUDIO_MIXER_ENUM1;
1118 d->mixer_class = AZ_CLASS_OUTPUT1;
1119 m->target = MI_TARGET_PINDIR0x102;
1120
1121 k = 0;
1122 d->un.e.member[k].ord = 0;
1123 strlcpy(d->un.e.member[k].label.name, "none",
1124 MAX_AUDIO_DEV_LEN16);
1125 k++;
1126
1127 if (w->d.pin.cap & COP_PINCAP_OUTPUT0x00000010) {
1128 d->un.e.member[k].ord = 1;
1129 strlcpy(d->un.e.member[k].label.name,
1130 AudioNoutput"output", MAX_AUDIO_DEV_LEN16);
1131 k++;
1132 }
1133
1134 if (w->d.pin.cap & COP_PINCAP_INPUT0x00000020) {
1135 d->un.e.member[k].ord = 2;
1136 strlcpy(d->un.e.member[k].label.name,
1137 AudioNinput"input", MAX_AUDIO_DEV_LEN16);
1138 k++;
1139
1140 for (j = 0; j < 4; j++) {
1141 if (j == 0) {
1142 bits = (1 << CORB_PWC_VREF_GND0x02);
1143 strlcpy(d->un.e.member[k].label.name,
1144 AudioNinput"input" "-vr0",
1145 MAX_AUDIO_DEV_LEN16);
1146 } else if (j == 1) {
1147 bits = (1 << CORB_PWC_VREF_500x01);
1148 strlcpy(d->un.e.member[k].label.name,
1149 AudioNinput"input" "-vr50",
1150 MAX_AUDIO_DEV_LEN16);
1151 } else if (j == 2) {
1152 bits = (1 << CORB_PWC_VREF_800x04);
1153 strlcpy(d->un.e.member[k].label.name,
1154 AudioNinput"input" "-vr80",
1155 MAX_AUDIO_DEV_LEN16);
1156 } else if (j == 3) {
1157 bits = (1 << CORB_PWC_VREF_1000x05);
1158 strlcpy(d->un.e.member[k].label.name,
1159 AudioNinput"input" "-vr100",
1160 MAX_AUDIO_DEV_LEN16);
1161 }
1162 if ((COP_PINCAP_VREF(w->d.pin.cap)((w->d.pin.cap >> 8) & 0xff) &
1163 bits) == bits) {
1164 d->un.e.member[k].ord = j + 3;
1165 k++;
1166 }
1167 }
1168 }
1169 d->un.e.num_mem = k;
1170 this->nmixers++;
1171 }
1172
1173 /* pin headphone-boost */
1174 if (w->type == COP_AWTYPE_PIN_COMPLEX0x4 &&
1175 w->d.pin.cap & COP_PINCAP_HEADPHONE0x00000008 &&
1176 w->nid != this->mic) {
1177 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1178 snprintf(d->label.name, sizeof(d->label.name),
1179 "%s_boost", w->name);
1180 d->mixer_class = AZ_CLASS_OUTPUT1;
1181 m->target = MI_TARGET_PINBOOST0x103;
1182 azalia_devinfo_offon(d);
1183 this->nmixers++;
1184 }
1185
1186 if (w->type == COP_AWTYPE_PIN_COMPLEX0x4 &&
1187 w->d.pin.cap & COP_PINCAP_EAPD0x00010000) {
1188 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1189 snprintf(d->label.name, sizeof(d->label.name),
1190 "%s_eapd", w->name);
1191 d->mixer_class = AZ_CLASS_OUTPUT1;
1192 m->target = MI_TARGET_EAPD0x109;
1193 azalia_devinfo_offon(d);
1194 this->nmixers++;
1195 }
1196 }
1197
1198 /* sense pins */
1199 for (i = 0; i < this->nsense_pins; i++) {
1200 if (!azalia_widget_enabled(this, this->sense_pins[i])) {
1201 DPRINTF(("%s: sense pin %2.2x not found\n",do {} while (0 )
1202 __func__, this->sense_pins[i]))do {} while (0 );
1203 continue;
1204 }
1205
1206 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1207 m->nid = this->w[this->sense_pins[i]].nid;
1208 snprintf(d->label.name, sizeof(d->label.name), "%s_sense",
1209 this->w[this->sense_pins[i]].name);
1210 d->type = AUDIO_MIXER_ENUM1;
1211 d->mixer_class = AZ_CLASS_OUTPUT1;
1212 m->target = MI_TARGET_PINSENSE0x10b;
1213 d->un.e.num_mem = 2;
1214 d->un.e.member[0].ord = 0;
1215 strlcpy(d->un.e.member[0].label.name, "unplugged",
1216 MAX_AUDIO_DEV_LEN16);
1217 d->un.e.member[1].ord = 1;
1218 strlcpy(d->un.e.member[1].label.name, "plugged",
1219 MAX_AUDIO_DEV_LEN16);
1220 this->nmixers++;
1221 }
1222
1223 /* spkr mute by jack sense */
1224 this->spkr_mute_method = AZ_SPKR_MUTE_NONE0;
1225 if (this->speaker != -1 && this->spkr_dac != -1 && this->nsense_pins > 0) {
1226 w = &this->w[this->speaker];
1227 if ((w->widgetcap & COP_AWCAP_OUTAMP0x004) &&
1228 (w->outamp_cap & COP_AMPCAP_MUTE0x80000000))
1229 this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_MUTE1;
1230 else if ((w->d.pin.cap & COP_PINCAP_OUTPUT0x00000010) &&
1231 (w->d.pin.cap & COP_PINCAP_INPUT0x00000020))
1232 this->spkr_mute_method = AZ_SPKR_MUTE_SPKR_DIR2;
1233 else {
1234 w = &this->w[this->spkr_dac];
1235 if (w->nid != this->dacs.groups[0].conv[0] &&
1236 (w->widgetcap & COP_AWCAP_OUTAMP0x004) &&
1237 (w->outamp_cap & COP_AMPCAP_MUTE0x80000000))
1238 this->spkr_mute_method = AZ_SPKR_MUTE_DAC_MUTE3;
1239 }
1240 }
1241 if (this->spkr_mute_method != AZ_SPKR_MUTE_NONE0) {
1242 w = &this->w[this->speaker];
1243 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1244 m->nid = w->nid;
1245 snprintf(d->label.name, sizeof(d->label.name),
1246 "%s_muters", w->name);
1247 m->target = MI_TARGET_SENSESET0x10c;
1248 d->type = AUDIO_MIXER_SET2;
1249 d->mixer_class = AZ_CLASS_OUTPUT1;
1250 this->spkr_muters = 0;
1251 for (i = 0, j = 0; i < this->nsense_pins; i++) {
1252 ww = &this->w[this->sense_pins[i]];
1253 if (!(ww->d.pin.cap & COP_PINCAP_OUTPUT0x00000010))
1254 continue;
1255 if (!(ww->widgetcap & COP_AWCAP_UNSOL0x080))
1256 continue;
1257 d->un.s.member[j].mask = 1 << i;
1258 this->spkr_muters |= (1 << i);
1259 strlcpy(d->un.s.member[j++].label.name, ww->name,
1260 MAX_AUDIO_DEV_LEN16);
1261 }
1262 d->un.s.num_mem = j;
1263 if (j != 0)
1264 this->nmixers++;
1265 }
1266
1267 /* playback volume group */
1268 if (this->playvols.nslaves > 0) {
1269 mixer_devinfo_t *d;
1270 err = azalia_mixer_ensure_capacity(this,
1271 this->nmixers + 3);
1272
1273 /* volume */
1274 m = &this->mixers[this->nmixers];
1275 m->nid = this->playvols.master;
1276 m->target = MI_TARGET_PLAYVOL0x10d;
1277 d = &m->devinfo;
1278 d->mixer_class = AZ_CLASS_OUTPUT1;
1279 snprintf(d->label.name, sizeof(d->label.name),
1280 "%s", AudioNmaster"master");
1281 d->type = AUDIO_MIXER_VALUE3;
1282 d->un.v.num_channels = 2;
1283 d->un.v.delta = 8;
1284 this->nmixers++;
1285 d->next = this->nmixers;
1286
1287 /* mute */
1288 m = &this->mixers[this->nmixers];
1289 m->nid = this->playvols.master;
1290 m->target = MI_TARGET_PLAYVOL0x10d;
1291 d = &m->devinfo;
1292 d->prev = this->nmixers - 1;
1293 d->mixer_class = AZ_CLASS_OUTPUT1;
1294 snprintf(d->label.name, sizeof(d->label.name),
1295 "%s", AudioNmute"mute");
1296 azalia_devinfo_offon(d);
1297 this->nmixers++;
1298 d->next = this->nmixers;
1299
1300 /* slaves */
1301 m = &this->mixers[this->nmixers];
1302 m->nid = this->playvols.master;
1303 m->target = MI_TARGET_PLAYVOL0x10d;
1304 d = &m->devinfo;
1305 d->prev = this->nmixers - 1;
1306 d->mixer_class = AZ_CLASS_OUTPUT1;
1307 snprintf(d->label.name, sizeof(d->label.name),
1308 "%s", "slaves");
1309 d->type = AUDIO_MIXER_SET2;
1310 for (i = 0, j = 0; i < this->playvols.nslaves; i++) {
1311 ww = &this->w[this->playvols.slaves[i]];
1312 d->un.s.member[j].mask = (1 << i);
1313 strlcpy(d->un.s.member[j++].label.name, ww->name,
1314 MAX_AUDIO_DEV_LEN16);
1315 }
1316 d->un.s.num_mem = j;
1317 this->nmixers++;
1318 }
1319
1320 /* recording volume group */
1321 if (this->recvols.nslaves > 0) {
1322 mixer_devinfo_t *d;
1323 err = azalia_mixer_ensure_capacity(this,
1324 this->nmixers + 3);
1325
1326 /* volume */
1327 m = &this->mixers[this->nmixers];
1328 m->nid = this->recvols.master;
1329 m->target = MI_TARGET_RECVOL0x10e;
1330 d = &m->devinfo;
1331 d->mixer_class = AZ_CLASS_RECORD2;
1332 snprintf(d->label.name, sizeof(d->label.name),
1333 "%s", AudioNvolume"volume");
1334 d->type = AUDIO_MIXER_VALUE3;
1335 d->un.v.num_channels = 2;
1336 d->un.v.delta = 8;
1337 this->nmixers++;
1338 d->next = this->nmixers;
1339
1340 /* mute */
1341 m = &this->mixers[this->nmixers];
1342 m->nid = this->recvols.master;
1343 m->target = MI_TARGET_RECVOL0x10e;
1344 d = &m->devinfo;
1345 d->prev = this->nmixers - 1;
1346 d->mixer_class = AZ_CLASS_RECORD2;
1347 snprintf(d->label.name, sizeof(d->label.name),
1348 "%s", AudioNmute"mute");
1349 azalia_devinfo_offon(d);
1350 this->nmixers++;
1351 d->next = this->nmixers;
1352
1353 /* slaves */
1354 m = &this->mixers[this->nmixers];
1355 m->nid = this->recvols.master;
1356 m->target = MI_TARGET_RECVOL0x10e;
1357 d = &m->devinfo;
1358 d->prev = this->nmixers - 1;
1359 d->mixer_class = AZ_CLASS_RECORD2;
1360 snprintf(d->label.name, sizeof(d->label.name),
1361 "%s", "slaves");
1362 d->type = AUDIO_MIXER_SET2;
1363 for (i = 0, j = 0; i < this->recvols.nslaves; i++) {
1364 ww = &this->w[this->recvols.slaves[i]];
1365 d->un.s.member[j].mask = (1 << i);
1366 strlcpy(d->un.s.member[j++].label.name, ww->name,
1367 MAX_AUDIO_DEV_LEN16);
1368 }
1369 d->un.s.num_mem = j;
1370 this->nmixers++;
1371 }
1372
1373 /* if the codec has more than one DAC group, the first is analog
1374 * and the second is digital.
1375 */
1376 if (this->dacs.ngroups > 1) {
1377 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1378 strlcpy(d->label.name, AudioNmode"mode", sizeof(d->label.name));
1379 d->type = AUDIO_MIXER_ENUM1;
1380 d->mixer_class = AZ_CLASS_OUTPUT1;
1381 m->target = MI_TARGET_DAC0x104;
1382 m->nid = this->audiofunc;
1383 d->un.e.member[0].ord = 0;
1384 strlcpy(d->un.e.member[0].label.name, "analog",
1385 MAX_AUDIO_DEV_LEN16);
1386 d->un.e.member[1].ord = 1;
1387 strlcpy(d->un.e.member[1].label.name, "digital",
1388 MAX_AUDIO_DEV_LEN16);
1389 d->un.e.num_mem = 2;
1390 this->nmixers++;
1391 }
1392
1393 /* if the codec has more than one ADC group, the first is analog
1394 * and the second is digital.
1395 */
1396 if (this->adcs.ngroups > 1) {
1397 MIXER_REG_PROLOGmixer_devinfo_t *d; err = azalia_mixer_ensure_capacity(this, this
->nmixers + 1); if (err) return err; m = &this->mixers
[this->nmixers]; d = &m->devinfo; m->nid = i
;
1398 strlcpy(d->label.name, AudioNmode"mode", sizeof(d->label.name));
1399 d->type = AUDIO_MIXER_ENUM1;
1400 d->mixer_class = AZ_CLASS_RECORD2;
1401 m->target = MI_TARGET_ADC0x105;
1402 m->nid = this->audiofunc;
1403 d->un.e.member[0].ord = 0;
1404 strlcpy(d->un.e.member[0].label.name, "analog",
1405 MAX_AUDIO_DEV_LEN16);
1406 d->un.e.member[1].ord = 1;
1407 strlcpy(d->un.e.member[1].label.name, "digital",
1408 MAX_AUDIO_DEV_LEN16);
1409 d->un.e.num_mem = 2;
1410 this->nmixers++;
1411 }
1412
1413 azalia_mixer_fix_indexes(this);
1414 azalia_mixer_default(this);
1415 return 0;
1416}
1417
1418void
1419azalia_devinfo_offon(mixer_devinfo_t *d)
1420{
1421 d->type = AUDIO_MIXER_ENUM1;
1422 d->un.e.num_mem = 2;
1423 d->un.e.member[0].ord = 0;
1424 strlcpy(d->un.e.member[0].label.name, AudioNoff"off", MAX_AUDIO_DEV_LEN16);
1425 d->un.e.member[1].ord = 1;
1426 strlcpy(d->un.e.member[1].label.name, AudioNon"on", MAX_AUDIO_DEV_LEN16);
1427}
1428
1429int
1430azalia_mixer_ensure_capacity(codec_t *this, size_t newsize)
1431{
1432 size_t newmax;
1433 void *newbuf;
1434
1435 if (this->maxmixers >= newsize)
1436 return 0;
1437 newmax = this->maxmixers + 10;
1438 if (newmax < newsize)
1439 newmax = newsize;
1440 newbuf = mallocarray(newmax, sizeof(mixer_item_t), M_DEVBUF2,
1441 M_NOWAIT0x0002 | M_ZERO0x0008);
1442 if (newbuf == NULL((void *)0)) {
1443 printf("%s: out of memory in %s\n", XNAME(this)(((struct device *)this->az)->dv_xname), __func__);
1444 return ENOMEM12;
1445 }
1446 bcopy(this->mixers, newbuf, this->maxmixers * sizeof(mixer_item_t));
1447 free(this->mixers, M_DEVBUF2, this->maxmixers * sizeof(mixer_item_t));
1448 this->mixers = newbuf;
1449 this->maxmixers = newmax;
1450 return 0;
1451}
1452
1453int
1454azalia_mixer_fix_indexes(codec_t *this)
1455{
1456 int i;
1457 mixer_devinfo_t *d;
1458
1459 for (i = 0; i < this->nmixers; i++) {
1460 d = &this->mixers[i].devinfo;
1461#ifdef DIAGNOSTIC1
1462 if (d->index != 0 && d->index != i)
1463 printf("%s: index mismatch %d %d\n", __func__,
1464 d->index, i);
1465#endif
1466 d->index = i;
1467 if (d->prev == 0)
1468 d->prev = AUDIO_MIXER_LAST-1;
1469 if (d->next == 0)
1470 d->next = AUDIO_MIXER_LAST-1;
1471 }
1472 return 0;
1473}
1474
1475int
1476azalia_mixer_default(codec_t *this)
1477{
1478 widget_t *w;
1479 mixer_item_t *m;
1480 mixer_ctrl_t mc;
1481 int i, j, tgt, cap, err;
1482
1483 /* unmute all */
1484 for (i = 0; i < this->nmixers; i++) {
1485 m = &this->mixers[i];
1486 if (!IS_MI_TARGET_INAMP(m->target)((m->target) <= 15) &&
1487 m->target != MI_TARGET_OUTAMP0x100)
1488 continue;
1489 if (m->devinfo.type != AUDIO_MIXER_ENUM1)
1490 continue;
1491 bzero(&mc, sizeof(mc))__builtin_bzero((&mc), (sizeof(mc)));
1492 mc.dev = i;
1493 mc.type = AUDIO_MIXER_ENUM1;
1494 azalia_mixer_set(this, m->nid, m->target, &mc);
1495 }
1496
1497 /* set unextreme volume */
1498 for (i = 0; i < this->nmixers; i++) {
1499 m = &this->mixers[i];
1500 if (!IS_MI_TARGET_INAMP(m->target)((m->target) <= 15) &&
1501 m->target != MI_TARGET_OUTAMP0x100)
1502 continue;
1503 if (m->devinfo.type != AUDIO_MIXER_VALUE3)
1504 continue;
1505 bzero(&mc, sizeof(mc))__builtin_bzero((&mc), (sizeof(mc)));
1506 mc.dev = i;
1507 mc.type = AUDIO_MIXER_VALUE3;
1508 mc.un.value.num_channels = 1;
1509 mc.un.value.level[0] = AUDIO_MAX_GAIN255 / 2;
1510 if (WIDGET_CHANNELS(&this->w[m->nid])((&this->w[m->nid])->widgetcap & 0x001 ? 2 :
1)
== 2) {
1511 mc.un.value.num_channels = 2;
1512 mc.un.value.level[1] = mc.un.value.level[0];
1513 }
1514 azalia_mixer_set(this, m->nid, m->target, &mc);
1515 }
1516
1517 /* unmute all */
1518 for (i = 0; i < this->nmixers; i++) {
1519 m = &this->mixers[i];
1520 if (m->target != MI_TARGET_MUTESET0x10a)
1521 continue;
1522 if (m->devinfo.type != AUDIO_MIXER_SET2)
1523 continue;
1524 bzero(&mc, sizeof(mc))__builtin_bzero((&mc), (sizeof(mc)));
1525 mc.dev = i;
1526 mc.type = AUDIO_MIXER_SET2;
1527 if (!azalia_widget_enabled(this, m->nid)) {
1528 DPRINTF(("%s: invalid set nid\n", __func__))do {} while (0 );
1529 return EINVAL22;
1530 }
1531 w = &this->w[m->nid];
1532 for (j = 0; j < w->nconnections; j++) {
1533 if (!azalia_widget_enabled(this, w->connections[j]))
1534 continue;
1535 if (w->nid == this->input_mixer &&
1536 w->connections[j] == this->mic)
1537 continue;
1538 mc.un.mask |= 1 << j;
1539 }
1540 azalia_mixer_set(this, m->nid, m->target, &mc);
1541 }
1542
1543 /* make sure default connection is valid */
1544 for (i = 0; i < this->nmixers; i++) {
1545 m = &this->mixers[i];
1546 if (m->target != MI_TARGET_CONNLIST0x101)
1547 continue;
1548
1549 azalia_mixer_get(this, m->nid, m->target, &mc);
1550 for (j = 0; j < m->devinfo.un.e.num_mem; j++) {
1551 if (mc.un.ord == m->devinfo.un.e.member[j].ord)
1552 break;
1553 }
1554 if (j >= m->devinfo.un.e.num_mem) {
1555 bzero(&mc, sizeof(mc))__builtin_bzero((&mc), (sizeof(mc)));
1556 mc.dev = i;
1557 mc.type = AUDIO_MIXER_ENUM1;
1558 mc.un.ord = m->devinfo.un.e.member[0].ord;
1559 }
1560 azalia_mixer_set(this, m->nid, m->target, &mc);
1561 }
1562
1563 /* get default value for play group master */
1564 for (i = 0; i < this->playvols.nslaves; i++) {
1565 if (!(this->playvols.cur & (1 << i)))
1566 continue;
1567 w = &this->w[this->playvols.slaves[i]];
1568 if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)((w->outamp_cap >> 8) & 0x7f)))
1569 continue;
1570 mc.type = AUDIO_MIXER_VALUE3;
1571 tgt = MI_TARGET_OUTAMP0x100;
1572 azalia_mixer_get(this, w->nid, tgt, &mc);
1573 this->playvols.vol_l = mc.un.value.level[0];
1574 this->playvols.vol_r = mc.un.value.level[0];
1575 break;
1576 }
1577 this->playvols.mute = 0;
1578
1579 /* get default value for record group master */
1580 for (i = 0; i < this->recvols.nslaves; i++) {
1581 if (!(this->recvols.cur & (1 << i)))
1582 continue;
1583 w = &this->w[this->recvols.slaves[i]];
1584 mc.type = AUDIO_MIXER_VALUE3;
1585 tgt = MI_TARGET_OUTAMP0x100;
1586 cap = w->outamp_cap;
1587 if (w->type == COP_AWTYPE_PIN_COMPLEX0x4 ||
1588 w->type == COP_AWTYPE_AUDIO_INPUT0x1) {
1589 tgt = 0;
1590 cap = w->inamp_cap;
1591 }
1592 if (!(COP_AMPCAP_NUMSTEPS(cap)((cap >> 8) & 0x7f)))
1593 continue;
1594 azalia_mixer_get(this, w->nid, tgt, &mc);
1595 this->recvols.vol_l = mc.un.value.level[0];
1596 this->recvols.vol_r = mc.un.value.level[0];
1597 break;
1598 }
1599 this->recvols.mute = 0;
1600
1601 err = azalia_codec_enable_unsol(this);
1602 if (err)
1603 return(err);
1604
1605 return 0;
1606}
1607
1608int
1609azalia_codec_enable_unsol(codec_t *this)
1610{
1611 widget_t *w;
1612 uint32_t result;
1613 int i, err;
1614
1615 /* jack sense */
1616 for (i = 0; i < this->nsense_pins; i++) {
1617 if (this->spkr_muters & (1 << i)) {
1618 azalia_comresp(this, this->sense_pins[i],
1619 CORB_SET_UNSOLICITED_RESPONSE0x708,
1620 CORB_UNSOL_ENABLE0x80 | AZ_TAG_SPKR0x01, NULL((void *)0));
1621 }
1622 }
1623 if (this->spkr_muters != 0)
1624 azalia_unsol_event(this, AZ_TAG_SPKR0x01);
1625
1626 /* volume knob */
1627 if (this->playvols.master != this->audiofunc) {
1628
1629 w = &this->w[this->playvols.master];
1630 err = azalia_comresp(this, w->nid, CORB_GET_VOLUME_KNOB0xf0f,
1631 0, &result);
1632 if (err) {
1633 DPRINTF(("%s: get volume knob error\n", __func__))do {} while (0 );
1634 return err;
1635 }
1636
1637 /* current level */
1638 this->playvols.hw_step = CORB_VKNOB_VOLUME(result)(result & 0x7f);
1639 this->playvols.hw_nsteps = COP_VKCAP_NUMSTEPS(w->d.volume.cap)(w->d.volume.cap & 0x7f);
1640
1641 /* indirect mode */
1642 result &= ~(CORB_VKNOB_DIRECT0x80);
1643 err = azalia_comresp(this, w->nid, CORB_SET_VOLUME_KNOB0x70f,
1644 result, NULL((void *)0));
1645 if (err) {
1646 DPRINTF(("%s: set volume knob error\n", __func__))do {} while (0 );
1647 /* XXX If there was an error setting indirect
1648 * mode, do not return an error. However, do not
1649 * enable unsolicited responses either. Most
1650 * likely the volume knob doesn't work right.
1651 * Perhaps it's simply not wired/enabled.
1652 */
1653 return 0;
1654 }
1655
1656 /* enable unsolicited responses */
1657 result = CORB_UNSOL_ENABLE0x80 | AZ_TAG_PLAYVOL0x02;
1658 err = azalia_comresp(this, w->nid,
1659 CORB_SET_UNSOLICITED_RESPONSE0x708, result, NULL((void *)0));
1660 if (err) {
1661 DPRINTF(("%s: set vknob unsol resp error\n", __func__))do {} while (0 );
1662 return err;
1663 }
1664 }
1665
1666 return 0;
1667}
1668
1669int
1670azalia_mixer_delete(codec_t *this)
1671{
1672 if (this->mixers != NULL((void *)0)) {
1673 free(this->mixers, M_DEVBUF2, 0);
1674 this->mixers = NULL((void *)0);
1675 }
1676 return 0;
1677}
1678
1679/**
1680 * @param mc mc->type must be set by the caller before the call
1681 */
1682int
1683azalia_mixer_get(const codec_t *this, nid_t nid, int target,
1684 mixer_ctrl_t *mc)
1685{
1686 uint32_t result, cap, value;
1687 nid_t n;
1688 int i, err;
1689
1690 if (mc->type == AUDIO_MIXER_CLASS0) {
1691 return(0);
1692 }
1693
1694 /* inamp mute */
1695 else if (IS_MI_TARGET_INAMP(target)((target) <= 15) && mc->type == AUDIO_MIXER_ENUM1) {
1696 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1697 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
1698 MI_TARGET_INAMP(target)(target), &result);
1699 if (err)
1700 return err;
1701 mc->un.ord = result & CORB_GAGM_MUTE0x00000080 ? 1 : 0;
1702 }
1703
1704 /* inamp gain */
1705 else if (IS_MI_TARGET_INAMP(target)((target) <= 15) && mc->type == AUDIO_MIXER_VALUE3) {
1706 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1707 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
1708 MI_TARGET_INAMP(target)(target), &result);
1709 if (err)
1710 return err;
1711 mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1712 nid, target, CORB_GAGM_GAIN(result)(result & 0x0000007f));
1713 if (this->w[nid].type == COP_AWTYPE_AUDIO_SELECTOR0x3 ||
1714 this->w[nid].type == COP_AWTYPE_AUDIO_MIXER0x2) {
1715 n = this->w[nid].connections[MI_TARGET_INAMP(target)(target)];
1716 if (!azalia_widget_enabled(this, n)) {
1717 DPRINTF(("%s: nid %2.2x invalid index %d\n",do {} while (0 )
1718 __func__, nid, MI_TARGET_INAMP(target)))do {} while (0 );
1719 n = nid;
1720 }
1721 } else
1722 n = nid;
1723 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[n])((&this->w[n])->widgetcap & 0x001 ? 2 : 1);
1724 if (mc->un.value.num_channels == 2) {
1725 err = azalia_comresp(this, nid,
1726 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00, CORB_GAGM_INPUT0x0000 |
1727 CORB_GAGM_RIGHT0x0000 | MI_TARGET_INAMP(target)(target),
1728 &result);
1729 if (err)
1730 return err;
1731 mc->un.value.level[1] = azalia_mixer_from_device_value
1732 (this, nid, target, CORB_GAGM_GAIN(result)(result & 0x0000007f));
1733 }
1734 }
1735
1736 /* outamp mute */
1737 else if (target == MI_TARGET_OUTAMP0x100 && mc->type == AUDIO_MIXER_ENUM1) {
1738 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1739 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_LEFT0x2000 | 0, &result);
1740 if (err)
1741 return err;
1742 mc->un.ord = result & CORB_GAGM_MUTE0x00000080 ? 1 : 0;
1743 }
1744
1745 /* outamp gain */
1746 else if (target == MI_TARGET_OUTAMP0x100 && mc->type == AUDIO_MIXER_VALUE3) {
1747 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1748 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_LEFT0x2000 | 0, &result);
1749 if (err)
1750 return err;
1751 mc->un.value.level[0] = azalia_mixer_from_device_value(this,
1752 nid, target, CORB_GAGM_GAIN(result)(result & 0x0000007f));
1753 mc->un.value.num_channels = WIDGET_CHANNELS(&this->w[nid])((&this->w[nid])->widgetcap & 0x001 ? 2 : 1);
1754 if (mc->un.value.num_channels == 2) {
1755 err = azalia_comresp(this, nid,
1756 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1757 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_RIGHT0x0000 | 0, &result);
1758 if (err)
1759 return err;
1760 mc->un.value.level[1] = azalia_mixer_from_device_value
1761 (this, nid, target, CORB_GAGM_GAIN(result)(result & 0x0000007f));
1762 }
1763 }
1764
1765 /* selection */
1766 else if (target == MI_TARGET_CONNLIST0x101) {
1767 err = azalia_comresp(this, nid,
1768 CORB_GET_CONNECTION_SELECT_CONTROL0xf01, 0, &result);
1769 if (err)
1770 return err;
1771 result = CORB_CSC_INDEX(result)(result & 0xff);
1772 if (!azalia_widget_enabled(this,
1773 this->w[nid].connections[result]))
1774 mc->un.ord = -1;
1775 else
1776 mc->un.ord = result;
1777 }
1778
1779 /* pin I/O */
1780 else if (target == MI_TARGET_PINDIR0x102) {
1781 err = azalia_comresp(this, nid,
1782 CORB_GET_PIN_WIDGET_CONTROL0xf07, 0, &result);
1783 if (err)
1784 return err;
1785
1786 value = result;
Value stored to 'value' is never read
1787 if (!(result & (CORB_PWC_INPUT0x20 | CORB_PWC_OUTPUT0x40)))
1788 mc->un.ord = 0;
1789 else if (result & CORB_PWC_OUTPUT0x40)
1790 mc->un.ord = 1;
1791 else {
1792 cap = COP_PINCAP_VREF(this->w[nid].d.pin.cap)((this->w[nid].d.pin.cap >> 8) & 0xff);
1793 result &= CORB_PWC_VREF_MASK0x07;
1794 if (result == CORB_PWC_VREF_GND0x02)
1795 mc->un.ord = 3;
1796 else if (result == CORB_PWC_VREF_500x01)
1797 mc->un.ord = 4;
1798 else if (result == CORB_PWC_VREF_800x04)
1799 mc->un.ord = 5;
1800 else if (result == CORB_PWC_VREF_1000x05)
1801 mc->un.ord = 6;
1802 else
1803 mc->un.ord = 2;
1804 }
1805 }
1806
1807 /* pin headphone-boost */
1808 else if (target == MI_TARGET_PINBOOST0x103) {
1809 err = azalia_comresp(this, nid,
1810 CORB_GET_PIN_WIDGET_CONTROL0xf07, 0, &result);
1811 if (err)
1812 return err;
1813 mc->un.ord = result & CORB_PWC_HEADPHONE0x80 ? 1 : 0;
1814 }
1815
1816 /* DAC group selection */
1817 else if (target == MI_TARGET_DAC0x104) {
1818 mc->un.ord = this->dacs.cur;
1819 }
1820
1821 /* ADC selection */
1822 else if (target == MI_TARGET_ADC0x105) {
1823 mc->un.ord = this->adcs.cur;
1824 }
1825
1826 /* S/PDIF */
1827 else if (target == MI_TARGET_SPDIF0x107) {
1828 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL0xf0d,
1829 0, &result);
1830 if (err)
1831 return err;
1832 mc->un.mask = result & 0xff & ~(CORB_DCC_DIGEN0x01 | CORB_DCC_NAUDIO0x20);
1833 } else if (target == MI_TARGET_SPDIF_CC0x108) {
1834 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL0xf0d,
1835 0, &result);
1836 if (err)
1837 return err;
1838 mc->un.value.num_channels = 1;
1839 mc->un.value.level[0] = CORB_DCC_CC(result)((result >> 8) & 0x7f);
1840 }
1841
1842 /* EAPD */
1843 else if (target == MI_TARGET_EAPD0x109) {
1844 err = azalia_comresp(this, nid, CORB_GET_EAPD_BTL_ENABLE0xf0c,
1845 0, &result);
1846 if (err)
1847 return err;
1848 mc->un.ord = result & CORB_EAPD_EAPD0x02 ? 1 : 0;
1849 }
1850
1851 /* sense pin */
1852 else if (target == MI_TARGET_PINSENSE0x10b) {
1853 err = azalia_comresp(this, nid, CORB_GET_PIN_SENSE0xf09,
1854 0, &result);
1855 if (err)
1856 return err;
1857 mc->un.ord = result & CORB_PS_PRESENCE0x80000000 ? 1 : 0;
1858 }
1859
1860 /* mute set */
1861 else if (target == MI_TARGET_MUTESET0x10a && mc->type == AUDIO_MIXER_SET2) {
1862 const widget_t *w;
1863
1864 if (!azalia_widget_enabled(this, nid)) {
1865 DPRINTF(("%s: invalid muteset nid\n", XNAME(this)))do {} while (0 );
1866 return EINVAL22;
1867 }
1868 w = &this->w[nid];
1869 mc->un.mask = 0;
1870 for (i = 0; i < w->nconnections; i++) {
1871 if (!azalia_widget_enabled(this, w->connections[i]))
1872 continue;
1873 err = azalia_comresp(this, nid,
1874 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1875 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
1876 MI_TARGET_INAMP(i)(i), &result);
1877 if (err)
1878 return err;
1879 mc->un.mask |= (result & CORB_GAGM_MUTE0x00000080) ? 0 : (1 << i);
1880 }
1881 }
1882
1883 /* mixer set - show all connections */
1884 else if (target == MI_TARGET_MIXERSET0x10f && mc->type == AUDIO_MIXER_SET2) {
1885 const widget_t *w;
1886
1887 if (!azalia_widget_enabled(this, nid)) {
1888 DPRINTF(("%s: invalid mixerset nid\n", XNAME(this)))do {} while (0 );
1889 return EINVAL22;
1890 }
1891 w = &this->w[nid];
1892 mc->un.mask = 0;
1893 for (i = 0; i < w->nconnections; i++) {
1894 if (!azalia_widget_enabled(this, w->connections[i]))
1895 continue;
1896 mc->un.mask |= (1 << i);
1897 }
1898 }
1899
1900 else if (target == MI_TARGET_SENSESET0x10c && mc->type == AUDIO_MIXER_SET2) {
1901
1902 if (nid == this->speaker) {
1903 mc->un.mask = this->spkr_muters;
1904 } else {
1905 DPRINTF(("%s: invalid senseset nid\n", XNAME(this)))do {} while (0 );
1906 return EINVAL22;
1907 }
1908 }
1909
1910 else if (target == MI_TARGET_PLAYVOL0x10d) {
1911
1912 if (mc->type == AUDIO_MIXER_VALUE3) {
1913 mc->un.value.num_channels = 2;
1914 mc->un.value.level[0] = this->playvols.vol_l;
1915 mc->un.value.level[1] = this->playvols.vol_r;
1916
1917 } else if (mc->type == AUDIO_MIXER_ENUM1) {
1918 mc->un.ord = this->playvols.mute;
1919
1920 } else if (mc->type == AUDIO_MIXER_SET2) {
1921 mc->un.mask = this->playvols.cur;
1922
1923 } else {
1924 DPRINTF(("%s: invalid outmaster mixer type\n",do {} while (0 )
1925 XNAME(this)))do {} while (0 );
1926 return EINVAL22;
1927 }
1928 }
1929
1930 else if (target == MI_TARGET_RECVOL0x10e) {
1931
1932 if (mc->type == AUDIO_MIXER_VALUE3) {
1933 mc->un.value.num_channels = 2;
1934 mc->un.value.level[0] = this->recvols.vol_l;
1935 mc->un.value.level[1] = this->recvols.vol_r;
1936
1937 } else if (mc->type == AUDIO_MIXER_ENUM1) {
1938 mc->un.ord = this->recvols.mute;
1939
1940 } else if (mc->type == AUDIO_MIXER_SET2) {
1941 mc->un.mask = this->recvols.cur;
1942
1943 } else {
1944 DPRINTF(("%s: invalid inmaster mixer type\n",do {} while (0 )
1945 XNAME(this)))do {} while (0 );
1946 return EINVAL22;
1947 }
1948 }
1949
1950 else {
1951 DPRINTF(("%s: internal error in %s: target=%x\n",do {} while (0 )
1952 XNAME(this), __func__, target))do {} while (0 );
1953 return -1;
1954 }
1955 return 0;
1956}
1957
1958int
1959azalia_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_t *mc)
1960{
1961 uint32_t result, value;
1962 int i, err;
1963
1964 if (mc->type == AUDIO_MIXER_CLASS0) {
1965 return(0);
1966 }
1967
1968 /* inamp mute */
1969 else if (IS_MI_TARGET_INAMP(target)((target) <= 15) && mc->type == AUDIO_MIXER_ENUM1) {
1970 /* set stereo mute separately to keep each gain value */
1971 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
1972 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
1973 MI_TARGET_INAMP(target)(target), &result);
1974 if (err)
1975 return err;
1976 value = CORB_AGM_INPUT0x4000 | CORB_AGM_LEFT0x2000 |
1977 (target << CORB_AGM_INDEX_SHIFT8) |
1978 CORB_GAGM_GAIN(result)(result & 0x0000007f);
1979 if (mc->un.ord)
1980 value |= CORB_AGM_MUTE0x0080;
1981 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE0x300,
1982 value, &result);
1983 if (err)
1984 return err;
1985 if (WIDGET_CHANNELS(&this->w[nid])((&this->w[nid])->widgetcap & 0x001 ? 2 : 1) == 2) {
1986 err = azalia_comresp(this, nid,
1987 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00, CORB_GAGM_INPUT0x0000 |
1988 CORB_GAGM_RIGHT0x0000 | MI_TARGET_INAMP(target)(target),
1989 &result);
1990 if (err)
1991 return err;
1992 value = CORB_AGM_INPUT0x4000 | CORB_AGM_RIGHT0x1000 |
1993 (target << CORB_AGM_INDEX_SHIFT8) |
1994 CORB_GAGM_GAIN(result)(result & 0x0000007f);
1995 if (mc->un.ord)
1996 value |= CORB_AGM_MUTE0x0080;
1997 err = azalia_comresp(this, nid,
1998 CORB_SET_AMPLIFIER_GAIN_MUTE0x300, value, &result);
1999 if (err)
2000 return err;
2001 }
2002 }
2003
2004 /* inamp gain */
2005 else if (IS_MI_TARGET_INAMP(target)((target) <= 15) && mc->type == AUDIO_MIXER_VALUE3) {
2006 if (mc->un.value.num_channels < 1)
2007 return EINVAL22;
2008 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2009 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
2010 MI_TARGET_INAMP(target)(target), &result);
2011 if (err)
2012 return err;
2013 value = azalia_mixer_to_device_value(this, nid, target,
2014 mc->un.value.level[0]);
2015 value = CORB_AGM_INPUT0x4000 | CORB_AGM_LEFT0x2000 |
2016 (target << CORB_AGM_INDEX_SHIFT8) |
2017 (result & CORB_GAGM_MUTE0x00000080 ? CORB_AGM_MUTE0x0080 : 0) |
2018 (value & CORB_AGM_GAIN_MASK0x007f);
2019 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE0x300,
2020 value, &result);
2021 if (err)
2022 return err;
2023 if (mc->un.value.num_channels >= 2 &&
2024 WIDGET_CHANNELS(&this->w[nid])((&this->w[nid])->widgetcap & 0x001 ? 2 : 1) == 2) {
2025 err = azalia_comresp(this, nid,
2026 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00, CORB_GAGM_INPUT0x0000 |
2027 CORB_GAGM_RIGHT0x0000 | MI_TARGET_INAMP(target)(target),
2028 &result);
2029 if (err)
2030 return err;
2031 value = azalia_mixer_to_device_value(this, nid, target,
2032 mc->un.value.level[1]);
2033 value = CORB_AGM_INPUT0x4000 | CORB_AGM_RIGHT0x1000 |
2034 (target << CORB_AGM_INDEX_SHIFT8) |
2035 (result & CORB_GAGM_MUTE0x00000080 ? CORB_AGM_MUTE0x0080 : 0) |
2036 (value & CORB_AGM_GAIN_MASK0x007f);
2037 err = azalia_comresp(this, nid,
2038 CORB_SET_AMPLIFIER_GAIN_MUTE0x300, value, &result);
2039 if (err)
2040 return err;
2041 }
2042 }
2043
2044 /* outamp mute */
2045 else if (target == MI_TARGET_OUTAMP0x100 && mc->type == AUDIO_MIXER_ENUM1) {
2046 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2047 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_LEFT0x2000, &result);
2048 if (err)
2049 return err;
2050 value = CORB_AGM_OUTPUT0x8000 | CORB_AGM_LEFT0x2000 | CORB_GAGM_GAIN(result)(result & 0x0000007f);
2051 if (mc->un.ord)
2052 value |= CORB_AGM_MUTE0x0080;
2053 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE0x300,
2054 value, &result);
2055 if (err)
2056 return err;
2057 if (WIDGET_CHANNELS(&this->w[nid])((&this->w[nid])->widgetcap & 0x001 ? 2 : 1) == 2) {
2058 err = azalia_comresp(this, nid,
2059 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2060 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_RIGHT0x0000, &result);
2061 if (err)
2062 return err;
2063 value = CORB_AGM_OUTPUT0x8000 | CORB_AGM_RIGHT0x1000 |
2064 CORB_GAGM_GAIN(result)(result & 0x0000007f);
2065 if (mc->un.ord)
2066 value |= CORB_AGM_MUTE0x0080;
2067 err = azalia_comresp(this, nid,
2068 CORB_SET_AMPLIFIER_GAIN_MUTE0x300, value, &result);
2069 if (err)
2070 return err;
2071 }
2072 }
2073
2074 /* outamp gain */
2075 else if (target == MI_TARGET_OUTAMP0x100 && mc->type == AUDIO_MIXER_VALUE3) {
2076 if (mc->un.value.num_channels < 1)
2077 return EINVAL22;
2078 err = azalia_comresp(this, nid, CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2079 CORB_GAGM_OUTPUT0x8000 | CORB_GAGM_LEFT0x2000, &result);
2080 if (err)
2081 return err;
2082 value = azalia_mixer_to_device_value(this, nid, target,
2083 mc->un.value.level[0]);
2084 value = CORB_AGM_OUTPUT0x8000 | CORB_AGM_LEFT0x2000 |
2085 (result & CORB_GAGM_MUTE0x00000080 ? CORB_AGM_MUTE0x0080 : 0) |
2086 (value & CORB_AGM_GAIN_MASK0x007f);
2087 err = azalia_comresp(this, nid, CORB_SET_AMPLIFIER_GAIN_MUTE0x300,
2088 value, &result);
2089 if (err)
2090 return err;
2091 if (mc->un.value.num_channels >= 2 &&
2092 WIDGET_CHANNELS(&this->w[nid])((&this->w[nid])->widgetcap & 0x001 ? 2 : 1) == 2) {
2093 err = azalia_comresp(this, nid,
2094 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00, CORB_GAGM_OUTPUT0x8000 |
2095 CORB_GAGM_RIGHT0x0000, &result);
2096 if (err)
2097 return err;
2098 value = azalia_mixer_to_device_value(this, nid, target,
2099 mc->un.value.level[1]);
2100 value = CORB_AGM_OUTPUT0x8000 | CORB_AGM_RIGHT0x1000 |
2101 (result & CORB_GAGM_MUTE0x00000080 ? CORB_AGM_MUTE0x0080 : 0) |
2102 (value & CORB_AGM_GAIN_MASK0x007f);
2103 err = azalia_comresp(this, nid,
2104 CORB_SET_AMPLIFIER_GAIN_MUTE0x300, value, &result);
2105 if (err)
2106 return err;
2107 }
2108 }
2109
2110 /* selection */
2111 else if (target == MI_TARGET_CONNLIST0x101) {
2112 if (mc->un.ord < 0 ||
2113 mc->un.ord >= this->w[nid].nconnections ||
2114 !azalia_widget_enabled(this,
2115 this->w[nid].connections[mc->un.ord]))
2116 return EINVAL22;
2117 err = azalia_comresp(this, nid,
2118 CORB_SET_CONNECTION_SELECT_CONTROL0x701, mc->un.ord, &result);
2119 if (err)
2120 return err;
2121 }
2122
2123 /* pin I/O */
2124 else if (target == MI_TARGET_PINDIR0x102) {
2125
2126 err = azalia_comresp(this, nid,
2127 CORB_GET_PIN_WIDGET_CONTROL0xf07, 0, &result);
2128 if (err)
2129 return err;
2130
2131 value = result;
2132 value &= ~(CORB_PWC_VREF_MASK0x07);
2133 if (mc->un.ord == 0) {
2134 value &= ~(CORB_PWC_OUTPUT0x40 | CORB_PWC_INPUT0x20);
2135 } else if (mc->un.ord == 1) {
2136 value &= ~CORB_PWC_INPUT0x20;
2137 value |= CORB_PWC_OUTPUT0x40;
2138 if (this->qrks & AZ_QRK_WID_OVREF500x00004000)
2139 value |= CORB_PWC_VREF_500x01;
2140 } else {
2141 value &= ~CORB_PWC_OUTPUT0x40;
2142 value |= CORB_PWC_INPUT0x20;
2143
2144 if (mc->un.ord == 3)
2145 value |= CORB_PWC_VREF_GND0x02;
2146 if (mc->un.ord == 4)
2147 value |= CORB_PWC_VREF_500x01;
2148 if (mc->un.ord == 5)
2149 value |= CORB_PWC_VREF_800x04;
2150 if (mc->un.ord == 6)
2151 value |= CORB_PWC_VREF_1000x05;
2152 }
2153 err = azalia_comresp(this, nid,
2154 CORB_SET_PIN_WIDGET_CONTROL0x707, value, &result);
2155 if (err)
2156 return err;
2157
2158 /* Run the unsolicited response handler for speaker mute
2159 * since it depends on pin direction.
2160 */
2161 for (i = 0; i < this->nsense_pins; i++) {
2162 if (this->sense_pins[i] == nid)
2163 break;
2164 }
2165 if (i < this->nsense_pins) {
2166 azalia_unsol_event(this, AZ_TAG_SPKR0x01);
2167 }
2168 }
2169
2170 /* pin headphone-boost */
2171 else if (target == MI_TARGET_PINBOOST0x103) {
2172 if (mc->un.ord >= 2)
2173 return EINVAL22;
2174 err = azalia_comresp(this, nid,
2175 CORB_GET_PIN_WIDGET_CONTROL0xf07, 0, &result);
2176 if (err)
2177 return err;
2178 if (mc->un.ord == 0) {
2179 result &= ~CORB_PWC_HEADPHONE0x80;
2180 } else {
2181 result |= CORB_PWC_HEADPHONE0x80;
2182 }
2183 err = azalia_comresp(this, nid,
2184 CORB_SET_PIN_WIDGET_CONTROL0x707, result, &result);
2185 if (err)
2186 return err;
2187 }
2188
2189 /* DAC group selection */
2190 else if (target == MI_TARGET_DAC0x104) {
2191 if (this->running)
2192 return EBUSY16;
2193 if (mc->un.ord >= this->dacs.ngroups)
2194 return EINVAL22;
2195 if (mc->un.ord != this->dacs.cur)
2196 return azalia_codec_construct_format(this,
2197 mc->un.ord, this->adcs.cur);
2198 else
2199 return 0;
2200 }
2201
2202 /* ADC selection */
2203 else if (target == MI_TARGET_ADC0x105) {
2204 if (this->running)
2205 return EBUSY16;
2206 if (mc->un.ord >= this->adcs.ngroups)
2207 return EINVAL22;
2208 if (mc->un.ord != this->adcs.cur)
2209 return azalia_codec_construct_format(this,
2210 this->dacs.cur, mc->un.ord);
2211 else
2212 return 0;
2213 }
2214
2215 /* S/PDIF */
2216 else if (target == MI_TARGET_SPDIF0x107) {
2217 err = azalia_comresp(this, nid, CORB_GET_DIGITAL_CONTROL0xf0d,
2218 0, &result);
2219 result &= CORB_DCC_DIGEN0x01 | CORB_DCC_NAUDIO0x20;
2220 result |= mc->un.mask & 0xff & ~CORB_DCC_DIGEN0x01;
2221 err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_L0x70d,
2222 result, NULL((void *)0));
2223 if (err)
2224 return err;
2225 } else if (target == MI_TARGET_SPDIF_CC0x108) {
2226 if (mc->un.value.num_channels != 1)
2227 return EINVAL22;
2228 if (mc->un.value.level[0] > 127)
2229 return EINVAL22;
2230 err = azalia_comresp(this, nid, CORB_SET_DIGITAL_CONTROL_H0x70e,
2231 mc->un.value.level[0], NULL((void *)0));
2232 if (err)
2233 return err;
2234 }
2235
2236 /* EAPD */
2237 else if (target == MI_TARGET_EAPD0x109) {
2238 if (mc->un.ord >= 2)
2239 return EINVAL22;
2240 err = azalia_comresp(this, nid,
2241 CORB_GET_EAPD_BTL_ENABLE0xf0c, 0, &result);
2242 if (err)
2243 return err;
2244 result &= 0xff;
2245 if (mc->un.ord == 0) {
2246 result &= ~CORB_EAPD_EAPD0x02;
2247 } else {
2248 result |= CORB_EAPD_EAPD0x02;
2249 }
2250 err = azalia_comresp(this, nid,
2251 CORB_SET_EAPD_BTL_ENABLE0x70c, result, &result);
2252 if (err)
2253 return err;
2254 }
2255
2256 else if (target == MI_TARGET_PINSENSE0x10b) {
2257 /* do nothing, control is read only */
2258 }
2259
2260 else if (target == MI_TARGET_MUTESET0x10a && mc->type == AUDIO_MIXER_SET2) {
2261 const widget_t *w;
2262
2263 if (!azalia_widget_enabled(this, nid)) {
2264 DPRINTF(("%s: invalid muteset nid\n", XNAME(this)))do {} while (0 );
2265 return EINVAL22;
2266 }
2267 w = &this->w[nid];
2268 for (i = 0; i < w->nconnections; i++) {
2269 if (!azalia_widget_enabled(this, w->connections[i]))
2270 continue;
2271
2272 /* We have to set stereo mute separately
2273 * to keep each gain value.
2274 */
2275 err = azalia_comresp(this, nid,
2276 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2277 CORB_GAGM_INPUT0x0000 | CORB_GAGM_LEFT0x2000 |
2278 MI_TARGET_INAMP(i)(i), &result);
2279 if (err)
2280 return err;
2281 value = CORB_AGM_INPUT0x4000 | CORB_AGM_LEFT0x2000 |
2282 (i << CORB_AGM_INDEX_SHIFT8) |
2283 CORB_GAGM_GAIN(result)(result & 0x0000007f);
2284 if ((mc->un.mask & (1 << i)) == 0)
2285 value |= CORB_AGM_MUTE0x0080;
2286 err = azalia_comresp(this, nid,
2287 CORB_SET_AMPLIFIER_GAIN_MUTE0x300, value, &result);
2288 if (err)
2289 return err;
2290
2291 if (WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1) == 2) {
2292 err = azalia_comresp(this, nid,
2293 CORB_GET_AMPLIFIER_GAIN_MUTE0xb00,
2294 CORB_GAGM_INPUT0x0000 | CORB_GAGM_RIGHT0x0000 |
2295 MI_TARGET_INAMP(i)(i), &result);
2296 if (err)
2297 return err;
2298 value = CORB_AGM_INPUT0x4000 | CORB_AGM_RIGHT0x1000 |
2299 (i << CORB_AGM_INDEX_SHIFT8) |
2300 CORB_GAGM_GAIN(result)(result & 0x0000007f);
2301 if ((mc->un.mask & (1 << i)) == 0)
2302 value |= CORB_AGM_MUTE0x0080;
2303 err = azalia_comresp(this, nid,
2304 CORB_SET_AMPLIFIER_GAIN_MUTE0x300,
2305 value, &result);
2306 if (err)
2307 return err;
2308 }
2309 }
2310 }
2311
2312 else if (target == MI_TARGET_MIXERSET0x10f && mc->type == AUDIO_MIXER_SET2) {
2313 /* do nothing, control is read only */
2314 }
2315
2316 else if (target == MI_TARGET_SENSESET0x10c && mc->type == AUDIO_MIXER_SET2) {
2317
2318 if (nid == this->speaker) {
2319 this->spkr_muters = mc->un.mask;
2320 azalia_unsol_event(this, AZ_TAG_SPKR0x01);
2321 } else {
2322 DPRINTF(("%s: invalid senseset nid\n", XNAME(this)))do {} while (0 );
2323 return EINVAL22;
2324 }
2325 }
2326
2327 else if (target == MI_TARGET_PLAYVOL0x10d) {
2328
2329 const widget_t *w;
2330 mixer_ctrl_t mc2;
2331
2332 if (mc->type == AUDIO_MIXER_VALUE3) {
2333 if (mc->un.value.num_channels != 2)
2334 return EINVAL22;
2335 this->playvols.vol_l = mc->un.value.level[0];
2336 this->playvols.vol_r = mc->un.value.level[1];
2337 for (i = 0; i < this->playvols.nslaves; i++) {
2338 if (!(this->playvols.cur & (1 << i)))
2339 continue;
2340 w = &this->w[this->playvols.slaves[i]];
2341 if (!(COP_AMPCAP_NUMSTEPS(w->outamp_cap)((w->outamp_cap >> 8) & 0x7f)))
2342 continue;
2343
2344 /* don't change volume if muted */
2345 if (w->outamp_cap & COP_AMPCAP_MUTE0x80000000) {
2346 mc2.type = AUDIO_MIXER_ENUM1;
2347 azalia_mixer_get(this, w->nid,
2348 MI_TARGET_OUTAMP0x100, &mc2);
2349 if (mc2.un.ord)
2350 continue;
2351 }
2352 mc2.type = AUDIO_MIXER_VALUE3;
2353 mc2.un.value.num_channels = WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1);
2354 mc2.un.value.level[0] = this->playvols.vol_l;
2355 mc2.un.value.level[1] = this->playvols.vol_r;
2356 err = azalia_mixer_set(this, w->nid,
2357 MI_TARGET_OUTAMP0x100, &mc2);
2358 if (err) {
2359 DPRINTF(("%s: out slave %2.2x vol\n",do {} while (0 )
2360 __func__, w->nid))do {} while (0 );
2361 return err;
2362 }
2363 }
2364 } else if (mc->type == AUDIO_MIXER_ENUM1) {
2365 if (mc->un.ord != 0 && mc->un.ord != 1)
2366 return EINVAL22;
2367 this->playvols.mute = mc->un.ord;
2368 for (i = 0; i < this->playvols.nslaves; i++) {
2369 if (!(this->playvols.cur & (1 << i)))
2370 continue;
2371 w = &this->w[this->playvols.slaves[i]];
2372 if (!(w->outamp_cap & COP_AMPCAP_MUTE0x80000000))
2373 continue;
2374 if (this->spkr_muted == 1 &&
2375 ((this->spkr_mute_method ==
2376 AZ_SPKR_MUTE_SPKR_MUTE1 &&
2377 (w->nid == this->speaker ||
2378 w->nid == this->speaker2)) ||
2379 (this->spkr_mute_method ==
2380 AZ_SPKR_MUTE_DAC_MUTE3 &&
2381 w->nid == this->spkr_dac))) {
2382 continue;
2383 }
2384 mc2.type = AUDIO_MIXER_ENUM1;
2385 mc2.un.ord = this->playvols.mute;
2386 err = azalia_mixer_set(this, w->nid,
2387 MI_TARGET_OUTAMP0x100, &mc2);
2388 if (err) {
2389 DPRINTF(("%s: out slave %2.2x mute\n",do {} while (0 )
2390 __func__, w->nid))do {} while (0 );
2391 return err;
2392 }
2393 }
2394
2395 } else if (mc->type == AUDIO_MIXER_SET2) {
2396 this->playvols.cur =
2397 (mc->un.mask & this->playvols.mask);
2398
2399 } else {
2400 DPRINTF(("%s: invalid output master mixer type\n",do {} while (0 )
2401 XNAME(this)))do {} while (0 );
2402 return EINVAL22;
2403 }
2404 }
2405
2406 else if (target == MI_TARGET_RECVOL0x10e) {
2407
2408 const widget_t *w;
2409 mixer_ctrl_t mc2;
2410 uint32_t cap;
2411 int tgt;
2412
2413 if (mc->type == AUDIO_MIXER_VALUE3) {
2414 if (mc->un.value.num_channels != 2)
2415 return EINVAL22;
2416 this->recvols.vol_l = mc->un.value.level[0];
2417 this->recvols.vol_r = mc->un.value.level[1];
2418 for (i = 0; i < this->recvols.nslaves; i++) {
2419 if (!(this->recvols.cur & (1 << i)))
2420 continue;
2421 w = &this->w[this->recvols.slaves[i]];
2422 tgt = MI_TARGET_OUTAMP0x100;
2423 cap = w->outamp_cap;
2424 if (w->type == COP_AWTYPE_AUDIO_INPUT0x1 ||
2425 w->type == COP_AWTYPE_PIN_COMPLEX0x4) {
2426 tgt = 0;
2427 cap = w->inamp_cap;
2428 }
2429 if (!(COP_AMPCAP_NUMSTEPS(cap)((cap >> 8) & 0x7f)))
2430 continue;
2431 mc2.type = AUDIO_MIXER_VALUE3;
2432 mc2.un.value.num_channels = WIDGET_CHANNELS(w)((w)->widgetcap & 0x001 ? 2 : 1);
2433 mc2.un.value.level[0] = this->recvols.vol_l;
2434 mc2.un.value.level[1] = this->recvols.vol_r;
2435 err = azalia_mixer_set(this, w->nid,
2436 tgt, &mc2);
2437 if (err) {
2438 DPRINTF(("%s: in slave %2.2x vol\n",do {} while (0 )
2439 __func__, w->nid))do {} while (0 );
2440 return err;
2441 }
2442 }
2443 } else if (mc->type == AUDIO_MIXER_ENUM1) {
2444 if (mc->un.ord != 0 && mc->un.ord != 1)
2445 return EINVAL22;
2446 this->recvols.mute = mc->un.ord;
2447 for (i = 0; i < this->recvols.nslaves; i++) {
2448 if (!(this->recvols.cur & (1 << i)))
2449 continue;
2450 w = &this->w[this->recvols.slaves[i]];
2451 tgt = MI_TARGET_OUTAMP0x100;
2452 cap = w->outamp_cap;
2453 if (w->type == COP_AWTYPE_AUDIO_INPUT0x1 ||
2454 w->type == COP_AWTYPE_PIN_COMPLEX0x4) {
2455 tgt = 0;
2456 cap = w->inamp_cap;
2457 }
2458 if (!(cap & COP_AMPCAP_MUTE0x80000000))
2459 continue;
2460 mc2.type = AUDIO_MIXER_ENUM1;
2461 mc2.un.ord = this->recvols.mute;
2462 err = azalia_mixer_set(this, w->nid,
2463 tgt, &mc2);
2464 if (err) {
2465 DPRINTF(("%s: out slave %2.2x mute\n",do {} while (0 )
2466 __func__, w->nid))do {} while (0 );
2467 return err;
2468 }
2469 }
2470
2471 } else if (mc->type == AUDIO_MIXER_SET2) {
2472 this->recvols.cur = (mc->un.mask & this->recvols.mask);
2473
2474 } else {
2475 DPRINTF(("%s: invalid input master mixer type\n",do {} while (0 )
2476 XNAME(this)))do {} while (0 );
2477 return EINVAL22;
2478 }
2479 }
2480
2481 else {
2482 DPRINTF(("%s: internal error in %s: target=%x\n",do {} while (0 )
2483 XNAME(this), __func__, target))do {} while (0 );
2484 return -1;
2485 }
2486 return 0;
2487}
2488
2489u_char
2490azalia_mixer_from_device_value(const codec_t *this, nid_t nid, int target,
2491 uint32_t dv)
2492{
2493 uint32_t steps;
2494 int max_gain, ctloff;
2495
2496 if (IS_MI_TARGET_INAMP(target)((target) <= 15)) {
2497 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap)((this->w[nid].inamp_cap >> 8) & 0x7f);
2498 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap)((this->w[nid].inamp_cap >> 24) & 0x7f);
2499 } else if (target == MI_TARGET_OUTAMP0x100) {
2500 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap)((this->w[nid].outamp_cap >> 8) & 0x7f);
2501 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap)((this->w[nid].outamp_cap >> 24) & 0x7f);
2502 } else {
2503 DPRINTF(("%s: unknown target: %d\n", __func__, target))do {} while (0 );
2504 steps = 255;
2505 ctloff = 0;
2506 }
2507 dv -= ctloff;
2508 if (dv <= 0 || steps == 0)
2509 return(AUDIO_MIN_GAIN0);
2510 max_gain = AUDIO_MAX_GAIN255 - AUDIO_MAX_GAIN255 % steps;
2511 if (dv >= steps)
2512 return(max_gain);
2513 return(dv * max_gain / steps);
2514}
2515
2516uint32_t
2517azalia_mixer_to_device_value(const codec_t *this, nid_t nid, int target,
2518 u_char uv)
2519{
2520 uint32_t steps;
2521 int max_gain, ctloff;
2522
2523 if (IS_MI_TARGET_INAMP(target)((target) <= 15)) {
2524 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].inamp_cap)((this->w[nid].inamp_cap >> 8) & 0x7f);
2525 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].inamp_cap)((this->w[nid].inamp_cap >> 24) & 0x7f);
2526 } else if (target == MI_TARGET_OUTAMP0x100) {
2527 steps = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap)((this->w[nid].outamp_cap >> 8) & 0x7f);
2528 ctloff = COP_AMPCAP_CTLOFF(this->w[nid].outamp_cap)((this->w[nid].outamp_cap >> 24) & 0x7f);
2529 } else {
2530 DPRINTF(("%s: unknown target: %d\n", __func__, target))do {} while (0 );
2531 steps = 255;
2532 ctloff = 0;
2533 }
2534 if (uv <= AUDIO_MIN_GAIN0 || steps == 0)
2535 return(ctloff);
2536 max_gain = AUDIO_MAX_GAIN255 - AUDIO_MAX_GAIN255 % steps;
2537 if (uv >= max_gain)
2538 return(steps + ctloff);
2539 return(uv * steps / max_gain + ctloff);
2540}
2541
2542int
2543azalia_gpio_unmute(codec_t *this, int pin)
2544{
2545 uint32_t data, mask, dir;
2546
2547 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DATA0xf15, 0, &data);
2548 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_ENABLE_MASK0xf16, 0, &mask);
2549 azalia_comresp(this, this->audiofunc, CORB_GET_GPIO_DIRECTION0xf17, 0, &dir);
2550
2551 data |= 1 << pin;
2552 mask |= 1 << pin;
2553 dir |= 1 << pin;
2554
2555 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_ENABLE_MASK0x716, mask, NULL((void *)0));
2556 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DIRECTION0x717, dir, NULL((void *)0));
2557 DELAY(1000)(*delay_func)(1000);
2558 azalia_comresp(this, this->audiofunc, CORB_SET_GPIO_DATA0x715, data, NULL((void *)0));
2559
2560 return 0;
2561}
2562
2563void
2564azalia_ampcap_ov(widget_t *w, int type, int offset, int steps, int size,
2565 int ctloff, int mute)
2566{
2567 uint32_t cap;
2568
2569 cap = (offset & 0x7f) | ((steps & 0x7f) << 8) |
2570 ((size & 0x7f) << 16) | ((ctloff & 0x7f) << 24) |
2571 (mute ? COP_AMPCAP_MUTE0x80000000 : 0);
2572
2573 if (type == COP_OUTPUT_AMPCAP0x12) {
2574 w->outamp_cap = cap;
2575 } else if (type == COP_INPUT_AMPCAP0x0d) {
2576 w->inamp_cap = cap;
2577 }
2578}
2579
2580void
2581azalia_pin_config_ov(widget_t *w, int mask, int val)
2582{
2583 int bits, offset;
2584
2585 switch (mask) {
2586 case CORB_CD_DEVICE_MASK(0xf << 20):
2587 bits = CORB_CD_DEVICE_BITS0xf;
2588 offset = CORB_CD_DEVICE_OFFSET20;
2589 break;
2590 case CORB_CD_PORT_MASK(0x3 << 30):
2591 bits = CORB_CD_PORT_BITS0x3;
2592 offset = CORB_CD_PORT_OFFSET30;
2593 break;
2594 default:
2595 return;
2596 }
2597 val &= bits;
2598 w->d.pin.config &= ~(mask);
2599 w->d.pin.config |= val << offset;
2600 if (mask == CORB_CD_DEVICE_MASK(0xf << 20))
2601 w->d.pin.device = val;
2602}
2603
2604int
2605azalia_codec_gpio_quirks(codec_t *this)
2606{
2607 if (this->qrks & AZ_QRK_GPIO_POL_00x00000100) {
2608 azalia_comresp(this, this->audiofunc,
2609 CORB_SET_GPIO_POLARITY0x7e7, 0, NULL((void *)0));
2610 }
2611 if (this->qrks & AZ_QRK_GPIO_UNMUTE_00x00000001) {
2612 azalia_gpio_unmute(this, 0);
2613 }
2614 if (this->qrks & AZ_QRK_GPIO_UNMUTE_10x00000002) {
2615 azalia_gpio_unmute(this, 1);
2616 }
2617 if (this->qrks & AZ_QRK_GPIO_UNMUTE_20x00000004) {
2618 azalia_gpio_unmute(this, 2);
2619 }
2620 if (this->qrks & AZ_QRK_GPIO_UNMUTE_30x00000008) {
2621 azalia_gpio_unmute(this, 3);
2622 }
2623
2624 return(0);
2625}
2626
2627int
2628azalia_codec_widget_quirks(codec_t *this, nid_t nid)
2629{
2630 widget_t *w;
2631
2632 w = &this->w[nid];
2633
2634 if (this->qrks & AZ_QRK_WID_BEEP_1D0x00002000 &&
2635 nid == 0x1d && w->enable == 0) {
2636 azalia_pin_config_ov(w, CORB_CD_DEVICE_MASK(0xf << 20), CORB_CD_BEEP0xe);
2637 azalia_pin_config_ov(w, CORB_CD_PORT_MASK(0x3 << 30), CORB_CD_FIXED0x2);
2638 w->widgetcap |= COP_AWCAP_STEREO0x001;
2639 w->enable = 1;
2640 }
2641
2642 if (this->qrks & AZ_QRK_WID_TPDOCK10x00010000 &&
2643 nid == 0x19) {
2644 /* Thinkpad x230/t430 style dock microphone */
2645 w->d.pin.config = 0x23a11040;
2646 w->enable = 1;
2647 }
2648
2649 if (this->qrks & AZ_QRK_WID_TPDOCK10x00010000 &&
2650 nid == 0x1b) {
2651 /* Thinkpad x230/t430 style dock headphone */
2652 w->d.pin.config = 0x2121103f;
2653 w->enable = 1;
2654 }
2655
2656 if (this->qrks & AZ_QRK_WID_TPDOCK20x00020000 &&
2657 nid == 0x16) {
2658 /* Thinkpad x240/t440 style dock headphone */
2659 w->d.pin.config = 0x21211010;
2660 w->enable = 1;
2661 }
2662
2663 if (this->qrks & AZ_QRK_WID_TPDOCK20x00020000 &&
2664 nid == 0x19) {
2665 /* Thinkpad x240/t440 style dock microphone */
2666 w->d.pin.config = 0x21a11010;
2667 w->enable = 1;
2668 }
2669
2670 if (this->qrks & AZ_QRK_WID_TPDOCK30x00040000 &&
2671 nid == 0x1a) {
2672 /* Thinkpad x220/t420 style dock microphone */
2673 w->d.pin.config = 0x21a190f0;
2674 w->enable = 1;
2675 }
2676
2677 if (this->qrks & AZ_QRK_WID_TPDOCK30x00040000 &&
2678 nid == 0x1c) {
2679 /* Thinkpad x220/t420 style dock headphone */
2680 w->d.pin.config = 0x212140ff;
2681 w->enable = 1;
2682 }
2683
2684 if (this->qrks & AZ_QRK_WID_CDIN_1C0x00001000 &&
2685 nid == 0x1c && w->enable == 0 && w->d.pin.device == CORB_CD_CD0x3) {
2686 azalia_pin_config_ov(w, CORB_CD_PORT_MASK(0x3 << 30), CORB_CD_FIXED0x2);
2687 w->widgetcap |= COP_AWCAP_STEREO0x001;
2688 w->enable = 1;
2689 }
2690
2691 if ((this->qrks & AZ_QRK_WID_AD1981_OAMP0x00008000) &&
2692 ((nid == 0x05) || (nid == 0x06) || (nid == 0x07) ||
2693 (nid == 0x09) || (nid == 0x18))) {
2694 azalia_ampcap_ov(w, COP_OUTPUT_AMPCAP0x12, 31, 33, 6, 30, 1);
2695 }
2696
2697 if ((this->qrks & AZ_QRK_WID_CLOSE_PCBEEP0x00080000) && (nid == 0x20)) {
2698 /* Close PC beep passthrough to avoid headphone noise */
2699 azalia_comresp(this, nid, CORB_SET_COEFFICIENT_INDEX0x500, 0x36,
2700 NULL((void *)0));
2701 azalia_comresp(this, nid, CORB_SET_PROCESSING_COEFFICIENT0x400,
2702 0x57d7, NULL((void *)0));
2703 }
2704
2705 return(0);
2706}
2707
2708/* Magic init sequence to make the right speaker work (reverse-engineered) */
2709void
2710azalia_codec_init_dolby_atmos(codec_t *this)
2711{
2712 static uint16_t atmos_init[] = {
2713 0x06, 0x73e, 0x00, 0x06, 0x73e, 0x80,
2714 0x20, 0x500, 0x26, 0x20, 0x4f0, 0x00,
2715 0x20, 0x500, 0x22, 0x20, 0x400, 0x31,
2716 0x20, 0x500, 0x23, 0x20, 0x400, 0x0b,
2717 0x20, 0x500, 0x25, 0x20, 0x400, 0x00,
2718 0x20, 0x500, 0x26, 0x20, 0x4b0, 0x10,
2719 };
2720 static struct {
2721 unsigned char v23;
2722 unsigned char v25;
2723 } atmos_v23_v25[] = {
2724 { 0x0c, 0x00 }, { 0x0d, 0x00 }, { 0x0e, 0x00 }, { 0x0f, 0x00 },
2725 { 0x10, 0x00 }, { 0x1a, 0x40 }, { 0x1b, 0x82 }, { 0x1c, 0x00 },
2726 { 0x1d, 0x00 }, { 0x1e, 0x00 }, { 0x1f, 0x00 }, { 0x20, 0xc2 },
2727 { 0x21, 0xc8 }, { 0x22, 0x26 }, { 0x23, 0x24 }, { 0x27, 0xff },
2728 { 0x28, 0xff }, { 0x29, 0xff }, { 0x2a, 0x8f }, { 0x2b, 0x02 },
2729 { 0x2c, 0x48 }, { 0x2d, 0x34 }, { 0x2e, 0x00 }, { 0x2f, 0x00 },
2730 { 0x30, 0x00 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
2731 { 0x34, 0x00 }, { 0x35, 0x01 }, { 0x36, 0x93 }, { 0x37, 0x0c },
2732 { 0x38, 0x00 }, { 0x39, 0x00 }, { 0x3a, 0xf8 }, { 0x38, 0x80 },
2733 };
2734 int i;
2735
2736 for (i = 0; i < nitems(atmos_init)(sizeof((atmos_init)) / sizeof((atmos_init)[0])) / 3; i++) {
2737 if (azalia_comresp(this, atmos_init[i * 3],
2738 atmos_init[(i * 3) + 1], atmos_init[(i * 3) + 2], NULL((void *)0)))
2739 return;
2740 }
2741
2742 for (i = 0; i < nitems(atmos_v23_v25)(sizeof((atmos_v23_v25)) / sizeof((atmos_v23_v25)[0])); i++) {
2743 if (azalia_comresp(this, 0x06, 0x73e, 0x00, NULL((void *)0)))
2744 return;
2745 if (azalia_comresp(this, 0x20, 0x500, 0x26, NULL((void *)0)))
2746 return;
2747 if (azalia_comresp(this, 0x20, 0x4b0, 0x00, NULL((void *)0)))
2748 return;
2749 if (i == 0) {
2750 if (azalia_comresp(this, 0x21, 0xf09, 0x00, NULL((void *)0)))
2751 return;
2752 }
2753 if (i != 20) {
2754 if (azalia_comresp(this, 0x06, 0x73e, 0x80, NULL((void *)0)))
2755 return;
2756 }
2757
2758 if (azalia_comresp(this, 0x20, 0x500, 0x26, NULL((void *)0)))
2759 return;
2760 if (azalia_comresp(this, 0x20, 0x4f0, 0x00, NULL((void *)0)))
2761 return;
2762 if (azalia_comresp(this, 0x20, 0x500, 0x23, NULL((void *)0)))
2763 return;
2764
2765 if (azalia_comresp(this, 0x20, 0x400,
2766 atmos_v23_v25[i].v23, NULL((void *)0)))
2767 return;
2768
2769 if (atmos_v23_v25[i].v23 != 0x1e) {
2770 if (azalia_comresp(this, 0x20, 0x500, 0x25, NULL((void *)0)))
2771 return;
2772 if (azalia_comresp(this, 0x20, 0x400,
2773 atmos_v23_v25[i].v25, NULL((void *)0)))
2774 return;
2775 }
2776
2777 if (azalia_comresp(this, 0x20, 0x500, 0x26, NULL((void *)0)))
2778 return;
2779 if (azalia_comresp(this, 0x20, 0x4b0, 0x10, NULL((void *)0)))
2780 return;
2781 }
2782}