File: | dev/pci/azalia_codec.c |
Warning: | line 1276, column 3 Value stored to 'err' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
44 | int azalia_add_convgroup(codec_t *, convgroupset_t *, |
45 | struct io_pin *, int, nid_t *, int, uint32_t, uint32_t); |
46 | |
47 | int azalia_mixer_fix_indexes(codec_t *); |
48 | int azalia_mixer_default(codec_t *); |
49 | int azalia_mixer_ensure_capacity(codec_t *, size_t); |
50 | u_char azalia_mixer_from_device_value(const codec_t *, nid_t, int, uint32_t ); |
51 | uint32_t azalia_mixer_to_device_value(const codec_t *, nid_t, int, u_char); |
52 | |
53 | void azalia_devinfo_offon(mixer_devinfo_t *); |
54 | void azalia_pin_config_ov(widget_t *, int, int); |
55 | void azalia_ampcap_ov(widget_t *, int, int, int, int, int, int); |
56 | int azalia_gpio_unmute(codec_t *, int); |
57 | |
58 | |
59 | int |
60 | azalia_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 | |
574 | int |
575 | azalia_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 | |
582 | int |
583 | azalia_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 | |
614 | int |
615 | azalia_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 | } |
682 | done: |
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 | |
703 | int |
704 | azalia_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 | |
732 | int |
733 | azalia_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 | |
836 | int |
837 | azalia_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 | |
1424 | void |
1425 | azalia_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 | |
1435 | int |
1436 | azalia_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 | |
1459 | int |
1460 | azalia_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 | |
1481 | int |
1482 | azalia_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 | |
1614 | int |
1615 | azalia_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 | |
1675 | int |
1676 | azalia_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 | */ |
1688 | int |
1689 | azalia_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 | |
1964 | int |
1965 | azalia_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 | |
2495 | u_char |
2496 | azalia_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 | |
2522 | uint32_t |
2523 | azalia_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 | |
2548 | int |
2549 | azalia_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 | |
2569 | void |
2570 | azalia_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 | |
2586 | void |
2587 | azalia_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 | |
2610 | int |
2611 | azalia_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 | |
2633 | int |
2634 | azalia_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) */ |
2715 | void |
2716 | azalia_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 | } |