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>
7 * May be copied or modified under the terms of the GNU General Public License
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
14 * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
15 * are available, video.ko should be used to handle the device.
17 * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
18 * sony_acpi,... can take care about backlight brightness.
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.
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.
29 #include <linux/export.h>
30 #include <linux/acpi.h>
31 #include <linux/backlight.h>
32 #include <linux/dmi.h>
33 #include <linux/module.h>
34 #include <linux/pci.h>
35 #include <linux/types.h>
36 #include <linux/workqueue.h>
37 #include <acpi/video.h>
39 void acpi_video_unregister_backlight(void);
41 static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
42 static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
44 static void acpi_video_parse_cmdline(void)
46 if (!strcmp("vendor", acpi_video_backlight_string))
47 acpi_backlight_cmdline = acpi_backlight_vendor;
48 if (!strcmp("video", acpi_video_backlight_string))
49 acpi_backlight_cmdline = acpi_backlight_video;
50 if (!strcmp("native", acpi_video_backlight_string))
51 acpi_backlight_cmdline = acpi_backlight_native;
52 if (!strcmp("none", acpi_video_backlight_string))
53 acpi_backlight_cmdline = acpi_backlight_none;
57 find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
59 struct acpi_device *acpi_dev = acpi_fetch_acpi_dev(handle);
63 static const struct acpi_device_id video_ids[] = {
68 if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) {
69 dev = acpi_get_pci_dev(handle);
73 *cap |= acpi_is_video_device(handle);
78 /* Force to use vendor driver when the ACPI device is known to be
80 static int video_detect_force_vendor(const struct dmi_system_id *d)
82 acpi_backlight_dmi = acpi_backlight_vendor;
86 static int video_detect_force_video(const struct dmi_system_id *d)
88 acpi_backlight_dmi = acpi_backlight_video;
92 static int video_detect_force_native(const struct dmi_system_id *d)
94 acpi_backlight_dmi = acpi_backlight_native;
98 static int video_detect_force_none(const struct dmi_system_id *d)
100 acpi_backlight_dmi = acpi_backlight_none;
104 static const struct dmi_system_id video_detect_dmi_table[] = {
105 /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
106 * ACPI backlight device is used. This flag will definitively break
107 * the backlight interface (even the vendor interface) until next
108 * reboot. It's why we should prevent video.ko from being used here
109 * and we can't rely on a later call to acpi_video_unregister().
112 .callback = video_detect_force_vendor,
115 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
116 DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
117 DMI_MATCH(DMI_BOARD_NAME, "X360"),
121 .callback = video_detect_force_vendor,
124 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
125 DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
129 .callback = video_detect_force_vendor,
132 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
133 DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
137 .callback = video_detect_force_vendor,
138 /* GIGABYTE GB-BXBT-2807 */
140 DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
141 DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
145 .callback = video_detect_force_vendor,
148 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
149 DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
153 .callback = video_detect_force_vendor,
154 /* Xiaomi Mi Pad 2 */
156 DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
157 DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
162 * These models have a working acpi_video backlight control, and using
163 * native backlight causes a regression where backlight does not work
164 * when userspace is not handling brightness key events. Disable
165 * native_backlight on these to fix this:
166 * https://bugzilla.kernel.org/show_bug.cgi?id=81691
169 .callback = video_detect_force_video,
172 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
173 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
177 .callback = video_detect_force_video,
180 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
181 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
185 .callback = video_detect_force_video,
188 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
189 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
193 .callback = video_detect_force_video,
196 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
197 DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
201 /* The native backlight controls do not work on some older machines */
203 /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
204 .callback = video_detect_force_video,
205 /* HP ENVY 15 Notebook */
207 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
208 DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
212 .callback = video_detect_force_video,
213 /* SAMSUNG 870Z5E/880Z5E/680Z5E */
215 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
216 DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
220 .callback = video_detect_force_video,
221 /* SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V */
223 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
224 DMI_MATCH(DMI_PRODUCT_NAME,
225 "370R4E/370R4V/370R5E/3570RE/370R5V"),
229 /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
230 .callback = video_detect_force_video,
231 /* SAMSUNG 3570R/370R/470R/450R/510R/4450RV */
233 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
234 DMI_MATCH(DMI_PRODUCT_NAME,
235 "3570R/370R/470R/450R/510R/4450RV"),
239 /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
240 .callback = video_detect_force_video,
243 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
244 DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
248 /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
249 .callback = video_detect_force_video,
250 /* SAMSUNG 730U3E/740U3E */
252 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
253 DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
257 /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
258 .callback = video_detect_force_video,
259 /* SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D */
261 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
262 DMI_MATCH(DMI_PRODUCT_NAME,
263 "900X3C/900X3D/900X3E/900X4C/900X4D"),
267 /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */
268 .callback = video_detect_force_video,
269 /* Dell XPS14 L421X */
271 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
272 DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
276 /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
277 .callback = video_detect_force_video,
278 /* Dell XPS15 L521X */
280 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
281 DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
285 /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */
286 .callback = video_detect_force_video,
287 /* SAMSUNG 530U4E/540U4E */
289 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
290 DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
293 /* https://bugs.launchpad.net/bugs/1894667 */
295 .callback = video_detect_force_video,
296 /* HP 635 Notebook */
298 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
299 DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
303 /* Non win8 machines which need native backlight nevertheless */
305 /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */
306 .callback = video_detect_force_native,
307 /* Lenovo Ideapad S405 */
309 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
310 DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"),
314 /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
315 .callback = video_detect_force_native,
316 /* Lenovo Ideapad Z570 */
318 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
319 DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
323 .callback = video_detect_force_native,
326 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
327 DMI_MATCH(DMI_PRODUCT_NAME, "81FS"),
331 .callback = video_detect_force_native,
334 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
335 DMI_MATCH(DMI_PRODUCT_NAME, "82BK"),
339 /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
340 .callback = video_detect_force_native,
341 /* Apple MacBook Pro 12,1 */
343 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
344 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
348 .callback = video_detect_force_native,
349 /* Dell Inspiron N4010 */
351 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
352 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N4010"),
356 .callback = video_detect_force_native,
357 /* Dell Vostro V131 */
359 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
360 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
364 /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
365 .callback = video_detect_force_native,
366 /* Dell XPS 17 L702X */
368 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
369 DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
373 .callback = video_detect_force_native,
374 /* Dell Precision 7510 */
376 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
377 DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
381 .callback = video_detect_force_native,
382 /* Acer Aspire 5738z */
384 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
385 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
386 DMI_MATCH(DMI_BOARD_NAME, "JV50"),
390 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
391 .callback = video_detect_force_native,
392 /* Acer TravelMate 5735Z */
394 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
395 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
396 DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
400 .callback = video_detect_force_native,
401 /* ASUSTeK COMPUTER INC. GA401 */
403 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
404 DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
408 .callback = video_detect_force_native,
409 /* ASUSTeK COMPUTER INC. GA502 */
411 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
412 DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
416 .callback = video_detect_force_native,
417 /* ASUSTeK COMPUTER INC. GA503 */
419 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
420 DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
424 * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
425 * working native and video interface. However the default detection
426 * mechanism first registers the video interface before unregistering
427 * it again and switching to the native interface during boot. This
428 * results in a dangling SBIOS request for backlight change for some
429 * reason, causing the backlight to switch to ~2% once per boot on the
430 * first power cord connect or disconnect event. Setting the native
431 * interface explicitly circumvents this buggy behaviour, by avoiding
432 * the unregistering process.
435 .callback = video_detect_force_native,
436 .ident = "Clevo NL5xRU",
438 DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
442 .callback = video_detect_force_native,
443 .ident = "Clevo NL5xRU",
445 DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
446 DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
450 .callback = video_detect_force_native,
451 .ident = "Clevo NL5xRU",
453 DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
454 DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
458 .callback = video_detect_force_native,
459 .ident = "Clevo NL5xNU",
461 DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
465 * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
466 * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
467 * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
471 .callback = video_detect_force_native,
472 .ident = "TongFang PF5PU1G",
474 DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
478 .callback = video_detect_force_native,
479 .ident = "TongFang PF4NU1F",
481 DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
485 .callback = video_detect_force_native,
486 .ident = "TongFang PF4NU1F",
488 DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
489 DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
493 .callback = video_detect_force_native,
494 .ident = "TongFang PF5NU1G",
496 DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
500 .callback = video_detect_force_native,
501 .ident = "TongFang PF5NU1G",
503 DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
504 DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
508 .callback = video_detect_force_native,
509 .ident = "TongFang PF5LUXG",
511 DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
515 * Desktops which falsely report a backlight and which our heuristics
516 * for this do not catch.
519 .callback = video_detect_force_none,
520 /* Dell OptiPlex 9020M */
522 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
523 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
527 .callback = video_detect_force_none,
530 DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
531 DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
538 * Determine which type of backlight interface to use on this system,
539 * First check cmdline, then dmi quirks, then do autodetect.
541 static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
543 static DEFINE_MUTEX(init_mutex);
544 static bool native_available;
545 static bool init_done;
546 static long video_caps;
548 /* Parse cmdline, dmi and acpi only once */
549 mutex_lock(&init_mutex);
551 acpi_video_parse_cmdline();
552 dmi_check_system(video_detect_dmi_table);
553 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
554 ACPI_UINT32_MAX, find_video, NULL,
559 native_available = true;
560 mutex_unlock(&init_mutex);
563 * The below heuristics / detection steps are in order of descending
564 * presedence. The commandline takes presedence over anything else.
566 if (acpi_backlight_cmdline != acpi_backlight_undef)
567 return acpi_backlight_cmdline;
569 /* DMI quirks override any autodetection. */
570 if (acpi_backlight_dmi != acpi_backlight_undef)
571 return acpi_backlight_dmi;
573 /* On systems with ACPI video use either native or ACPI video. */
574 if (video_caps & ACPI_VIDEO_BACKLIGHT) {
576 * Windows 8 and newer no longer use the ACPI video interface,
577 * so it often does not work. If the ACPI tables are written
578 * for win8 and native brightness ctl is available, use that.
580 * The native check deliberately is inside the if acpi-video
581 * block on older devices without acpi-video support native
582 * is usually not the best choice.
584 if (acpi_osi_is_win8() && native_available)
585 return acpi_backlight_native;
587 return acpi_backlight_video;
590 /* No ACPI video (old hw), use vendor specific fw methods. */
591 return acpi_backlight_vendor;
594 enum acpi_backlight_type acpi_video_get_backlight_type(void)
596 return __acpi_video_get_backlight_type(false);
598 EXPORT_SYMBOL(acpi_video_get_backlight_type);
600 bool acpi_video_backlight_use_native(void)
602 return __acpi_video_get_backlight_type(true) == acpi_backlight_native;
604 EXPORT_SYMBOL(acpi_video_backlight_use_native);
607 * Set the preferred backlight interface type based on DMI info.
608 * This function allows DMI blacklists to be implemented by external
609 * platform drivers instead of putting a big blacklist in video_detect.c
611 void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
613 acpi_backlight_dmi = type;
614 /* Remove acpi-video backlight interface if it is no longer desired */
615 if (acpi_video_get_backlight_type() != acpi_backlight_video)
616 acpi_video_unregister_backlight();
618 EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);