cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

video_detect.c (16970B)


      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
     21 * which driver should handle the backlight.
     22 *
     23 * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
     24 * this file will not be compiled and acpi_video_get_backlight_type() will
     25 * always return acpi_backlight_vendor.
     26 */
     27
     28#include <linux/export.h>
     29#include <linux/acpi.h>
     30#include <linux/backlight.h>
     31#include <linux/dmi.h>
     32#include <linux/module.h>
     33#include <linux/pci.h>
     34#include <linux/types.h>
     35#include <linux/workqueue.h>
     36#include <acpi/video.h>
     37
     38void acpi_video_unregister_backlight(void);
     39
     40static bool backlight_notifier_registered;
     41static struct notifier_block backlight_nb;
     42static struct work_struct backlight_notify_work;
     43
     44static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
     45static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
     46
     47static void acpi_video_parse_cmdline(void)
     48{
     49	if (!strcmp("vendor", acpi_video_backlight_string))
     50		acpi_backlight_cmdline = acpi_backlight_vendor;
     51	if (!strcmp("video", acpi_video_backlight_string))
     52		acpi_backlight_cmdline = acpi_backlight_video;
     53	if (!strcmp("native", acpi_video_backlight_string))
     54		acpi_backlight_cmdline = acpi_backlight_native;
     55	if (!strcmp("none", acpi_video_backlight_string))
     56		acpi_backlight_cmdline = acpi_backlight_none;
     57}
     58
     59static acpi_status
     60find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
     61{
     62	struct acpi_device *acpi_dev = acpi_fetch_acpi_dev(handle);
     63	long *cap = context;
     64	struct pci_dev *dev;
     65
     66	static const struct acpi_device_id video_ids[] = {
     67		{ACPI_VIDEO_HID, 0},
     68		{"", 0},
     69	};
     70
     71	if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) {
     72		dev = acpi_get_pci_dev(handle);
     73		if (!dev)
     74			return AE_OK;
     75		pci_dev_put(dev);
     76		*cap |= acpi_is_video_device(handle);
     77	}
     78	return AE_OK;
     79}
     80
     81/* Force to use vendor driver when the ACPI device is known to be
     82 * buggy */
     83static int video_detect_force_vendor(const struct dmi_system_id *d)
     84{
     85	acpi_backlight_dmi = acpi_backlight_vendor;
     86	return 0;
     87}
     88
     89static int video_detect_force_video(const struct dmi_system_id *d)
     90{
     91	acpi_backlight_dmi = acpi_backlight_video;
     92	return 0;
     93}
     94
     95static int video_detect_force_native(const struct dmi_system_id *d)
     96{
     97	acpi_backlight_dmi = acpi_backlight_native;
     98	return 0;
     99}
    100
    101static int video_detect_force_none(const struct dmi_system_id *d)
    102{
    103	acpi_backlight_dmi = acpi_backlight_none;
    104	return 0;
    105}
    106
    107static const struct dmi_system_id video_detect_dmi_table[] = {
    108	/* On Samsung X360, the BIOS will set a flag (VDRV) if generic
    109	 * ACPI backlight device is used. This flag will definitively break
    110	 * the backlight interface (even the vendor interface) until next
    111	 * reboot. It's why we should prevent video.ko from being used here
    112	 * and we can't rely on a later call to acpi_video_unregister().
    113	 */
    114	{
    115	 .callback = video_detect_force_vendor,
    116	 /* X360 */
    117	 .matches = {
    118		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    119		DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
    120		DMI_MATCH(DMI_BOARD_NAME, "X360"),
    121		},
    122	},
    123	{
    124	.callback = video_detect_force_vendor,
    125	/* Asus UL30VT */
    126	.matches = {
    127		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    128		DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
    129		},
    130	},
    131	{
    132	.callback = video_detect_force_vendor,
    133	/* Asus UL30A */
    134	.matches = {
    135		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
    136		DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
    137		},
    138	},
    139	{
    140	.callback = video_detect_force_vendor,
    141	/* GIGABYTE GB-BXBT-2807 */
    142	.matches = {
    143		DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
    144		DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
    145		},
    146	},
    147	{
    148	.callback = video_detect_force_vendor,
    149	/* Sony VPCEH3U1E */
    150	.matches = {
    151		DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
    152		DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
    153		},
    154	},
    155	{
    156	.callback = video_detect_force_vendor,
    157	/* Xiaomi Mi Pad 2 */
    158	.matches = {
    159			DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
    160			DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
    161		},
    162	},
    163
    164	/*
    165	 * These models have a working acpi_video backlight control, and using
    166	 * native backlight causes a regression where backlight does not work
    167	 * when userspace is not handling brightness key events. Disable
    168	 * native_backlight on these to fix this:
    169	 * https://bugzilla.kernel.org/show_bug.cgi?id=81691
    170	 */
    171	{
    172	 .callback = video_detect_force_video,
    173	 /* ThinkPad T420 */
    174	 .matches = {
    175		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    176		DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
    177		},
    178	},
    179	{
    180	 .callback = video_detect_force_video,
    181	 /* ThinkPad T520 */
    182	 .matches = {
    183		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    184		DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
    185		},
    186	},
    187	{
    188	 .callback = video_detect_force_video,
    189	 /* ThinkPad X201s */
    190	 .matches = {
    191		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    192		DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
    193		},
    194	},
    195	{
    196	 .callback = video_detect_force_video,
    197	 /* ThinkPad X201T */
    198	 .matches = {
    199		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    200		DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201T"),
    201		},
    202	},
    203
    204	/* The native backlight controls do not work on some older machines */
    205	{
    206	 /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
    207	 .callback = video_detect_force_video,
    208	 /* HP ENVY 15 Notebook */
    209	 .matches = {
    210		DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
    211		DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
    212		},
    213	},
    214	{
    215	 .callback = video_detect_force_video,
    216	 /* SAMSUNG 870Z5E/880Z5E/680Z5E */
    217	 .matches = {
    218		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    219		DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
    220		},
    221	},
    222	{
    223	 .callback = video_detect_force_video,
    224	 /* SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V */
    225	 .matches = {
    226		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    227		DMI_MATCH(DMI_PRODUCT_NAME,
    228			  "370R4E/370R4V/370R5E/3570RE/370R5V"),
    229		},
    230	},
    231	{
    232	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
    233	 .callback = video_detect_force_video,
    234	 /* SAMSUNG 3570R/370R/470R/450R/510R/4450RV */
    235	 .matches = {
    236		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    237		DMI_MATCH(DMI_PRODUCT_NAME,
    238			  "3570R/370R/470R/450R/510R/4450RV"),
    239		},
    240	},
    241	{
    242	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
    243	 .callback = video_detect_force_video,
    244	 /* SAMSUNG 670Z5E */
    245	 .matches = {
    246		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    247		DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
    248		},
    249	},
    250	{
    251	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
    252	 .callback = video_detect_force_video,
    253	 /* SAMSUNG 730U3E/740U3E */
    254	 .matches = {
    255		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    256		DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
    257		},
    258	},
    259	{
    260	 /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
    261	 .callback = video_detect_force_video,
    262	 /* SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D */
    263	 .matches = {
    264		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    265		DMI_MATCH(DMI_PRODUCT_NAME,
    266			  "900X3C/900X3D/900X3E/900X4C/900X4D"),
    267		},
    268	},
    269	{
    270	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */
    271	 .callback = video_detect_force_video,
    272	 /* Dell XPS14 L421X */
    273	 .matches = {
    274		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    275		DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
    276		},
    277	},
    278	{
    279	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
    280	 .callback = video_detect_force_video,
    281	 /* Dell XPS15 L521X */
    282	 .matches = {
    283		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    284		DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
    285		},
    286	},
    287	{
    288	 /* https://bugzilla.kernel.org/show_bug.cgi?id=108971 */
    289	 .callback = video_detect_force_video,
    290	 /* SAMSUNG 530U4E/540U4E */
    291	 .matches = {
    292		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
    293		DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
    294		},
    295	},
    296	/* https://bugs.launchpad.net/bugs/1894667 */
    297	{
    298	 .callback = video_detect_force_video,
    299	 /* HP 635 Notebook */
    300	 .matches = {
    301		DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
    302		DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
    303		},
    304	},
    305
    306	/* Non win8 machines which need native backlight nevertheless */
    307	{
    308	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1201530 */
    309	 .callback = video_detect_force_native,
    310	 /* Lenovo Ideapad S405 */
    311	 .matches = {
    312		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    313		DMI_MATCH(DMI_BOARD_NAME, "Lenovo IdeaPad S405"),
    314		},
    315	},
    316	{
    317	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
    318	 .callback = video_detect_force_native,
    319	 /* Lenovo Ideapad Z570 */
    320	 .matches = {
    321		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    322		DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
    323		},
    324	},
    325	{
    326	 .callback = video_detect_force_native,
    327	 /* Lenovo E41-25 */
    328	 .matches = {
    329		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    330		DMI_MATCH(DMI_PRODUCT_NAME, "81FS"),
    331		},
    332	},
    333	{
    334	 .callback = video_detect_force_native,
    335	 /* Lenovo E41-45 */
    336	 .matches = {
    337		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
    338		DMI_MATCH(DMI_PRODUCT_NAME, "82BK"),
    339		},
    340	},
    341	{
    342	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
    343	 .callback = video_detect_force_native,
    344	 /* Apple MacBook Pro 12,1 */
    345	 .matches = {
    346		DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
    347		DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
    348		},
    349	},
    350	{
    351	 .callback = video_detect_force_native,
    352	 /* Dell Vostro V131 */
    353	 .matches = {
    354		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    355		DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
    356		},
    357	},
    358	{
    359	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
    360	 .callback = video_detect_force_native,
    361	 /* Dell XPS 17 L702X */
    362	 .matches = {
    363		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    364		DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
    365		},
    366	},
    367	{
    368	 .callback = video_detect_force_native,
    369	 /* Dell Precision 7510 */
    370	 .matches = {
    371		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    372		DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"),
    373		},
    374	},
    375	{
    376	 .callback = video_detect_force_native,
    377	 /* Acer Aspire 5738z */
    378	 .matches = {
    379		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
    380		DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5738"),
    381		DMI_MATCH(DMI_BOARD_NAME, "JV50"),
    382		},
    383	},
    384	{
    385	 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
    386	 .callback = video_detect_force_native,
    387	 /* Acer TravelMate 5735Z */
    388	 .matches = {
    389		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
    390		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
    391		DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
    392		},
    393	},
    394	{
    395	.callback = video_detect_force_native,
    396	/* ASUSTeK COMPUTER INC. GA401 */
    397	.matches = {
    398		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    399		DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
    400		},
    401	},
    402	{
    403	.callback = video_detect_force_native,
    404	/* ASUSTeK COMPUTER INC. GA502 */
    405	.matches = {
    406		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    407		DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
    408		},
    409	},
    410	{
    411	.callback = video_detect_force_native,
    412	/* ASUSTeK COMPUTER INC. GA503 */
    413	.matches = {
    414		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
    415		DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
    416		},
    417	},
    418	/*
    419	 * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
    420	 * working native and video interface. However the default detection
    421	 * mechanism first registers the video interface before unregistering
    422	 * it again and switching to the native interface during boot. This
    423	 * results in a dangling SBIOS request for backlight change for some
    424	 * reason, causing the backlight to switch to ~2% once per boot on the
    425	 * first power cord connect or disconnect event. Setting the native
    426	 * interface explicitly circumvents this buggy behaviour, by avoiding
    427	 * the unregistering process.
    428	 */
    429	{
    430	.callback = video_detect_force_native,
    431	.ident = "Clevo NL5xRU",
    432	.matches = {
    433		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
    434		DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
    435		},
    436	},
    437	{
    438	.callback = video_detect_force_native,
    439	.ident = "Clevo NL5xRU",
    440	.matches = {
    441		DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
    442		DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
    443		},
    444	},
    445	{
    446	.callback = video_detect_force_native,
    447	.ident = "Clevo NL5xRU",
    448	.matches = {
    449		DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
    450		DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
    451		},
    452	},
    453	{
    454	.callback = video_detect_force_native,
    455	.ident = "Clevo NL5xRU",
    456	.matches = {
    457		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
    458		DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
    459		},
    460	},
    461	{
    462	.callback = video_detect_force_native,
    463	.ident = "Clevo NL5xRU",
    464	.matches = {
    465		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
    466		DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
    467		},
    468	},
    469	{
    470	.callback = video_detect_force_native,
    471	.ident = "Clevo NL5xNU",
    472	.matches = {
    473		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
    474		DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
    475		},
    476	},
    477	{
    478	.callback = video_detect_force_native,
    479	.ident = "Clevo NL5xNU",
    480	.matches = {
    481		DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
    482		DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
    483		},
    484	},
    485	{
    486	.callback = video_detect_force_native,
    487	.ident = "Clevo NL5xNU",
    488	.matches = {
    489		DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
    490		DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
    491		},
    492	},
    493
    494	/*
    495	 * Desktops which falsely report a backlight and which our heuristics
    496	 * for this do not catch.
    497	 */
    498	{
    499	 .callback = video_detect_force_none,
    500	 /* Dell OptiPlex 9020M */
    501	 .matches = {
    502		DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
    503		DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"),
    504		},
    505	},
    506	{
    507	 .callback = video_detect_force_none,
    508	 /* MSI MS-7721 */
    509	 .matches = {
    510		DMI_MATCH(DMI_SYS_VENDOR, "MSI"),
    511		DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"),
    512		},
    513	},
    514	{ },
    515};
    516
    517/* This uses a workqueue to avoid various locking ordering issues */
    518static void acpi_video_backlight_notify_work(struct work_struct *work)
    519{
    520	if (acpi_video_get_backlight_type() != acpi_backlight_video)
    521		acpi_video_unregister_backlight();
    522}
    523
    524static int acpi_video_backlight_notify(struct notifier_block *nb,
    525				       unsigned long val, void *bd)
    526{
    527	struct backlight_device *backlight = bd;
    528
    529	/* A raw bl registering may change video -> native */
    530	if (backlight->props.type == BACKLIGHT_RAW &&
    531	    val == BACKLIGHT_REGISTERED)
    532		schedule_work(&backlight_notify_work);
    533
    534	return NOTIFY_OK;
    535}
    536
    537/*
    538 * Determine which type of backlight interface to use on this system,
    539 * First check cmdline, then dmi quirks, then do autodetect.
    540 *
    541 * The autodetect order is:
    542 * 1) Is the acpi-video backlight interface supported ->
    543 *  no, use a vendor interface
    544 * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
    545 *  yes, use a native interface
    546 * 3) Else use the acpi-video interface
    547 *
    548 * Arguably the native on win8 check should be done first, but that would
    549 * be a behavior change, which may causes issues.
    550 */
    551enum acpi_backlight_type acpi_video_get_backlight_type(void)
    552{
    553	static DEFINE_MUTEX(init_mutex);
    554	static bool init_done;
    555	static long video_caps;
    556
    557	/* Parse cmdline, dmi and acpi only once */
    558	mutex_lock(&init_mutex);
    559	if (!init_done) {
    560		acpi_video_parse_cmdline();
    561		dmi_check_system(video_detect_dmi_table);
    562		acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
    563				    ACPI_UINT32_MAX, find_video, NULL,
    564				    &video_caps, NULL);
    565		INIT_WORK(&backlight_notify_work,
    566			  acpi_video_backlight_notify_work);
    567		backlight_nb.notifier_call = acpi_video_backlight_notify;
    568		backlight_nb.priority = 0;
    569		if (backlight_register_notifier(&backlight_nb) == 0)
    570			backlight_notifier_registered = true;
    571		init_done = true;
    572	}
    573	mutex_unlock(&init_mutex);
    574
    575	if (acpi_backlight_cmdline != acpi_backlight_undef)
    576		return acpi_backlight_cmdline;
    577
    578	if (acpi_backlight_dmi != acpi_backlight_undef)
    579		return acpi_backlight_dmi;
    580
    581	if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
    582		return acpi_backlight_vendor;
    583
    584	if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW))
    585		return acpi_backlight_native;
    586
    587	return acpi_backlight_video;
    588}
    589EXPORT_SYMBOL(acpi_video_get_backlight_type);
    590
    591/*
    592 * Set the preferred backlight interface type based on DMI info.
    593 * This function allows DMI blacklists to be implemented by external
    594 * platform drivers instead of putting a big blacklist in video_detect.c
    595 */
    596void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
    597{
    598	acpi_backlight_dmi = type;
    599	/* Remove acpi-video backlight interface if it is no longer desired */
    600	if (acpi_video_get_backlight_type() != acpi_backlight_video)
    601		acpi_video_unregister_backlight();
    602}
    603EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
    604
    605void __exit acpi_video_detect_exit(void)
    606{
    607	if (backlight_notifier_registered)
    608		backlight_unregister_notifier(&backlight_nb);
    609}