Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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