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