1 /* 2 * blacklist.c 3 * 4 * Check to see if the given machine has a known bad ACPI BIOS 5 * or if the BIOS is too old. 6 * Check given machine against acpi_osi_dmi_table[]. 7 * 8 * Copyright (C) 2004 Len Brown <len.brown@intel.com> 9 * Copyright (C) 2002 Andy Grover <andrew.grover@intel.com> 10 * 11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or (at 16 * your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, but 19 * WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * General Public License for more details. 22 * 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 */ 25 26 #include <linux/kernel.h> 27 #include <linux/init.h> 28 #include <linux/acpi.h> 29 #include <linux/dmi.h> 30 31 #include "internal.h" 32 33 enum acpi_blacklist_predicates { 34 all_versions, 35 less_than_or_equal, 36 equal, 37 greater_than_or_equal, 38 }; 39 40 struct acpi_blacklist_item { 41 char oem_id[7]; 42 char oem_table_id[9]; 43 u32 oem_revision; 44 char *table; 45 enum acpi_blacklist_predicates oem_revision_predicate; 46 char *reason; 47 u32 is_critical_error; 48 }; 49 50 static struct dmi_system_id acpi_osi_dmi_table[] __initdata; 51 52 /* 53 * POLICY: If *anything* doesn't work, put it on the blacklist. 54 * If they are critical errors, mark it critical, and abort driver load. 55 */ 56 static struct acpi_blacklist_item acpi_blacklist[] __initdata = { 57 /* Compaq Presario 1700 */ 58 {"PTLTD ", " DSDT ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal, 59 "Multiple problems", 1}, 60 /* Sony FX120, FX140, FX150? */ 61 {"SONY ", "U0 ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal, 62 "ACPI driver problem", 1}, 63 /* Compaq Presario 800, Insyde BIOS */ 64 {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal, 65 "Does not use _REG to protect EC OpRegions", 1}, 66 /* IBM 600E - _ADR should return 7, but it returns 1 */ 67 {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, 68 "Incorrect _ADR", 1}, 69 70 {""} 71 }; 72 73 int __init acpi_blacklisted(void) 74 { 75 int i = 0; 76 int blacklisted = 0; 77 struct acpi_table_header table_header; 78 79 while (acpi_blacklist[i].oem_id[0] != '\0') { 80 if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) { 81 i++; 82 continue; 83 } 84 85 if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) { 86 i++; 87 continue; 88 } 89 90 if (strncmp 91 (acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 92 8)) { 93 i++; 94 continue; 95 } 96 97 if ((acpi_blacklist[i].oem_revision_predicate == all_versions) 98 || (acpi_blacklist[i].oem_revision_predicate == 99 less_than_or_equal 100 && table_header.oem_revision <= 101 acpi_blacklist[i].oem_revision) 102 || (acpi_blacklist[i].oem_revision_predicate == 103 greater_than_or_equal 104 && table_header.oem_revision >= 105 acpi_blacklist[i].oem_revision) 106 || (acpi_blacklist[i].oem_revision_predicate == equal 107 && table_header.oem_revision == 108 acpi_blacklist[i].oem_revision)) { 109 110 printk(KERN_ERR PREFIX 111 "Vendor \"%6.6s\" System \"%8.8s\" " 112 "Revision 0x%x has a known ACPI BIOS problem.\n", 113 acpi_blacklist[i].oem_id, 114 acpi_blacklist[i].oem_table_id, 115 acpi_blacklist[i].oem_revision); 116 117 printk(KERN_ERR PREFIX 118 "Reason: %s. This is a %s error\n", 119 acpi_blacklist[i].reason, 120 (acpi_blacklist[i]. 121 is_critical_error ? "non-recoverable" : 122 "recoverable")); 123 124 blacklisted = acpi_blacklist[i].is_critical_error; 125 break; 126 } else { 127 i++; 128 } 129 } 130 131 dmi_check_system(acpi_osi_dmi_table); 132 133 return blacklisted; 134 } 135 #ifdef CONFIG_DMI 136 static int __init dmi_enable_osi_linux(const struct dmi_system_id *d) 137 { 138 acpi_dmi_osi_linux(1, d); /* enable */ 139 return 0; 140 } 141 static int __init dmi_disable_osi_vista(const struct dmi_system_id *d) 142 { 143 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); 144 acpi_osi_setup("!Windows 2006"); 145 acpi_osi_setup("!Windows 2006 SP1"); 146 acpi_osi_setup("!Windows 2006 SP2"); 147 return 0; 148 } 149 static int __init dmi_disable_osi_win7(const struct dmi_system_id *d) 150 { 151 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); 152 acpi_osi_setup("!Windows 2009"); 153 return 0; 154 } 155 static int __init dmi_disable_osi_win8(const struct dmi_system_id *d) 156 { 157 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); 158 acpi_osi_setup("!Windows 2012"); 159 return 0; 160 } 161 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE 162 static int __init dmi_enable_rev_override(const struct dmi_system_id *d) 163 { 164 printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n", 165 d->ident); 166 acpi_rev_override_setup(NULL); 167 return 0; 168 } 169 #endif 170 171 static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { 172 { 173 .callback = dmi_disable_osi_vista, 174 .ident = "Fujitsu Siemens", 175 .matches = { 176 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 177 DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), 178 }, 179 }, 180 { 181 /* 182 * There have a NVIF method in MSI GX723 DSDT need call by Nvidia 183 * driver (e.g. nouveau) when user press brightness hotkey. 184 * Currently, nouveau driver didn't do the job and it causes there 185 * have a infinite while loop in DSDT when user press hotkey. 186 * We add MSI GX723's dmi information to this table for workaround 187 * this issue. 188 * Will remove MSI GX723 from the table after nouveau grows support. 189 */ 190 .callback = dmi_disable_osi_vista, 191 .ident = "MSI GX723", 192 .matches = { 193 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 194 DMI_MATCH(DMI_PRODUCT_NAME, "GX723"), 195 }, 196 }, 197 { 198 .callback = dmi_disable_osi_vista, 199 .ident = "Sony VGN-NS10J_S", 200 .matches = { 201 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 202 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"), 203 }, 204 }, 205 { 206 .callback = dmi_disable_osi_vista, 207 .ident = "Sony VGN-SR290J", 208 .matches = { 209 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 210 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"), 211 }, 212 }, 213 { 214 .callback = dmi_disable_osi_vista, 215 .ident = "VGN-NS50B_L", 216 .matches = { 217 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 218 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS50B_L"), 219 }, 220 }, 221 { 222 .callback = dmi_disable_osi_vista, 223 .ident = "VGN-SR19XN", 224 .matches = { 225 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 226 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"), 227 }, 228 }, 229 { 230 .callback = dmi_disable_osi_vista, 231 .ident = "Toshiba Satellite L355", 232 .matches = { 233 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 234 DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"), 235 }, 236 }, 237 { 238 .callback = dmi_disable_osi_win7, 239 .ident = "ASUS K50IJ", 240 .matches = { 241 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), 242 DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"), 243 }, 244 }, 245 { 246 .callback = dmi_disable_osi_vista, 247 .ident = "Toshiba P305D", 248 .matches = { 249 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 250 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"), 251 }, 252 }, 253 { 254 .callback = dmi_disable_osi_vista, 255 .ident = "Toshiba NB100", 256 .matches = { 257 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 258 DMI_MATCH(DMI_PRODUCT_NAME, "NB100"), 259 }, 260 }, 261 262 /* 263 * The wireless hotkey does not work on those machines when 264 * returning true for _OSI("Windows 2012") 265 */ 266 { 267 .callback = dmi_disable_osi_win8, 268 .ident = "Dell Inspiron 7737", 269 .matches = { 270 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 271 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"), 272 }, 273 }, 274 { 275 .callback = dmi_disable_osi_win8, 276 .ident = "Dell Inspiron 7537", 277 .matches = { 278 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 279 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"), 280 }, 281 }, 282 { 283 .callback = dmi_disable_osi_win8, 284 .ident = "Dell Inspiron 5437", 285 .matches = { 286 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 287 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5437"), 288 }, 289 }, 290 { 291 .callback = dmi_disable_osi_win8, 292 .ident = "Dell Inspiron 3437", 293 .matches = { 294 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 295 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3437"), 296 }, 297 }, 298 { 299 .callback = dmi_disable_osi_win8, 300 .ident = "Dell Vostro 3446", 301 .matches = { 302 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 303 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"), 304 }, 305 }, 306 { 307 .callback = dmi_disable_osi_win8, 308 .ident = "Dell Vostro 3546", 309 .matches = { 310 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 311 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"), 312 }, 313 }, 314 315 /* 316 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. 317 * Linux ignores it, except for the machines enumerated below. 318 */ 319 320 /* 321 * Without this this EEEpc exports a non working WMI interface, with 322 * this it exports a working "good old" eeepc_laptop interface, fixing 323 * both brightness control, and rfkill not working. 324 */ 325 { 326 .callback = dmi_enable_osi_linux, 327 .ident = "Asus EEE PC 1015PX", 328 .matches = { 329 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."), 330 DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"), 331 }, 332 }, 333 334 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE 335 /* 336 * DELL XPS 13 (2015) switches sound between HDA and I2S 337 * depending on the ACPI _REV callback. If userspace supports 338 * I2S sufficiently (or if you do not care about sound), you 339 * can safely disable this quirk. 340 */ 341 { 342 .callback = dmi_enable_rev_override, 343 .ident = "DELL XPS 13 (2015)", 344 .matches = { 345 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 346 DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), 347 }, 348 }, 349 #endif 350 {} 351 }; 352 353 #endif /* CONFIG_DMI */ 354