1 /* 2 * Copyright (C) 2015 Red Hat Inc. 3 * Hans de Goede <hdegoede@redhat.com> 4 * Copyright (C) 2008 SuSE Linux Products GmbH 5 * Thomas Renninger <trenn@suse.de> 6 * 7 * May be copied or modified under the terms of the GNU General Public License 8 * 9 * video_detect.c: 10 * After PCI devices are glued with ACPI devices 11 * acpi_get_pci_dev() can be called to identify ACPI graphics 12 * devices for which a real graphics card is plugged in 13 * 14 * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B) 15 * are available, video.ko should be used to handle the device. 16 * 17 * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop, 18 * sony_acpi,... can take care about backlight brightness. 19 * 20 * Backlight drivers can use acpi_video_get_backlight_type() to determine which 21 * driver should handle the backlight. RAW/GPU-driver backlight drivers must 22 * use the acpi_video_backlight_use_native() helper for this. 23 * 24 * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m) 25 * this file will not be compiled and acpi_video_get_backlight_type() will 26 * always return acpi_backlight_vendor. 27 */ 28 29 #include <linux/export.h> 30 #include <linux/acpi.h> 31 #include <linux/apple-gmux.h> 32 #include <linux/backlight.h> 33 #include <linux/dmi.h> 34 #include <linux/module.h> 35 #include <linux/pci.h> 36 #include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h> 37 #include <linux/pnp.h> 38 #include <linux/types.h> 39 #include <linux/workqueue.h> 40 #include <acpi/video.h> 41 42 static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef; 43 static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef; 44 45 static void acpi_video_parse_cmdline(void) 46 { 47 if (!strcmp("vendor", acpi_video_backlight_string)) 48 acpi_backlight_cmdline = acpi_backlight_vendor; 49 if (!strcmp("video", acpi_video_backlight_string)) 50 acpi_backlight_cmdline = acpi_backlight_video; 51 if (!strcmp("native", acpi_video_backlight_string)) 52 acpi_backlight_cmdline = acpi_backlight_native; 53 if (!strcmp("nvidia_wmi_ec", acpi_video_backlight_string)) 54 acpi_backlight_cmdline = acpi_backlight_nvidia_wmi_ec; 55 if (!strcmp("apple_gmux", acpi_video_backlight_string)) 56 acpi_backlight_cmdline = acpi_backlight_apple_gmux; 57 if (!strcmp("none", acpi_video_backlight_string)) 58 acpi_backlight_cmdline = acpi_backlight_none; 59 } 60 61 static acpi_status 62 find_video(acpi_handle handle, u32 lvl, void *context, void **rv) 63 { 64 struct acpi_device *acpi_dev = acpi_fetch_acpi_dev(handle); 65 long *cap = context; 66 struct pci_dev *dev; 67 68 static const struct acpi_device_id video_ids[] = { 69 {ACPI_VIDEO_HID, 0}, 70 {"", 0}, 71 }; 72 73 if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) { 74 dev = acpi_get_pci_dev(handle); 75 if (!dev) 76 return AE_OK; 77 pci_dev_put(dev); 78 *cap |= acpi_is_video_device(handle); 79 } 80 return AE_OK; 81 } 82 83 /* This depends on ACPI_WMI which is X86 only */ 84 #ifdef CONFIG_X86 85 static bool nvidia_wmi_ec_supported(void) 86 { 87 struct wmi_brightness_args args = { 88 .mode = WMI_BRIGHTNESS_MODE_GET, 89 .val = 0, 90 .ret = 0, 91 }; 92 struct acpi_buffer buf = { (acpi_size)sizeof(args), &args }; 93 acpi_status status; 94 95 status = wmi_evaluate_method(WMI_BRIGHTNESS_GUID, 0, 96 WMI_BRIGHTNESS_METHOD_SOURCE, &buf, &buf); 97 if (ACPI_FAILURE(status)) 98 return false; 99 100 /* 101 * If brightness is handled by the EC then nvidia-wmi-ec-backlight 102 * should be used, else the GPU driver(s) should be used. 103 */ 104 return args.ret == WMI_BRIGHTNESS_SOURCE_EC; 105 } 106 #else 107 static bool nvidia_wmi_ec_supported(void) 108 { 109 return false; 110 } 111 #endif 112 113 /* Force to use vendor driver when the ACPI device is known to be 114 * buggy */ 115 static int video_detect_force_vendor(const struct dmi_system_id *d) 116 { 117 acpi_backlight_dmi = acpi_backlight_vendor; 118 return 0; 119 } 120 121 static int video_detect_force_video(const struct dmi_system_id *d) 122 { 123 acpi_backlight_dmi = acpi_backlight_video; 124 return 0; 125 } 126 127 static int video_detect_force_native(const struct dmi_system_id *d) 128 { 129 acpi_backlight_dmi = acpi_backlight_native; 130 return 0; 131 } 132 133 static int video_detect_force_none(const struct dmi_system_id *d) 134 { 135 acpi_backlight_dmi = acpi_backlight_none; 136 return 0; 137 } 138 139 static const struct dmi_system_id video_detect_dmi_table[] = { 140 /* 141 * Models which should use the vendor backlight interface, 142 * because of broken ACPI video backlight control. 143 */ 144 { 145 /* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */ 146 .callback = video_detect_force_vendor, 147 /* Acer KAV80 */ 148 .matches = { 149 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 150 DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"), 151 }, 152 }, 153 { 154 .callback = video_detect_force_vendor, 155 /* Asus UL30VT */ 156 .matches = { 157 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), 158 DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), 159 }, 160 }, 161 { 162 .callback = video_detect_force_vendor, 163 /* Asus UL30A */ 164 .matches = { 165 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), 166 DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), 167 }, 168 }, 169 { 170 .callback = video_detect_force_vendor, 171 /* Asus X55U */ 172 .matches = { 173 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 174 DMI_MATCH(DMI_PRODUCT_NAME, "X55U"), 175 }, 176 }, 177 { 178 /* https://bugs.launchpad.net/bugs/1000146 */ 179 .callback = video_detect_force_vendor, 180 /* Asus X101CH */ 181 .matches = { 182 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 183 DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"), 184 }, 185 }, 186 { 187 .callback = video_detect_force_vendor, 188 /* Asus X401U */ 189 .matches = { 190 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 191 DMI_MATCH(DMI_PRODUCT_NAME, "X401U"), 192 }, 193 }, 194 { 195 .callback = video_detect_force_vendor, 196 /* Asus X501U */ 197 .matches = { 198 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 199 DMI_MATCH(DMI_PRODUCT_NAME, "X501U"), 200 }, 201 }, 202 { 203 /* https://bugs.launchpad.net/bugs/1000146 */ 204 .callback = video_detect_force_vendor, 205 /* Asus 1015CX */ 206 .matches = { 207 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 208 DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"), 209 }, 210 }, 211 { 212 .callback = video_detect_force_vendor, 213 /* Samsung N150/N210/N220 */ 214 .matches = { 215 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 216 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), 217 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), 218 }, 219 }, 220 { 221 .callback = video_detect_force_vendor, 222 /* Samsung NF110/NF210/NF310 */ 223 .matches = { 224 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 225 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), 226 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), 227 }, 228 }, 229 { 230 .callback = video_detect_force_vendor, 231 /* Samsung NC210 */ 232 .matches = { 233 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 234 DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"), 235 DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"), 236 }, 237 }, 238 { 239 .callback = video_detect_force_vendor, 240 /* Xiaomi Mi Pad 2 */ 241 .matches = { 242 DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), 243 DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), 244 }, 245 }, 246 247 /* 248 * Models which should use the vendor backlight interface, 249 * because of broken native backlight control. 250 */ 251 { 252 .callback = video_detect_force_vendor, 253 /* Sony Vaio PCG-FRV35 */ 254 .matches = { 255 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 256 DMI_MATCH(DMI_PRODUCT_NAME, "PCG-FRV35"), 257 }, 258 }, 259 260 /* 261 * Toshiba models with Transflective display, these need to use 262 * the toshiba_acpi vendor driver for proper Transflective handling. 263 */ 264 { 265 .callback = video_detect_force_vendor, 266 .matches = { 267 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 268 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"), 269 }, 270 }, 271 { 272 .callback = video_detect_force_vendor, 273 .matches = { 274 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 275 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"), 276 }, 277 }, 278 279 /* 280 * These models have a working acpi_video backlight control, and using 281 * native backlight causes a regression where backlight does not work 282 * when userspace is not handling brightness key events. Disable 283 * native_backlight on these to fix this: 284 * https://bugzilla.kernel.org/show_bug.cgi?id=81691 285 */ 286 { 287 .callback = video_detect_force_video, 288 /* ThinkPad T420 */ 289 .matches = { 290 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 291 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"), 292 }, 293 }, 294 { 295 .callback = video_detect_force_video, 296 /* ThinkPad T520 */ 297 .matches = { 298 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 299 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"), 300 }, 301 }, 302 { 303 .callback = video_detect_force_video, 304 /* ThinkPad X201s */ 305 .matches = { 306 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 307 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"), 308 }, 309 }, 310 { 311 .callback = video_detect_force_video, 312 /* ThinkPad X201T */ 313 .matches = { 314 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 315 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"), 316 }, 317 }, 318 319 /* The native backlight controls do not work on some older machines */ 320 { 321 /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */ 322 .callback = video_detect_force_video, 323 /* HP ENVY 15 Notebook */ 324 .matches = { 325 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 326 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"), 327 }, 328 }, 329 { 330 .callback = video_detect_force_video, 331 /* SAMSUNG 870Z5E/880Z5E/680Z5E */ 332 .matches = { 333 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 334 DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"), 335 }, 336 }, 337 { 338 .callback = video_detect_force_video, 339 /* SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V */ 340 .matches = { 341 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 342 DMI_MATCH(DMI_PRODUCT_NAME, 343 "370R4E/370R4V/370R5E/3570RE/370R5V"), 344 }, 345 }, 346 { 347 /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */ 348 .callback = video_detect_force_video, 349 /* SAMSUNG 3570R/370R/470R/450R/510R/4450RV */ 350 .matches = { 351 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 352 DMI_MATCH(DMI_PRODUCT_NAME, 353 "3570R/370R/470R/450R/510R/4450RV"), 354 }, 355 }, 356 { 357 /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */ 358 .callback = video_detect_force_video, 359 /* SAMSUNG 670Z5E */ 360 .matches = { 361 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 362 DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"), 363 }, 364 }, 365 { 366 /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ 367 .callback = video_detect_force_video, 368 /* SAMSUNG 730U3E/740U3E */ 369 .matches = { 370 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 371 DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), 372 }, 373 }, 374 { 375 /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */ 376 .callback = video_detect_force_video, 377 /* SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D */ 378 .matches = { 379 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 380 DMI_MATCH(DMI_PRODUCT_NAME, 381 "900X3C/900X3D/900X3E/900X4C/900X4D"), 382 }, 383 }, 384 { 385 /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */ 386 .callback = video_detect_force_video, 387 /* Dell XPS14 L421X */ 388 .matches = { 389 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 390 DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"), 391 }, 392 }, 393 { 394 /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */ 395 .callback = video_detect_force_video, 396 /* Dell XPS15 L521X */ 397 .matches = { 398 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 399 DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"), 400 }, 401 }, 402 { 403 /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */ 404 .callback = video_detect_force_video, 405 /* SAMSUNG 530U4E/540U4E */ 406 .matches = { 407 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 408 DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"), 409 }, 410 }, 411 { 412 /* https://bugs.launchpad.net/bugs/1894667 */ 413 .callback = video_detect_force_video, 414 /* HP 635 Notebook */ 415 .matches = { 416 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 417 DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"), 418 }, 419 }, 420 421 /* Non win8 machines which need native backlight nevertheless */ 422 { 423 /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */ 424 .callback = video_detect_force_native, 425 /* Lenovo Ideapad S405 */ 426 .matches = { 427 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 428 DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"), 429 }, 430 }, 431 { 432 /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */ 433 .callback = video_detect_force_native, 434 /* Lenovo Ideapad Z570 */ 435 .matches = { 436 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 437 DMI_MATCH(DMI_PRODUCT_NAME, "102434U"), 438 }, 439 }, 440 { 441 .callback = video_detect_force_native, 442 /* Lenovo E41-25 */ 443 .matches = { 444 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 445 DMI_MATCH(DMI_PRODUCT_NAME, "81FS"), 446 }, 447 }, 448 { 449 .callback = video_detect_force_native, 450 /* Lenovo E41-45 */ 451 .matches = { 452 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 453 DMI_MATCH(DMI_PRODUCT_NAME, "82BK"), 454 }, 455 }, 456 { 457 /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */ 458 .callback = video_detect_force_native, 459 /* Apple MacBook Pro 12,1 */ 460 .matches = { 461 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 462 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"), 463 }, 464 }, 465 { 466 .callback = video_detect_force_native, 467 /* Dell Inspiron N4010 */ 468 .matches = { 469 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 470 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N4010"), 471 }, 472 }, 473 { 474 .callback = video_detect_force_native, 475 /* Dell Vostro V131 */ 476 .matches = { 477 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 478 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), 479 }, 480 }, 481 { 482 /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */ 483 .callback = video_detect_force_native, 484 /* Dell XPS 17 L702X */ 485 .matches = { 486 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 487 DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"), 488 }, 489 }, 490 { 491 .callback = video_detect_force_native, 492 /* Dell Precision 7510 */ 493 .matches = { 494 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 495 DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"), 496 }, 497 }, 498 { 499 .callback = video_detect_force_native, 500 /* Acer Aspire 4810T */ 501 .matches = { 502 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 503 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 4810T"), 504 }, 505 }, 506 { 507 .callback = video_detect_force_native, 508 /* Acer Aspire 5738z */ 509 .matches = { 510 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 511 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"), 512 DMI_MATCH(DMI_BOARD_NAME, "JV50"), 513 }, 514 }, 515 { 516 /* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */ 517 .callback = video_detect_force_native, 518 /* Acer Aspire 5741 */ 519 .matches = { 520 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 521 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"), 522 }, 523 }, 524 { 525 /* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */ 526 .callback = video_detect_force_native, 527 /* Acer Aspire 5750 */ 528 .matches = { 529 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 530 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"), 531 }, 532 }, 533 { 534 /* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */ 535 .callback = video_detect_force_native, 536 /* Acer Extensa 5235 */ 537 .matches = { 538 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 539 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"), 540 }, 541 }, 542 { 543 .callback = video_detect_force_native, 544 /* Acer TravelMate 4750 */ 545 .matches = { 546 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 547 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), 548 }, 549 }, 550 { 551 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */ 552 .callback = video_detect_force_native, 553 /* Acer TravelMate 5735Z */ 554 .matches = { 555 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 556 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"), 557 DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), 558 }, 559 }, 560 { 561 /* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */ 562 .callback = video_detect_force_native, 563 /* Acer TravelMate 5760 */ 564 .matches = { 565 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"), 566 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"), 567 }, 568 }, 569 { 570 .callback = video_detect_force_native, 571 /* ASUSTeK COMPUTER INC. GA401 */ 572 .matches = { 573 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 574 DMI_MATCH(DMI_PRODUCT_NAME, "GA401"), 575 }, 576 }, 577 { 578 .callback = video_detect_force_native, 579 /* ASUSTeK COMPUTER INC. GA502 */ 580 .matches = { 581 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 582 DMI_MATCH(DMI_PRODUCT_NAME, "GA502"), 583 }, 584 }, 585 { 586 .callback = video_detect_force_native, 587 /* ASUSTeK COMPUTER INC. GA503 */ 588 .matches = { 589 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 590 DMI_MATCH(DMI_PRODUCT_NAME, "GA503"), 591 }, 592 }, 593 { 594 .callback = video_detect_force_native, 595 /* Asus U46E */ 596 .matches = { 597 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), 598 DMI_MATCH(DMI_PRODUCT_NAME, "U46E"), 599 }, 600 }, 601 { 602 .callback = video_detect_force_native, 603 /* Asus UX303UB */ 604 .matches = { 605 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 606 DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"), 607 }, 608 }, 609 { 610 .callback = video_detect_force_native, 611 /* HP EliteBook 8460p */ 612 .matches = { 613 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 614 DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8460p"), 615 }, 616 }, 617 { 618 .callback = video_detect_force_native, 619 /* HP Pavilion g6-1d80nr / B4U19UA */ 620 .matches = { 621 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 622 DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion g6 Notebook PC"), 623 DMI_MATCH(DMI_PRODUCT_SKU, "B4U19UA"), 624 }, 625 }, 626 { 627 .callback = video_detect_force_native, 628 /* Samsung N150P */ 629 .matches = { 630 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 631 DMI_MATCH(DMI_PRODUCT_NAME, "N150P"), 632 DMI_MATCH(DMI_BOARD_NAME, "N150P"), 633 }, 634 }, 635 { 636 .callback = video_detect_force_native, 637 /* Samsung N145P/N250P/N260P */ 638 .matches = { 639 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 640 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), 641 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), 642 }, 643 }, 644 { 645 .callback = video_detect_force_native, 646 /* Samsung N250P */ 647 .matches = { 648 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 649 DMI_MATCH(DMI_PRODUCT_NAME, "N250P"), 650 DMI_MATCH(DMI_BOARD_NAME, "N250P"), 651 }, 652 }, 653 { 654 /* https://bugzilla.kernel.org/show_bug.cgi?id=202401 */ 655 .callback = video_detect_force_native, 656 /* Sony Vaio VPCEH3U1E */ 657 .matches = { 658 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 659 DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"), 660 }, 661 }, 662 { 663 .callback = video_detect_force_native, 664 /* Sony Vaio VPCY11S1E */ 665 .matches = { 666 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), 667 DMI_MATCH(DMI_PRODUCT_NAME, "VPCY11S1E"), 668 }, 669 }, 670 671 /* 672 * These Toshibas have a broken acpi-video interface for brightness 673 * control. They also have an issue where the panel is off after 674 * suspend until a special firmware call is made to turn it back 675 * on. This is handled by the toshiba_acpi kernel module, so that 676 * module must be enabled for these models to work correctly. 677 */ 678 { 679 /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ 680 .callback = video_detect_force_native, 681 /* Toshiba Portégé R700 */ 682 .matches = { 683 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 684 DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), 685 }, 686 }, 687 { 688 /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */ 689 /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ 690 .callback = video_detect_force_native, 691 /* Toshiba Satellite/Portégé R830 */ 692 .matches = { 693 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 694 DMI_MATCH(DMI_PRODUCT_NAME, "R830"), 695 }, 696 }, 697 { 698 .callback = video_detect_force_native, 699 /* Toshiba Satellite/Portégé Z830 */ 700 .matches = { 701 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 702 DMI_MATCH(DMI_PRODUCT_NAME, "Z830"), 703 }, 704 }, 705 706 /* 707 * Models which have nvidia-ec-wmi support, but should not use it. 708 * Note this indicates a likely firmware bug on these models and should 709 * be revisited if/when Linux gets support for dynamic mux mode. 710 */ 711 { 712 .callback = video_detect_force_native, 713 /* Dell G15 5515 */ 714 .matches = { 715 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 716 DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"), 717 }, 718 }, 719 720 /* 721 * Desktops which falsely report a backlight and which our heuristics 722 * for this do not catch. 723 */ 724 { 725 .callback = video_detect_force_none, 726 /* Dell OptiPlex 9020M */ 727 .matches = { 728 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 729 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"), 730 }, 731 }, 732 { 733 .callback = video_detect_force_none, 734 /* GIGABYTE GB-BXBT-2807 */ 735 .matches = { 736 DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"), 737 DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"), 738 }, 739 }, 740 { 741 .callback = video_detect_force_none, 742 /* MSI MS-7721 */ 743 .matches = { 744 DMI_MATCH(DMI_SYS_VENDOR, "MSI"), 745 DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"), 746 }, 747 }, 748 { }, 749 }; 750 751 static bool google_cros_ec_present(void) 752 { 753 return acpi_dev_found("GOOG0004") || acpi_dev_found("GOOG000C"); 754 } 755 756 /* 757 * Windows 8 and newer no longer use the ACPI video interface, so it often 758 * does not work. So on win8+ systems prefer native brightness control. 759 * Chromebooks should always prefer native backlight control. 760 */ 761 static bool prefer_native_over_acpi_video(void) 762 { 763 return acpi_osi_is_win8() || google_cros_ec_present(); 764 } 765 766 /* 767 * Determine which type of backlight interface to use on this system, 768 * First check cmdline, then dmi quirks, then do autodetect. 769 */ 770 static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native) 771 { 772 static DEFINE_MUTEX(init_mutex); 773 static bool nvidia_wmi_ec_present; 774 static bool apple_gmux_present; 775 static bool native_available; 776 static bool init_done; 777 static long video_caps; 778 779 /* Parse cmdline, dmi and acpi only once */ 780 mutex_lock(&init_mutex); 781 if (!init_done) { 782 acpi_video_parse_cmdline(); 783 dmi_check_system(video_detect_dmi_table); 784 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 785 ACPI_UINT32_MAX, find_video, NULL, 786 &video_caps, NULL); 787 nvidia_wmi_ec_present = nvidia_wmi_ec_supported(); 788 apple_gmux_present = apple_gmux_detect(NULL, NULL); 789 init_done = true; 790 } 791 if (native) 792 native_available = true; 793 mutex_unlock(&init_mutex); 794 795 /* 796 * The below heuristics / detection steps are in order of descending 797 * presedence. The commandline takes presedence over anything else. 798 */ 799 if (acpi_backlight_cmdline != acpi_backlight_undef) 800 return acpi_backlight_cmdline; 801 802 /* DMI quirks override any autodetection. */ 803 if (acpi_backlight_dmi != acpi_backlight_undef) 804 return acpi_backlight_dmi; 805 806 /* Special cases such as nvidia_wmi_ec and apple gmux. */ 807 if (nvidia_wmi_ec_present) 808 return acpi_backlight_nvidia_wmi_ec; 809 810 if (apple_gmux_present) 811 return acpi_backlight_apple_gmux; 812 813 /* Use ACPI video if available, except when native should be preferred. */ 814 if ((video_caps & ACPI_VIDEO_BACKLIGHT) && 815 !(native_available && prefer_native_over_acpi_video())) 816 return acpi_backlight_video; 817 818 /* Use native if available */ 819 if (native_available) 820 return acpi_backlight_native; 821 822 /* No ACPI video/native (old hw), use vendor specific fw methods. */ 823 return acpi_backlight_vendor; 824 } 825 826 enum acpi_backlight_type acpi_video_get_backlight_type(void) 827 { 828 return __acpi_video_get_backlight_type(false); 829 } 830 EXPORT_SYMBOL(acpi_video_get_backlight_type); 831 832 bool acpi_video_backlight_use_native(void) 833 { 834 return __acpi_video_get_backlight_type(true) == acpi_backlight_native; 835 } 836 EXPORT_SYMBOL(acpi_video_backlight_use_native); 837