Unverified Commit 3f1a3a28 authored by Maxime Ripard's avatar Maxime Ripard
Browse files

Merge tag 'backlight-detect-refactor-1' of...

Merge tag 'backlight-detect-refactor-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

 into drm-misc-next

Immutable backlight-detect-refactor branch between acpi, drm-* and pdx86

Tag (immutable branch) with v6.0-rc1 + the (acpi/x86) backlight
detect refactor work. For merging into the acpi, drm-* and pdx86
subsystems.

Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmMVsogUHGhkZWdvZWRl
# QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9yy6wgAlig+7hkq940L62lTpj0g2gNQv8zc
# HCsMpnU7dnJcZYaEvIjouZhf33ZbN52c0fQq2JWjt7fFX04LLyIiyrJ26Lc293JR
# ++yXpJcVoewRGqApy/P3Z05TKUCLll5bexvK4t8isnhOtEXD/nDPWKTLIV2Kd1DK
# nLY4KgRznXZ85RhYheUEdidZ7Lwlzt1JVBMq7tpnzu3nVdDExyZmqlqCUITcLynu
# ysuASQGr0D2i+1vb9eifHIA3xsQO0S37Bv62aBMBKxB6B8Fz1DYr8VA2YvoT82Hv
# IFT0hzCCZ/63Ljga05O78TwraxAQX0RvZWqjqGgnZg6fIBh2hxUiqeQY6g==
# =SA1R
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 05 Sep 2022 09:25:44 AM IST
# gpg:                using RSA key BAF03B5D2718411A5E9E177E92EC4779440327DC
# gpg:                issuer "hdegoede@redhat.com"
# gpg: Can't check signature: No public key
From: Hans de Goede <hdegoede@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/261afe3d-7790-e945-adf6-a2c96c9b1eff@redhat.com
parents a108772d 4f96b1bc
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -679,6 +679,74 @@ Contact: Sam Ravnborg

Level: Advanced

Brightness handling on devices with multiple internal panels
============================================================

On x86/ACPI devices there can be multiple backlight firmware interfaces:
(ACPI) video, vendor specific and others. As well as direct/native (PWM)
register programming by the KMS driver.

To deal with this backlight drivers used on x86/ACPI call
acpi_video_get_backlight_type() which has heuristics (+quirks) to select
which backlight interface to use; and backlight drivers which do not match
the returned type will not register themselves, so that only one backlight
device gets registered (in a single GPU setup, see below).

At the moment this more or less assumes that there will only
be 1 (internal) panel on a system.

On systems with 2 panels this may be a problem, depending on
what interface acpi_video_get_backlight_type() selects:

1. native: in this case the KMS driver is expected to know which backlight
   device belongs to which output so everything should just work.
2. video: this does support controlling multiple backlights, but some work
   will need to be done to get the output <-> backlight device mapping

The above assumes both panels will require the same backlight interface type.
Things will break on systems with multiple panels where the 2 panels need
a different type of control. E.g. one panel needs ACPI video backlight control,
where as the other is using native backlight control. Currently in this case
only one of the 2 required backlight devices will get registered, based on
the acpi_video_get_backlight_type() return value.

If this (theoretical) case ever shows up, then supporting this will need some
work. A possible solution here would be to pass a device and connector-name
to acpi_video_get_backlight_type() so that it can deal with this.

Note in a way we already have a case where userspace sees 2 panels,
in dual GPU laptop setups with a mux. On those systems we may see
either 2 native backlight devices; or 2 native backlight devices.

Userspace already has code to deal with this by detecting if the related
panel is active (iow which way the mux between the GPU and the panels
points) and then uses that backlight device. Userspace here very much
assumes a single panel though. It picks only 1 of the 2 backlight devices
and then only uses that one.

Note that all userspace code (that I know off) is currently hardcoded
to assume a single panel.

Before the recent changes to not register multiple (e.g. video + native)
/sys/class/backlight devices for a single panel (on a single GPU laptop),
userspace would see multiple backlight devices all controlling the same
backlight.

To deal with this userspace had to always picks one preferred device under
/sys/class/backlight and will ignore the others. So to support brightness
control on multiple panels userspace will need to be updated too.

There are plans to allow brightness control through the KMS API by adding
a "display brightness" property to drm_connector objects for panels. This
solves a number of issues with the /sys/class/backlight API, including not
being able to map a sysfs backlight device to a specific connector. Any
userspace changes to add support for brightness control on devices with
multiple panels really should build on top of this new KMS property.

Contact: Hans de Goede

Level: Advanced

Outside DRM
===========

+1 −0
Original line number Diff line number Diff line
@@ -14532,6 +14532,7 @@ M: Daniel Dadap <ddadap@nvidia.com>
L:	platform-driver-x86@vger.kernel.org
S:	Supported
F:	drivers/platform/x86/nvidia-wmi-ec-backlight.c
F:	include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
NVM EXPRESS DRIVER
M:	Keith Busch <kbusch@kernel.org>
+1 −0
Original line number Diff line number Diff line
@@ -212,6 +212,7 @@ config ACPI_VIDEO
	tristate "Video"
	depends on BACKLIGHT_CLASS_DEVICE
	depends on INPUT
	depends on ACPI_WMI || !X86
	select THERMAL
	help
	  This driver implements the ACPI Extensions For Display Adapters
+46 −18
Original line number Diff line number Diff line
@@ -73,6 +73,16 @@ module_param(device_id_scheme, bool, 0444);
static int only_lcd = -1;
module_param(only_lcd, int, 0444);

/*
 * Display probing is known to take up to 5 seconds, so delay the fallback
 * backlight registration by 5 seconds + 3 seconds for some extra margin.
 */
static int register_backlight_delay = 8;
module_param(register_backlight_delay, int, 0444);
MODULE_PARM_DESC(register_backlight_delay,
	"Delay in seconds before doing fallback (non GPU driver triggered) "
	"backlight registration, set to 0 to disable.");

static bool may_report_brightness_keys;
static int register_count;
static DEFINE_MUTEX(register_count_mutex);
@@ -81,7 +91,9 @@ static LIST_HEAD(video_bus_head);
static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
void acpi_video_detect_exit(void);
static void acpi_video_bus_register_backlight_work(struct work_struct *ignored);
static DECLARE_DELAYED_WORK(video_bus_register_backlight_work,
			    acpi_video_bus_register_backlight_work);

/*
 * Indices in the _BCL method response: the first two items are special,
@@ -1859,8 +1871,6 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
	if (video->backlight_registered)
		return 0;

	acpi_video_run_bcl_for_osi(video);

	if (acpi_video_get_backlight_type() != acpi_backlight_video)
		return 0;

@@ -2086,7 +2096,11 @@ static int acpi_video_bus_add(struct acpi_device *device)
	list_add_tail(&video->entry, &video_bus_head);
	mutex_unlock(&video_list_lock);

	acpi_video_bus_register_backlight(video);
	/*
	 * The userspace visible backlight_device gets registered separately
	 * from acpi_video_register_backlight().
	 */
	acpi_video_run_bcl_for_osi(video);
	acpi_video_bus_add_notify_handler(video);

	return 0;
@@ -2111,20 +2125,25 @@ static int acpi_video_bus_remove(struct acpi_device *device)

	video = acpi_driver_data(device);

	acpi_video_bus_remove_notify_handler(video);
	acpi_video_bus_unregister_backlight(video);
	acpi_video_bus_put_devices(video);

	mutex_lock(&video_list_lock);
	list_del(&video->entry);
	mutex_unlock(&video_list_lock);

	acpi_video_bus_remove_notify_handler(video);
	acpi_video_bus_unregister_backlight(video);
	acpi_video_bus_put_devices(video);

	kfree(video->attached_array);
	kfree(video);

	return 0;
}

static void acpi_video_bus_register_backlight_work(struct work_struct *ignored)
{
	acpi_video_register_backlight();
}

static int __init is_i740(struct pci_dev *dev)
{
	if (dev->device == 0x00D1)
@@ -2235,6 +2254,18 @@ int acpi_video_register(void)
	 */
	register_count = 1;

	/*
	 * acpi_video_bus_add() skips registering the userspace visible
	 * backlight_device. The intend is for this to be registered by the
	 * drm/kms driver calling acpi_video_register_backlight() *after* it is
	 * done setting up its own native backlight device. The delayed work
	 * ensures that acpi_video_register_backlight() always gets called
	 * eventually, in case there is no drm/kms driver or it is disabled.
	 */
	if (register_backlight_delay)
		schedule_delayed_work(&video_bus_register_backlight_work,
				      register_backlight_delay * HZ);

leave:
	mutex_unlock(&register_count_mutex);
	return ret;
@@ -2245,6 +2276,7 @@ void acpi_video_unregister(void)
{
	mutex_lock(&register_count_mutex);
	if (register_count) {
		cancel_delayed_work_sync(&video_bus_register_backlight_work);
		acpi_bus_unregister_driver(&acpi_video_bus);
		register_count = 0;
		may_report_brightness_keys = false;
@@ -2253,19 +2285,16 @@ void acpi_video_unregister(void)
}
EXPORT_SYMBOL(acpi_video_unregister);

void acpi_video_unregister_backlight(void)
void acpi_video_register_backlight(void)
{
	struct acpi_video_bus *video;

	mutex_lock(&register_count_mutex);
	if (register_count) {
	mutex_lock(&video_list_lock);
	list_for_each_entry(video, &video_bus_head, entry)
			acpi_video_bus_unregister_backlight(video);
		acpi_video_bus_register_backlight(video);
	mutex_unlock(&video_list_lock);
}
	mutex_unlock(&register_count_mutex);
}
EXPORT_SYMBOL(acpi_video_register_backlight);

bool acpi_video_handles_brightness_key_presses(void)
{
@@ -2302,7 +2331,6 @@ static int __init acpi_video_init(void)

static void __exit acpi_video_exit(void)
{
	acpi_video_detect_exit();
	acpi_video_unregister();
}

+254 −174
Original line number Diff line number Diff line
@@ -17,8 +17,9 @@
 * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
 * sony_acpi,... can take care about backlight brightness.
 *
 * Backlight drivers can use acpi_video_get_backlight_type() to determine
 * which driver should handle the backlight.
 * Backlight drivers can use acpi_video_get_backlight_type() to determine which
 * driver should handle the backlight. RAW/GPU-driver backlight drivers must
 * use the acpi_video_backlight_use_native() helper for this.
 *
 * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
 * this file will not be compiled and acpi_video_get_backlight_type() will
@@ -27,20 +28,16 @@

#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/apple-gmux.h>
#include <linux/backlight.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <acpi/video.h>

void acpi_video_unregister_backlight(void);

static bool backlight_notifier_registered;
static struct notifier_block backlight_nb;
static struct work_struct backlight_notify_work;

static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;

@@ -78,6 +75,36 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
	return AE_OK;
}

/* This depends on ACPI_WMI which is X86 only */
#ifdef CONFIG_X86
static bool nvidia_wmi_ec_supported(void)
{
	struct wmi_brightness_args args = {
		.mode = WMI_BRIGHTNESS_MODE_GET,
		.val = 0,
		.ret = 0,
	};
	struct acpi_buffer buf = { (acpi_size)sizeof(args), &args };
	acpi_status status;

	status = wmi_evaluate_method(WMI_BRIGHTNESS_GUID, 0,
				     WMI_BRIGHTNESS_METHOD_SOURCE, &buf, &buf);
	if (ACPI_FAILURE(status))
		return false;

	/*
	 * If brightness is handled by the EC then nvidia-wmi-ec-backlight
	 * should be used, else the GPU driver(s) should be used.
	 */
	return args.ret == WMI_BRIGHTNESS_SOURCE_EC;
}
#else
static bool nvidia_wmi_ec_supported(void)
{
	return false;
}
#endif

/* Force to use vendor driver when the ACPI device is known to be
 * buggy */
static int video_detect_force_vendor(const struct dmi_system_id *d)
@@ -105,19 +132,13 @@ static int video_detect_force_none(const struct dmi_system_id *d)
}

static const struct dmi_system_id video_detect_dmi_table[] = {
	/* On Samsung X360, the BIOS will set a flag (VDRV) if generic
	 * ACPI backlight device is used. This flag will definitively break
	 * the backlight interface (even the vendor interface) until next
	 * reboot. It's why we should prevent video.ko from being used here
	 * and we can't rely on a later call to acpi_video_unregister().
	 */
	{
	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */
	 .callback = video_detect_force_vendor,
	 /* X360 */
	 /* Acer KAV80 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
		DMI_MATCH(DMI_BOARD_NAME, "X360"),
		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
		},
	},
	{
@@ -136,6 +157,46 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
		DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Asus X55U */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Asus X101CH */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Asus X401U */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Asus X501U */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Asus 1015CX */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* GIGABYTE GB-BXBT-2807 */
@@ -144,6 +205,33 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
		DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Samsung N150/N210/N220 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
		DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Samsung NF110/NF210/NF310 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
		DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Samsung NC210 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
		DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 /* Sony VPCEH3U1E */
@@ -161,6 +249,25 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
		},
	},

	/*
	 * Toshiba models with Transflective display, these need to use
	 * the toshiba_acpi vendor driver for proper Transflective handling.
	 */
	{
	 .callback = video_detect_force_vendor,
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
		DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"),
		},
	},
	{
	 .callback = video_detect_force_vendor,
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
		DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"),
		},
	},

	/*
	 * These models have a working acpi_video backlight control, and using
	 * native backlight causes a regression where backlight does not work
@@ -390,130 +497,119 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
		},
	},
	{
	 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
	 .callback = video_detect_force_native,
	 /* Acer TravelMate 5735Z */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
		DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
		},
	},
	{
	 /* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */
	 .callback = video_detect_force_native,
	/* ASUSTeK COMPUTER INC. GA401 */
	 /* Acer Aspire 5741 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
		DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
		},
	},
	{
	 /* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */
	 .callback = video_detect_force_native,
	/* ASUSTeK COMPUTER INC. GA502 */
	 /* Acer Aspire 5750 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
		DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
		},
	},
	{
	 /* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */
	 .callback = video_detect_force_native,
	/* ASUSTeK COMPUTER INC. GA503 */
	 /* Acer Extensa 5235 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
		DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
		},
	},
	/*
	 * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
	 * working native and video interface. However the default detection
	 * mechanism first registers the video interface before unregistering
	 * it again and switching to the native interface during boot. This
	 * results in a dangling SBIOS request for backlight change for some
	 * reason, causing the backlight to switch to ~2% once per boot on the
	 * first power cord connect or disconnect event. Setting the native
	 * interface explicitly circumvents this buggy behaviour, by avoiding
	 * the unregistering process.
	 */
	{
	 .callback = video_detect_force_native,
	.ident = "Clevo NL5xRU",
	 /* Acer TravelMate 4750 */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
		DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
		},
	},
	{
	 /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
	 .callback = video_detect_force_native,
	.ident = "Clevo NL5xRU",
	 /* Acer TravelMate 5735Z */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
		DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
		DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"),
		DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"),
		},
	},
	{
	 /* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */
	 .callback = video_detect_force_native,
	.ident = "Clevo NL5xRU",
	 /* Acer TravelMate 5760 */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
		DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
		DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
		DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "Clevo NL5xNU",
	 /* ASUSTeK COMPUTER INC. GA401 */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
		},
	},
	/*
	 * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
	 * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
	 * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
	 * above.
	 */
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF5PU1G",
	 /* ASUSTeK COMPUTER INC. GA502 */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF4NU1F",
	 /* ASUSTeK COMPUTER INC. GA503 */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF4NU1F",
	 /* Asus UX303UB */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
		DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
		DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
		DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF5NU1G",
	 /* Samsung N150P */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
		DMI_MATCH(DMI_BOARD_NAME, "N150P"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF5NU1G",
	 /* Samsung N145P/N250P/N260P */
	 .matches = {
		DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
		DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
		DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
		},
	},
	{
	 .callback = video_detect_force_native,
	.ident = "TongFang PF5LUXG",
	 /* Samsung N250P */
	 .matches = {
		DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
		DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
		DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
		DMI_MATCH(DMI_BOARD_NAME, "N250P"),
		},
	},

	/*
	 * Desktops which falsely report a backlight and which our heuristics
	 * for this do not catch.
@@ -537,43 +633,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
	{ },
};

/* This uses a workqueue to avoid various locking ordering issues */
static void acpi_video_backlight_notify_work(struct work_struct *work)
{
	if (acpi_video_get_backlight_type() != acpi_backlight_video)
		acpi_video_unregister_backlight();
}

static int acpi_video_backlight_notify(struct notifier_block *nb,
				       unsigned long val, void *bd)
{
	struct backlight_device *backlight = bd;

	/* A raw bl registering may change video -> native */
	if (backlight->props.type == BACKLIGHT_RAW &&
	    val == BACKLIGHT_REGISTERED)
		schedule_work(&backlight_notify_work);

	return NOTIFY_OK;
}

/*
 * Determine which type of backlight interface to use on this system,
 * First check cmdline, then dmi quirks, then do autodetect.
 *
 * The autodetect order is:
 * 1) Is the acpi-video backlight interface supported ->
 *  no, use a vendor interface
 * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
 *  yes, use a native interface
 * 3) Else use the acpi-video interface
 *
 * Arguably the native on win8 check should be done first, but that would
 * be a behavior change, which may causes issues.
 */
enum acpi_backlight_type acpi_video_get_backlight_type(void)
static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
{
	static DEFINE_MUTEX(init_mutex);
	static bool nvidia_wmi_ec_present;
	static bool native_available;
	static bool init_done;
	static long video_caps;

@@ -585,48 +653,60 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void)
		acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
				    ACPI_UINT32_MAX, find_video, NULL,
				    &video_caps, NULL);
		INIT_WORK(&backlight_notify_work,
			  acpi_video_backlight_notify_work);
		backlight_nb.notifier_call = acpi_video_backlight_notify;
		backlight_nb.priority = 0;
		if (backlight_register_notifier(&backlight_nb) == 0)
			backlight_notifier_registered = true;
		nvidia_wmi_ec_present = nvidia_wmi_ec_supported();
		init_done = true;
	}
	if (native)
		native_available = true;
	mutex_unlock(&init_mutex);

	/*
	 * The below heuristics / detection steps are in order of descending
	 * presedence. The commandline takes presedence over anything else.
	 */
	if (acpi_backlight_cmdline != acpi_backlight_undef)
		return acpi_backlight_cmdline;

	/* DMI quirks override any autodetection. */
	if (acpi_backlight_dmi != acpi_backlight_undef)
		return acpi_backlight_dmi;

	if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
		return acpi_backlight_vendor;
	/* Special cases such as nvidia_wmi_ec and apple gmux. */
	if (nvidia_wmi_ec_present)
		return acpi_backlight_nvidia_wmi_ec;

	if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW))
		return acpi_backlight_native;
	if (apple_gmux_present())
		return acpi_backlight_apple_gmux;

	/* On systems with ACPI video use either native or ACPI video. */
	if (video_caps & ACPI_VIDEO_BACKLIGHT) {
		/*
		 * Windows 8 and newer no longer use the ACPI video interface,
		 * so it often does not work. If the ACPI tables are written
		 * for win8 and native brightness ctl is available, use that.
		 *
		 * The native check deliberately is inside the if acpi-video
		 * block on older devices without acpi-video support native
		 * is usually not the best choice.
		 */
		if (acpi_osi_is_win8() && native_available)
			return acpi_backlight_native;
		else
			return acpi_backlight_video;
	}
EXPORT_SYMBOL(acpi_video_get_backlight_type);

/*
 * Set the preferred backlight interface type based on DMI info.
 * This function allows DMI blacklists to be implemented by external
 * platform drivers instead of putting a big blacklist in video_detect.c
 */
void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
	/* No ACPI video (old hw), use vendor specific fw methods. */
	return acpi_backlight_vendor;
}

enum acpi_backlight_type acpi_video_get_backlight_type(void)
{
	acpi_backlight_dmi = type;
	/* Remove acpi-video backlight interface if it is no longer desired */
	if (acpi_video_get_backlight_type() != acpi_backlight_video)
		acpi_video_unregister_backlight();
	return __acpi_video_get_backlight_type(false);
}
EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
EXPORT_SYMBOL(acpi_video_get_backlight_type);

void __exit acpi_video_detect_exit(void)
bool acpi_video_backlight_use_native(void)
{
	if (backlight_notifier_registered)
		backlight_unregister_notifier(&backlight_nb);
	return __acpi_video_get_backlight_type(true) == acpi_backlight_native;
}
EXPORT_SYMBOL(acpi_video_backlight_use_native);
Loading