asus-wmi: add scalar board brightness adj. support

Some ASUS ET2012E/I All-in-One machines that use a scalar board
to control the brightness, and they only accept brightness up and down
command. So, I introduced a get_scalar_command() function to pass the
command to the scalar board through WMI.

Besides, we have to store the brightness value locally, for we need the
old value to know the brightness value is increasing or decreasing.

BTW, since there is no way to retrieve the actual brightness(it would be
a fixed value), and the max brightness value would be fixed to 1, so we
have to keep passing the brightness up/down command when we reached the
max brightness value or 0.

Signed-off-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Corentin Chary <corentin.chary@gmail.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 1d91eb2..67186e6 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -48,6 +48,7 @@
 
 MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID);
 
+static struct quirk_entry *quirks;
 static bool hotplug_wireless;
 
 module_param(hotplug_wireless, bool, 0444);
@@ -90,6 +91,60 @@
 	{ KE_END, 0},
 };
 
+static struct quirk_entry quirk_asus_unknown = {
+};
+
+static struct quirk_entry quirk_asus_1000h = {
+	.hotplug_wireless = true,
+};
+
+static struct quirk_entry quirk_asus_et2012_type3 = {
+	.scalar_panel_brightness = true,
+};
+
+static int dmi_matched(const struct dmi_system_id *dmi)
+{
+	char *model;
+	quirks = dmi->driver_data;
+
+	model = (char *)dmi->matches[1].substr;
+	if (unlikely(strncmp(model, "ET2012", 6) == 0)) {
+		const struct dmi_device *dev = NULL;
+		char oemstring[30];
+		while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL,
+					      dev))) {
+			if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
+				if (oemstring[18] == '3')
+					quirks = &quirk_asus_et2012_type3;
+				break;
+			}
+		}
+	}
+	return 1;
+}
+
+static struct dmi_system_id asus_quirks[] = {
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK Computer INC. 1000H",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
+		},
+		.driver_data = &quirk_asus_1000h,
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "ASUSTeK Computer INC. ET2012E/I",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
+		},
+		.driver_data = &quirk_asus_unknown,
+	},
+	{},
+};
+
 static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
 				 unsigned int *value, bool *autorelease)
 {
@@ -144,33 +199,13 @@
 	return 0;
 }
 
-static void eeepc_dmi_check(struct asus_wmi_driver *driver)
-{
-	const char *model;
-
-	model = dmi_get_system_info(DMI_PRODUCT_NAME);
-	if (!model)
-		return;
-
-	/*
-	 * Whitelist for wlan hotplug
-	 *
-	 * Asus 1000H needs the current hotplug code to handle
-	 * Fn+F2 correctly. We may add other Asus here later, but
-	 * it seems that most of the laptops supported by asus-wmi
-	 * don't need to be on this list
-	 */
-	if (strcmp(model, "1000H") == 0) {
-		driver->hotplug_wireless = true;
-		pr_info("wlan hotplug enabled\n");
-	}
-}
-
 static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
 {
-	driver->hotplug_wireless = hotplug_wireless;
 	driver->wapf = -1;
-	eeepc_dmi_check(driver);
+	driver->quirks = &quirk_asus_unknown;
+	driver->quirks->hotplug_wireless = hotplug_wireless;
+	dmi_check_system(asus_quirks);
+	driver->quirks = quirks;
 }
 
 static struct asus_wmi_driver asus_wmi_driver = {
@@ -182,7 +217,7 @@
 	.input_phys = EEEPC_WMI_FILE "/input0",
 	.key_filter = eeepc_wmi_key_filter,
 	.probe = eeepc_wmi_probe,
-	.quirks = eeepc_wmi_quirks,
+	.detect_quirks = eeepc_wmi_quirks,
 };