]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/dev/sound/pci/hda/hdaa_patches.c
MFC r230181, r230312, r230326, r230331, r230451, r230465, r230488,
[FreeBSD/stable/8.git] / sys / dev / sound / pci / hda / hdaa_patches.c
1 /*-
2  * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3  * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4  * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
31  */
32
33 #ifdef HAVE_KERNEL_OPTION_HEADERS
34 #include "opt_snd.h"
35 #endif
36
37 #include <dev/sound/pcm/sound.h>
38
39 #include <sys/ctype.h>
40
41 #include <dev/sound/pci/hda/hdac.h>
42 #include <dev/sound/pci/hda/hdaa.h>
43 #include <dev/sound/pci/hda/hda_reg.h>
44
45 SND_DECLARE_FILE("$FreeBSD$");
46
47 static const struct {
48         uint32_t model;
49         uint32_t id;
50         uint32_t set, unset;
51         uint32_t gpio;
52 } hdac_quirks[] = {
53         /*
54          * XXX Force stereo quirk. Monoural recording / playback
55          *     on few codecs (especially ALC880) seems broken or
56          *     perhaps unsupported.
57          */
58         { HDA_MATCH_ALL, HDA_MATCH_ALL,
59             HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
60             0 },
61         { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
62             0, 0,
63             HDAA_GPIO_SET(0) },
64         { ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
65             0, 0,
66             HDAA_GPIO_SET(0) },
67         { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
68             0, 0,
69             HDAA_GPIO_SET(0) },
70         { ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
71             0, 0,
72             HDAA_GPIO_SET(0) },
73         { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
74             0, 0,
75             HDAA_GPIO_SET(0) },
76         { ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
77             0, 0,
78             HDAA_GPIO_SET(0) },
79         { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
80             HDAA_QUIRK_EAPDINV, 0,
81             0 },
82         { ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
83             HDAA_QUIRK_EAPDINV, 0,
84             0 },
85         { ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
86             HDAA_QUIRK_OVREF, 0,
87             0 },
88         { UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
89             HDAA_QUIRK_OVREF, 0,
90             0 },
91         /*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
92             HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
93             0 },*/
94         { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
95             0, 0,
96             HDAA_GPIO_SET(1) },
97         { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
98             HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
99             0 },
100         { SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
101             HDAA_QUIRK_EAPDINV, 0,
102             0 },
103         { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
104             HDAA_QUIRK_OVREF50, 0,
105             HDAA_GPIO_SET(0) },
106         { APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
107             0, 0,
108             HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
109         { APPLE_MACBOOKPRO55, HDA_CODEC_CS4206,
110             0, 0,
111             HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
112         { DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
113             0, 0,
114             HDAA_GPIO_SET(0) },
115         { DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
116             0, 0,
117             HDAA_GPIO_SET(2) },
118         { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
119             0, 0,
120             HDAA_GPIO_SET(0) },
121         { HDA_MATCH_ALL, HDA_CODEC_AD1988,
122             HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
123             0 },
124         { HDA_MATCH_ALL, HDA_CODEC_AD1988B,
125             HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
126             0 },
127         { HDA_MATCH_ALL, HDA_CODEC_CX20549,
128             0, HDAA_QUIRK_FORCESTEREO,
129             0 }
130 };
131 #define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
132
133 static void
134 hdac_pin_patch(struct hdaa_widget *w)
135 {
136         const char *patch = NULL;
137         uint32_t config, orig, id, subid;
138         nid_t nid = w->nid;
139
140         config = orig = w->wclass.pin.config;
141         id = hdaa_codec_id(w->devinfo);
142         subid = hdaa_subvendor_id(w->devinfo);
143
144         /* XXX: Old patches require complete review.
145          * Now they may create more problem then solve due to
146          * incorrect associations.
147          */
148         if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
149                 switch (nid) {
150                 case 26:
151                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
152                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
153                         break;
154                 case 27:
155                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
156                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
157                         break;
158                 default:
159                         break;
160                 }
161         } else if (id == HDA_CODEC_ALC880 &&
162             (subid == CLEVO_D900T_SUBVENDOR ||
163             subid == ASUS_M5200_SUBVENDOR)) {
164                 /*
165                  * Super broken BIOS
166                  */
167                 switch (nid) {
168                 case 24:        /* MIC1 */
169                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
170                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
171                         break;
172                 case 25:        /* XXX MIC2 */
173                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
174                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
175                         break;
176                 case 26:        /* LINE1 */
177                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
178                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
179                         break;
180                 case 27:        /* XXX LINE2 */
181                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
182                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
183                         break;
184                 case 28:        /* CD */
185                         config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
186                         config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
187                         break;
188                 }
189         } else if (id == HDA_CODEC_ALC883 &&
190             (subid == MSI_MS034A_SUBVENDOR ||
191             HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
192                 switch (nid) {
193                 case 25:
194                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
195                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
196                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
197                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
198                         break;
199                 case 28:
200                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
201                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
202                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
203                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
204                         break;
205                 }
206         } else if (id == HDA_CODEC_CX20549 && subid ==
207             HP_V3000_SUBVENDOR) {
208                 switch (nid) {
209                 case 18:
210                         config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
211                         config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
212                         break;
213                 case 20:
214                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
215                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
216                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
217                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
218                         break;
219                 case 21:
220                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
221                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
222                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
223                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
224                         break;
225                 }
226         } else if (id == HDA_CODEC_CX20551 && subid ==
227             HP_DV5000_SUBVENDOR) {
228                 switch (nid) {
229                 case 20:
230                 case 21:
231                         config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
232                         config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
233                         break;
234                 }
235         } else if (id == HDA_CODEC_ALC861 && subid ==
236             ASUS_W6F_SUBVENDOR) {
237                 switch (nid) {
238                 case 11:
239                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
240                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
241                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
242                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
243                         break;
244                 case 12:
245                 case 14:
246                 case 16:
247                 case 31:
248                 case 32:
249                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
250                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
251                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
252                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
253                         break;
254                 case 15:
255                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
256                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
257                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
258                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
259                         break;
260                 }
261         } else if (id == HDA_CODEC_ALC861 && subid ==
262             UNIWILL_9075_SUBVENDOR) {
263                 switch (nid) {
264                 case 15:
265                         config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
266                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
267                         config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
268                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
269                         break;
270                 }
271         }
272
273         /* New patches */
274         if (id == HDA_CODEC_AD1986A &&
275             (subid == ASUS_M2NPVMX_SUBVENDOR ||
276             subid == ASUS_A8NVMCSM_SUBVENDOR ||
277             subid == ASUS_P5PL2_SUBVENDOR)) {
278                 switch (nid) {
279                 case 26: /* Headphones with redirection */
280                         patch = "as=1 seq=15";
281                         break;
282                 case 28: /* 5.1 out => 2.0 out + 1 input */
283                         patch = "device=Line-in as=8 seq=1";
284                         break;
285                 case 29: /* Can't use this as input, as the only available mic
286                           * preamplifier is busy by front panel mic (nid 31).
287                           * If you want to use this rear connector as mic input,
288                           * you have to disable the front panel one. */
289                         patch = "as=0";
290                         break;
291                 case 31: /* Lot of inputs configured with as=15 and unusable */
292                         patch = "as=8 seq=3";
293                         break;
294                 case 32:
295                         patch = "as=8 seq=4";
296                         break;
297                 case 34:
298                         patch = "as=8 seq=5";
299                         break;
300                 case 36:
301                         patch = "as=8 seq=6";
302                         break;
303                 }
304         } else if (id == HDA_CODEC_ALC260 &&
305             HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
306                 switch (nid) {
307                 case 16:
308                         patch = "seq=15 device=Headphones";
309                         break;
310                 }
311         } else if (id == HDA_CODEC_ALC268) {
312             if (subid == ACER_T5320_SUBVENDOR) {
313                 switch (nid) {
314                 case 20: /* Headphones Jack */
315                         patch = "as=1 seq=15";
316                         break;
317                 }
318             }
319         } else if (id == HDA_CODEC_CX20561 &&
320             subid == LENOVO_B450_SUBVENDOR) {
321                 switch (nid) {
322                 case 22:
323                         patch = "as=1 seq=15";
324                         break;
325                 }
326         }
327
328         if (patch != NULL)
329                 config = hdaa_widget_pin_patch(config, patch);
330         HDA_BOOTVERBOSE(
331                 if (config != orig)
332                         device_printf(w->devinfo->dev,
333                             "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
334                             nid, orig, config);
335         );
336         w->wclass.pin.config = config;
337 }
338
339 static void
340 hdaa_widget_patch(struct hdaa_widget *w)
341 {
342         struct hdaa_devinfo *devinfo = w->devinfo;
343         uint32_t orig;
344         nid_t beeper = -1;
345
346         orig = w->param.widget_cap;
347         /* On some codecs beeper is an input pin, but it is not recordable
348            alone. Also most of BIOSes does not declare beeper pin.
349            Change beeper pin node type to beeper to help parser. */
350         switch (hdaa_codec_id(devinfo)) {
351         case HDA_CODEC_AD1882:
352         case HDA_CODEC_AD1883:
353         case HDA_CODEC_AD1984:
354         case HDA_CODEC_AD1984A:
355         case HDA_CODEC_AD1984B:
356         case HDA_CODEC_AD1987:
357         case HDA_CODEC_AD1988:
358         case HDA_CODEC_AD1988B:
359         case HDA_CODEC_AD1989B:
360                 beeper = 26;
361                 break;
362         case HDA_CODEC_ALC260:
363                 beeper = 23;
364                 break;
365         }
366         if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
367             hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
368                 beeper = 29;
369         if (w->nid == beeper) {
370                 w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
371                 w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
372                     HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
373                 w->waspin = 1;
374         }
375         HDA_BOOTVERBOSE(
376                 if (w->param.widget_cap != orig) {
377                         device_printf(w->devinfo->dev,
378                             "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
379                             w->nid, orig, w->param.widget_cap);
380                 }
381         );
382
383         if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
384                 hdac_pin_patch(w);
385 }
386
387 void
388 hdaa_patch(struct hdaa_devinfo *devinfo)
389 {
390         struct hdaa_widget *w;
391         uint32_t id, subid;
392         int i;
393
394         id = hdaa_codec_id(devinfo);
395         subid = hdaa_subvendor_id(devinfo);
396
397         /*
398          * Quirks
399          */
400         for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
401                 if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
402                     HDA_DEV_MATCH(hdac_quirks[i].id, id)))
403                         continue;
404                 if (hdac_quirks[i].set != 0)
405                         devinfo->quirks |=
406                             hdac_quirks[i].set;
407                 if (hdac_quirks[i].unset != 0)
408                         devinfo->quirks &=
409                             ~(hdac_quirks[i].unset);
410         }
411
412         /* Apply per-widget patch. */
413         for (i = devinfo->startnode; i < devinfo->endnode; i++) {
414                 w = hdaa_widget_get(devinfo, i);
415                 if (w == NULL)
416                         continue;
417                 hdaa_widget_patch(w);
418         }
419
420         switch (id) {
421         case HDA_CODEC_AD1983:
422                 /*
423                  * This CODEC has several possible usages, but none
424                  * fit the parser best. Help parser to choose better.
425                  */
426                 /* Disable direct unmixed playback to get pcm volume. */
427                 w = hdaa_widget_get(devinfo, 5);
428                 if (w != NULL)
429                         w->connsenable[0] = 0;
430                 w = hdaa_widget_get(devinfo, 6);
431                 if (w != NULL)
432                         w->connsenable[0] = 0;
433                 w = hdaa_widget_get(devinfo, 11);
434                 if (w != NULL)
435                         w->connsenable[0] = 0;
436                 /* Disable mic and line selectors. */
437                 w = hdaa_widget_get(devinfo, 12);
438                 if (w != NULL)
439                         w->connsenable[1] = 0;
440                 w = hdaa_widget_get(devinfo, 13);
441                 if (w != NULL)
442                         w->connsenable[1] = 0;
443                 /* Disable recording from mono playback mix. */
444                 w = hdaa_widget_get(devinfo, 20);
445                 if (w != NULL)
446                         w->connsenable[3] = 0;
447                 break;
448         case HDA_CODEC_AD1986A:
449                 /*
450                  * This CODEC has overcomplicated input mixing.
451                  * Make some cleaning there.
452                  */
453                 /* Disable input mono mixer. Not needed and not supported. */
454                 w = hdaa_widget_get(devinfo, 43);
455                 if (w != NULL)
456                         w->enable = 0;
457                 /* Disable any with any input mixing mesh. Use separately. */
458                 w = hdaa_widget_get(devinfo, 39);
459                 if (w != NULL)
460                         w->enable = 0;
461                 w = hdaa_widget_get(devinfo, 40);
462                 if (w != NULL)
463                         w->enable = 0;
464                 w = hdaa_widget_get(devinfo, 41);
465                 if (w != NULL)
466                         w->enable = 0;
467                 w = hdaa_widget_get(devinfo, 42);
468                 if (w != NULL)
469                         w->enable = 0;
470                 /* Disable duplicate mixer node connector. */
471                 w = hdaa_widget_get(devinfo, 15);
472                 if (w != NULL)
473                         w->connsenable[3] = 0;
474                 /* There is only one mic preamplifier, use it effectively. */
475                 w = hdaa_widget_get(devinfo, 31);
476                 if (w != NULL) {
477                         if ((w->wclass.pin.config &
478                             HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
479                             HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
480                                 w = hdaa_widget_get(devinfo, 16);
481                                 if (w != NULL)
482                                     w->connsenable[2] = 0;
483                         } else {
484                                 w = hdaa_widget_get(devinfo, 15);
485                                 if (w != NULL)
486                                     w->connsenable[0] = 0;
487                         }
488                 }
489                 w = hdaa_widget_get(devinfo, 32);
490                 if (w != NULL) {
491                         if ((w->wclass.pin.config &
492                             HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
493                             HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
494                                 w = hdaa_widget_get(devinfo, 16);
495                                 if (w != NULL)
496                                     w->connsenable[0] = 0;
497                         } else {
498                                 w = hdaa_widget_get(devinfo, 15);
499                                 if (w != NULL)
500                                     w->connsenable[1] = 0;
501                         }
502                 }
503
504                 if (subid == ASUS_A8X_SUBVENDOR) {
505                         /*
506                          * This is just plain ridiculous.. There
507                          * are several A8 series that share the same
508                          * pci id but works differently (EAPD).
509                          */
510                         w = hdaa_widget_get(devinfo, 26);
511                         if (w != NULL && w->type ==
512                             HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
513                             (w->wclass.pin.config &
514                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
515                             HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
516                                 devinfo->quirks &=
517                                     ~HDAA_QUIRK_EAPDINV;
518                 }
519                 break;
520         case HDA_CODEC_AD1981HD:
521                 /*
522                  * This CODEC has very unusual design with several
523                  * points inappropriate for the present parser.
524                  */
525                 /* Disable recording from mono playback mix. */
526                 w = hdaa_widget_get(devinfo, 21);
527                 if (w != NULL)
528                         w->connsenable[3] = 0;
529                 /* Disable rear to front mic mixer, use separately. */
530                 w = hdaa_widget_get(devinfo, 31);
531                 if (w != NULL)
532                         w->enable = 0;
533                 /* Disable direct playback, use mixer. */
534                 w = hdaa_widget_get(devinfo, 5);
535                 if (w != NULL)
536                         w->connsenable[0] = 0;
537                 w = hdaa_widget_get(devinfo, 6);
538                 if (w != NULL)
539                         w->connsenable[0] = 0;
540                 w = hdaa_widget_get(devinfo, 9);
541                 if (w != NULL)
542                         w->connsenable[0] = 0;
543                 w = hdaa_widget_get(devinfo, 24);
544                 if (w != NULL)
545                         w->connsenable[0] = 0;
546                 break;
547         case HDA_CODEC_CX20582:
548         case HDA_CODEC_CX20583:
549         case HDA_CODEC_CX20584:
550         case HDA_CODEC_CX20585:
551         case HDA_CODEC_CX20590:
552                 /*
553                  * These codecs have extra connectivity on record side
554                  * too reach for the present parser.
555                  */
556                 w = hdaa_widget_get(devinfo, 20);
557                 if (w != NULL)
558                         w->connsenable[1] = 0;
559                 w = hdaa_widget_get(devinfo, 21);
560                 if (w != NULL)
561                         w->connsenable[1] = 0;
562                 w = hdaa_widget_get(devinfo, 22);
563                 if (w != NULL)
564                         w->connsenable[0] = 0;
565                 break;
566         case HDA_CODEC_VT1708S_0:
567         case HDA_CODEC_VT1708S_1:
568         case HDA_CODEC_VT1708S_2:
569         case HDA_CODEC_VT1708S_3:
570         case HDA_CODEC_VT1708S_4:
571         case HDA_CODEC_VT1708S_5:
572         case HDA_CODEC_VT1708S_6:
573         case HDA_CODEC_VT1708S_7:
574                 /*
575                  * These codecs have hidden mic boost controls.
576                  */
577                 w = hdaa_widget_get(devinfo, 26);
578                 if (w != NULL)
579                         w->param.inamp_cap =
580                             (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
581                             (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
582                             (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
583                 w = hdaa_widget_get(devinfo, 30);
584                 if (w != NULL)
585                         w->param.inamp_cap =
586                             (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
587                             (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
588                             (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
589                 break;
590         }
591 }
592
593 void
594 hdaa_patch_direct(struct hdaa_devinfo *devinfo)
595 {
596         device_t dev = devinfo->dev;
597         uint32_t id, subid, val;
598
599         id = hdaa_codec_id(devinfo);
600         subid = hdaa_subvendor_id(devinfo);
601
602         switch (id) {
603         case HDA_CODEC_VT1708S_0:
604         case HDA_CODEC_VT1708S_1:
605         case HDA_CODEC_VT1708S_2:
606         case HDA_CODEC_VT1708S_3:
607         case HDA_CODEC_VT1708S_4:
608         case HDA_CODEC_VT1708S_5:
609         case HDA_CODEC_VT1708S_6:
610         case HDA_CODEC_VT1708S_7:
611                 /* Enable Mic Boost Volume controls. */
612                 hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
613                     0xf98, 0x01));
614                 /* Don't bypass mixer. */
615                 hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
616                     0xf88, 0xc0));
617                 break;
618         }
619         if (subid == APPLE_INTEL_MAC)
620                 hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
621                     0x7e7, 0));
622         if (id == HDA_CODEC_ALC269) {
623                 if (subid == 0x16e31043 || subid == 0x831a1043 ||
624                     subid == 0x834a1043 || subid == 0x83981043 ||
625                     subid == 0x83ce1043) {
626                         /*
627                          * The ditital mics on some Asus laptops produce
628                          * differential signals instead of expected stereo.
629                          * That results in silence if downmix it to mono.
630                          * To workaround, make codec to handle signal as mono.
631                          */
632                         hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
633                         val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, 0x20));
634                         hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
635                         hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, 0x20, val|0x80));
636                 }
637         }
638 }