linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 0/9] platform/x86: Huawei WMI laptop extras driver
@ 2019-07-31 17:52 Ayman Bagabas
  2019-07-31 17:52 ` [RFC 2/9] platform/x86: huawei-wmi: Move to platform driver Ayman Bagabas
                   ` (8 more replies)
  0 siblings, 9 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

This patch series introduce changes to huawei-wmi driver that includes:
* Move to platform driver
* Implement WMI management interface
* Add micmute LED support through WMI
* Add battery charging protection support through WMI
* Add fn-lock support through WMI
* Implement driver quirks and parameters
* Add a debugfs interface to WMI

# Move to platform driver

The current driver offers hotkeys and micmute led support only. With
these changes, a platform driver makes more sense since it handles these
changes pretty nicely.

# Implement WMI management interface

Huawei Matebook laptops come with two WMI interfaces. The first being
WMI0 which is considered "legacy" and AFAIK only found on the Matebook X
released in 2017. The second has a UID of "HWMI" and is found in pretty
much all models with a slight difference in implementation except for
the Matebook X (2017). Since this model has two interfaces, some aspects
are controlled through the legacy interface and some through the other
interface. Currently, the legacy interface is not fully implemented and
is only used for hotkeys and further debugging has to be done.

The WMI interface takes a 64 bit integer, although uses 32 bits most of
the time, and returns a 256-260 bytes buffer consists of either one ACPI
buffer of 260 bytes, in the case of Matebook X (2017), or one ACPI
package of two buffers, one with 4 bytes, and the other with 256 bytes.
We only care about the latter 256 buffer in both cases since the 4 bytes
always return zeros. The first byte of this 256 buffer always has the
return status where 1 indicated error. Some models require calling the
WMI interface twice to execute a command.

# Add micmute LED support through WMI

After implementing the WMI interface, micmute LED can be controlled
easily. Models with the legacy interface fall back to ACPI EC method
control since the legacy interface is not implemented.

# Add battery charging protection support through WMI

Most models, that has the WMI interface, are capable of battery
protection where it can control battery charging thresholds and limits
charging the battery to certain values.

# Add fn-lock support through WMI

The behavior of hotkeys is not the same among all models. Some models
require fn-lock to do things like `Ctrl-Ins` or `Alt-PrtSc`. By default,
hotkeys behave as special keys (media keys, Ins, etc), but if a modifier
is used (ctrl, alt, shift) these keys behave as F1-F12 keys. If the Fn
key is toggled on, the hotkeys with or without a modifier, behave as
F1-F12 keys. This makes it impossible to use a modifier and `PrtSc` or
`Ins`.

Now, some models fix this by excluding `PrtSc` and `Ins` keys from being
treated as F11 and F12 keys with the use of a modifier. However, some
models do not, and fixes this by the so called fn-lock.

Fn-lock inverts the behavior of the top row from special keys to F1-F12
keys. So a modifier and a special key would be possible which make
things like `Alt-Ins` possible. Now, with fn-lock we would have 4 modes:

* Fn-key off & fn-lock off - hotkeys treated as special keys using a
  modifier gives F1-F12 keys.
* Fn-key on & fn-lock off - hotkeys treated as F1-F12 keys and using a
  modifier gives F1-F12.
* Fn-key off & fn-lock on - hotkeys are treated as F1-F12 keys and using
  a modifier gives special keys.
* Fn-key on & fn-lock on - hotkeys are treated as special keys and using
  a modifier gives special keys.

# Implement driver quirks and parameters

The driver introduces 3 quirks and 2 parameters that can change the
driver's behavior. These quirks being as:
1. Fixes reporting brightness keys twice since it's already handled by
   acpi-video.
2. Some models need a short delay when setting battery thresholds to
   prevent a race condition when two processes read/write.
3. Matebook X (2017) handles micmute led through the "legacy" interface
   which is not currently implemented. Use ACPI EC method to control
   this led.

and the 2 parameters can enforce the behavior of quirk 1 & 2.

# Add a debugfs interface to WMI

An interface to the WMI management interface that allows easier
debugging.

Ayman Bagabas (9):
  platform/x86: huawei-wmi: rename guid and driver name
  platform/x86: huawei-wmi: move to platform driver
  platform/x86: huawei-wmi: implement huawei wmi management interface
  platform/x86: huawei-wmi: add quirks and module parameters
  platform/x86: huawei-wmi: control micmute led through wmi interface
  platform/x86: huawei-wmi: add battery charging thresholds
  platform/x86: huawei-wmi: add fn-lock support
  platform/x86: huawei-wmi: add sysfs interface support
  platform/x86: huawei-wmi: add debugfs support

 drivers/platform/x86/huawei-wmi.c | 710 ++++++++++++++++++++++++++----
 1 file changed, 629 insertions(+), 81 deletions(-)

-- 
2.20.1



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC 2/9] platform/x86: huawei-wmi: Move to platform driver
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 3/9] platform/x86: huawei-wmi: Implement huawei wmi management interface Ayman Bagabas
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Move from WMI driver to platform driver. This move is necessary since
the driver is no longer a hotkeys driver only. Platform driver makes it
easier for users to access sysfs attributes under (i.e.
/sys/devices/platform/huawei-wmi) compared to wmi driver.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
Do you think we should stick to wmi driver especially after
"platform/x86: wmi: add context pointer field to struct wmi_device_id"
https://patchwork.kernel.org/patch/10963421/ which is basically was my
issue with wmi driver where there wasn't a way to distinguish what wmi
device is associated with which guid.

I believe that platform driver is more suitable for this since it has
grown from just a hotkeys driver and users can access sysfs of this
easily with platform driver. What do you think?

 drivers/platform/x86/huawei-wmi.c | 152 +++++++++++++++++++++---------
 1 file changed, 110 insertions(+), 42 deletions(-)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index a1159850a16c..12cae450fc1f 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -10,6 +10,7 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/wmi.h>
 
 /*
@@ -23,12 +24,15 @@
 
 
 struct huawei_wmi_priv {
-	struct input_dev *idev;
+	struct input_dev *idev[2];
 	struct led_classdev cdev;
 	acpi_handle handle;
 	char *acpi_method;
+	struct platform_device *pdev;
 };
 
+struct platform_device *huawei_wmi_pdev;
+
 static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_KEY,    0x281, { KEY_BRIGHTNESSDOWN } },
 	{ KE_KEY,    0x282, { KEY_BRIGHTNESSUP } },
@@ -46,6 +50,8 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_END,	 0 }
 };
 
+/* LEDs */
+
 static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
 		enum led_brightness brightness)
 {
@@ -77,9 +83,9 @@ static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
 	return 0;
 }
 
-static int huawei_wmi_leds_setup(struct wmi_device *wdev)
+static int huawei_wmi_leds_setup(struct device *dev)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
 
 	priv->handle = ec_get_handle();
 	if (!priv->handle)
@@ -97,15 +103,16 @@ static int huawei_wmi_leds_setup(struct wmi_device *wdev)
 	priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
 	priv->cdev.default_trigger = "audio-micmute";
 	priv->cdev.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
-	priv->cdev.dev = &wdev->dev;
+	priv->cdev.dev = dev;
 	priv->cdev.flags = LED_CORE_SUSPENDRESUME;
 
-	return devm_led_classdev_register(&wdev->dev, &priv->cdev);
+	return devm_led_classdev_register(dev, &priv->cdev);
 }
 
-static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
+/* Input */
+
+static void huawei_wmi_process_key(struct input_dev *idev, int code)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
 	const struct key_entry *key;
 
 	/*
@@ -129,81 +136,142 @@ static void huawei_wmi_process_key(struct wmi_device *wdev, int code)
 		kfree(response.pointer);
 	}
 
-	key = sparse_keymap_entry_from_scancode(priv->idev, code);
+	key = sparse_keymap_entry_from_scancode(idev, code);
 	if (!key) {
-		dev_info(&wdev->dev, "Unknown key pressed, code: 0x%04x\n", code);
+		dev_info(&idev->dev, "Unknown key pressed, code: 0x%04x\n", code);
 		return;
 	}
 
-	sparse_keymap_report_entry(priv->idev, key, 1, true);
+	sparse_keymap_report_entry(idev, key, 1, true);
 }
 
-static void huawei_wmi_notify(struct wmi_device *wdev,
-		union acpi_object *obj)
+static void huawei_wmi_input_notify(u32 value, void *context)
 {
-	if (obj->type == ACPI_TYPE_INTEGER)
-		huawei_wmi_process_key(wdev, obj->integer.value);
+	struct input_dev *idev = (struct input_dev *)context;
+	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	status = wmi_get_event_data(value, &response);
+	if (ACPI_FAILURE(status)) {
+		dev_err(&idev->dev, "Unable to get event data\n");
+		return;
+	}
+
+	obj = (union acpi_object *)response.pointer;
+	if (obj && obj->type == ACPI_TYPE_INTEGER)
+		huawei_wmi_process_key(idev, obj->integer.value);
 	else
-		dev_info(&wdev->dev, "Bad response type %d\n", obj->type);
+		dev_err(&idev->dev, "Bad response type\n");
+
+	kfree(response.pointer);
 }
 
-static int huawei_wmi_input_setup(struct wmi_device *wdev)
+static int huawei_wmi_input_setup(struct device *dev,
+		struct input_dev **idev)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
 	int err;
 
-	priv->idev = devm_input_allocate_device(&wdev->dev);
-	if (!priv->idev)
+	*idev = devm_input_allocate_device(dev);
+	if (!*idev)
 		return -ENOMEM;
 
-	priv->idev->name = "Huawei WMI hotkeys";
-	priv->idev->phys = "wmi/input0";
-	priv->idev->id.bustype = BUS_HOST;
-	priv->idev->dev.parent = &wdev->dev;
+	(*idev)->name = "Huawei WMI hotkeys";
+	(*idev)->phys = "wmi/input0";
+	(*idev)->id.bustype = BUS_HOST;
+	(*idev)->dev.parent = dev;
 
-	err = sparse_keymap_setup(priv->idev, huawei_wmi_keymap, NULL);
+	err = sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL);
 	if (err)
 		return err;
 
-	return input_register_device(priv->idev);
+	return input_register_device(*idev);
 }
 
-static int huawei_wmi_probe(struct wmi_device *wdev, const void *context)
+/* Huawei driver */
+
+static int huawei_wmi_probe(struct platform_device *pdev)
 {
 	struct huawei_wmi_priv *priv;
 	int err;
 
-	priv = devm_kzalloc(&wdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
+	priv = devm_kzalloc(&pdev->dev, sizeof(struct huawei_wmi_priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	dev_set_drvdata(&wdev->dev, priv);
+	priv->pdev = pdev;
+	dev_set_drvdata(&pdev->dev, priv);
+
+	if (wmi_has_guid(WMI0_EVENT_GUID)) {
+		err = huawei_wmi_input_setup(&pdev->dev, &priv->idev[0]) ||
+				wmi_install_notify_handler(WMI0_EVENT_GUID,
+					huawei_wmi_input_notify, priv->idev[0]);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to setup input device\n");
+			return err;
+		}
+	}
 
-	err = huawei_wmi_input_setup(wdev);
-	if (err)
-		return err;
+	if (wmi_has_guid(HWMI_EVENT_GUID)) {
+		err = huawei_wmi_input_setup(&pdev->dev, &priv->idev[1]) ||
+				wmi_install_notify_handler(HWMI_EVENT_GUID,
+					huawei_wmi_input_notify, priv->idev[1]);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to setup input device\n");
+			return err;
+		}
+	}
 
-	return huawei_wmi_leds_setup(wdev);
+	return huawei_wmi_leds_setup(&pdev->dev);
 }
 
-static const struct wmi_device_id huawei_wmi_id_table[] = {
-	{ .guid_string = WMI0_EVENT_GUID },
-	{ .guid_string = HWMI_EVENT_GUID },
-	{  }
-};
+static int huawei_wmi_remove(struct platform_device *pdev)
+{
+	if (wmi_has_guid(WMI0_EVENT_GUID))
+		wmi_remove_notify_handler(WMI0_EVENT_GUID);
+
+	if (wmi_has_guid(HWMI_EVENT_GUID))
+		wmi_remove_notify_handler(HWMI_EVENT_GUID);
 
-static struct wmi_driver huawei_wmi_driver = {
+	return 0;
+}
+
+static struct platform_driver huawei_wmi_driver = {
 	.driver = {
 		.name = "huawei-wmi",
 	},
-	.id_table = huawei_wmi_id_table,
 	.probe = huawei_wmi_probe,
-	.notify = huawei_wmi_notify,
+	.remove = huawei_wmi_remove,
 };
 
-module_wmi_driver(huawei_wmi_driver);
+static __init int huawei_wmi_init(void)
+{
+	int err;
+
+	err = platform_driver_register(&huawei_wmi_driver);
+	if (err)
+		return err;
+
+	huawei_wmi_pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
+	if (IS_ERR(huawei_wmi_pdev)) {
+		platform_driver_unregister(&huawei_wmi_driver);
+		return PTR_ERR(huawei_wmi_pdev);
+	}
+
+	return 0;
+}
+
+static __exit void huawei_wmi_exit(void)
+{
+	platform_device_unregister(huawei_wmi_pdev);
+	platform_driver_unregister(&huawei_wmi_driver);
+}
+
+module_init(huawei_wmi_init);
+module_exit(huawei_wmi_exit);
 
-MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table);
+MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
+MODULE_ALIAS("wmi:"HWMI_EVENT_GUID);
 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
 MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
 MODULE_LICENSE("GPL v2");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 3/9] platform/x86: huawei-wmi: Implement huawei wmi management interface
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
  2019-07-31 17:52 ` [RFC 2/9] platform/x86: huawei-wmi: Move to platform driver Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 4/9] platform/x86: huawei-wmi: Add quirks and module parameters Ayman Bagabas
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Huawei Matebook laptops come with a WMI management interface that can
control various aspects of the device. This interface is also found on
the old Matebook X released in 2017.

Implement basic functionality of this interface along with supported
command IDs that are implemented in this series.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 130 ++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 12cae450fc1f..27520b0f8956 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -10,24 +10,36 @@
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/wmi.h>
 
 /*
  * Huawei WMI GUIDs
  */
+#define HWMI_METHOD_GUID "ABBC0F5B-8EA1-11D1-A000-C90629100000"
 #define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
 
 /* Legacy GUIDs */
 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
 #define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
 
+/* HWMI commands */
+
+enum {
+	BATTERY_THRESH_GET		= 0x00001103, /* \GBTT */
+	BATTERY_THRESH_SET		= 0x00001003, /* \SBTT */
+	FN_LOCK_GET			= 0x00000604, /* \GFRS */
+	FN_LOCK_SET			= 0x00000704, /* \SFRS */
+	MICMUTE_LED_SET			= 0x00000b04, /* \SMLS */
+};
 
 struct huawei_wmi_priv {
 	struct input_dev *idev[2];
 	struct led_classdev cdev;
 	acpi_handle handle;
 	char *acpi_method;
+	struct mutex wmi_lock;
 	struct platform_device *pdev;
 };
 
@@ -50,6 +62,116 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_END,	 0 }
 };
 
+/* Utils */
+
+static int huawei_wmi_call(struct device *dev, struct acpi_buffer *in,
+		struct acpi_buffer *out)
+{
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
+	acpi_status status;
+
+	mutex_lock(&priv->wmi_lock);
+	status = wmi_evaluate_method(HWMI_METHOD_GUID, 0, 1, in, out);
+	mutex_unlock(&priv->wmi_lock);
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Failed to evaluate wmi method\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* HWMI takes a 64 bit input and returns either a package with 2 buffers, one of
+ * 4 bytes and the other of 256 bytes, or one buffer of size 0x104 (260) bytes.
+ * The first 4 bytes are ignored, we ignore the first 4 bytes buffer if we got a
+ * package, or skip the first 4 if a buffer of 0x104 is used. The first byte of
+ * the remaining 0x100 sized buffer has the return status of every call. In case
+ * the return status is non-zero, we return -ENODEV but still copy the returned
+ * buffer to the given buffer parameter (buf).
+ */
+static int huawei_wmi_cmd(struct device *dev, u64 arg, u8 *buf, size_t buflen)
+{
+	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer in;
+	union acpi_object *obj;
+	size_t len;
+	int err, i;
+
+	in.length = sizeof(arg);
+	in.pointer = &arg;
+
+	/* Some models require calling HWMI twice to execute a command. We evaluate
+	 * HWMI and if we get a non-zero return status we evaluate it again.
+	 */
+	for (i = 0; i < 2; i++) {
+		err = huawei_wmi_call(dev,  &in, &out);
+		if (err)
+			goto fail_cmd;
+
+		obj = out.pointer;
+		if (!obj) {
+			err = -EIO;
+			goto fail_cmd;
+		}
+
+		switch (obj->type) {
+		/* Models that implement both "legacy" and HWMI tend to return a 0x104
+		 * sized buffer instead of a package of 0x4 and 0x100 buffers.
+		 */
+		case ACPI_TYPE_BUFFER:
+			if (obj->buffer.length == 0x104) {
+				// Skip the first 4 bytes.
+				obj->buffer.pointer += 4;
+				len = 0x100;
+			} else {
+				dev_err(dev, "Bad buffer length, got %d\n", obj->buffer.length);
+				err = -EIO;
+				goto fail_cmd;
+			}
+
+			break;
+		/* HWMI returns a package with 2 buffer elements, one of 4 bytes and the
+		 * other is 256 bytes.
+		 */
+		case ACPI_TYPE_PACKAGE:
+			if (obj->package.count != 2) {
+				dev_err(dev, "Bad package count, got %d\n", obj->package.count);
+				err = -EIO;
+				goto fail_cmd;
+			}
+
+			obj = &obj->package.elements[1];
+			if (obj->type != ACPI_TYPE_BUFFER) {
+				dev_err(dev, "Bad package element type, got %d\n", obj->type);
+				err = -EIO;
+				goto fail_cmd;
+			}
+			len = obj->buffer.length;
+
+			break;
+		/* Shouldn't get here! */
+		default:
+			dev_err(dev, "Unexpected obj type, got: %d\n", obj->type);
+			err = -EIO;
+			goto fail_cmd;
+		}
+
+		if (!*obj->buffer.pointer)
+			break;
+	}
+
+	err = (*obj->buffer.pointer) ? -ENODEV : 0;
+
+	if (buf) {
+		len = min(buflen, len);
+		memcpy(buf, obj->buffer.pointer, len);
+	}
+
+fail_cmd:
+	kfree(out.pointer);
+	return err;
+}
+
 /* LEDs */
 
 static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
@@ -222,6 +344,10 @@ static int huawei_wmi_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (wmi_has_guid(HWMI_METHOD_GUID)) {
+		mutex_init(&priv->wmi_lock);
+	}
+
 	return huawei_wmi_leds_setup(&pdev->dev);
 }
 
@@ -233,6 +359,9 @@ static int huawei_wmi_remove(struct platform_device *pdev)
 	if (wmi_has_guid(HWMI_EVENT_GUID))
 		wmi_remove_notify_handler(HWMI_EVENT_GUID);
 
+	if (wmi_has_guid(HWMI_METHOD_GUID)) {
+	}
+
 	return 0;
 }
 
@@ -272,6 +401,7 @@ module_exit(huawei_wmi_exit);
 
 MODULE_ALIAS("wmi:"WMI0_EVENT_GUID);
 MODULE_ALIAS("wmi:"HWMI_EVENT_GUID);
+MODULE_ALIAS("wmi:"HWMI_METHOD_GUID);
 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
 MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
 MODULE_LICENSE("GPL v2");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 4/9] platform/x86: huawei-wmi: Add quirks and module parameters
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
  2019-07-31 17:52 ` [RFC 2/9] platform/x86: huawei-wmi: Move to platform driver Ayman Bagabas
  2019-07-31 17:52 ` [RFC 3/9] platform/x86: huawei-wmi: Implement huawei wmi management interface Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 5/9] platform/x86: huawei-wmi: Control micmute led through wmi interface Ayman Bagabas
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Introduce quirks and module parameters. 3 quirks are added:
1. Fixes reporting brightness keys twice since it's already handled by
   acpi-video.
2. Some models need a short delay when setting battery thresholds to
   prevent a race condition when two processes read/write.
3. Matebook X (2017) handles micmute led through the "legacy" interface
   which is not currently implemented. Use ACPI EC method to control
   this led.

2 module parameters are added to enable this short delay and/or report
  brightness keys through this driver.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 71 +++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 27520b0f8956..8f918138053a 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/leds.h>
@@ -34,6 +35,14 @@ enum {
 	MICMUTE_LED_SET			= 0x00000b04, /* \SMLS */
 };
 
+struct quirk_entry {
+	bool battery_sleep;
+	bool ec_micmute;
+	bool report_brightness;
+};
+
+static struct quirk_entry *quirks;
+
 struct huawei_wmi_priv {
 	struct input_dev *idev[2];
 	struct led_classdev cdev;
@@ -62,6 +71,58 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_END,	 0 }
 };
 
+static bool battery_sleep;
+static bool report_brightness;
+
+module_param(battery_sleep, bool, 0444);
+MODULE_PARM_DESC(battery_sleep,
+		"Delay after setting battery charging thresholds.");
+module_param(report_brightness, bool, 0444);
+MODULE_PARM_DESC(report_brightness,
+		"Report brightness keys.");
+
+/* Quirks */
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
+{
+	quirks = dmi->driver_data;
+	return 1;
+}
+
+static struct quirk_entry quirk_unknown = {
+};
+
+static struct quirk_entry quirk_battery_sleep = {
+	.battery_sleep = true,
+};
+
+static struct quirk_entry quirk_matebook_x = {
+	.ec_micmute = true,
+	.report_brightness = true,
+};
+
+static const struct dmi_system_id huawei_quirks[] = {
+	{
+		.callback = dmi_matched,
+		.ident = "Huawei MACH-WX9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MACH-WX9"),
+		},
+		.driver_data = &quirk_battery_sleep
+	},
+	{
+		.callback = dmi_matched,
+		.ident = "Huawei MateBook X",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "HUAWEI"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HUAWEI MateBook X")
+		},
+		.driver_data = &quirk_matebook_x
+	},
+	{  }
+};
+
 /* Utils */
 
 static int huawei_wmi_call(struct device *dev, struct acpi_buffer *in,
@@ -264,6 +325,11 @@ static void huawei_wmi_process_key(struct input_dev *idev, int code)
 		return;
 	}
 
+	if (quirks && !quirks->report_brightness &&
+			(key->sw.code == KEY_BRIGHTNESSDOWN ||
+			key->sw.code == KEY_BRIGHTNESSUP))
+		return;
+
 	sparse_keymap_report_entry(idev, key, 1, true);
 }
 
@@ -377,6 +443,11 @@ static __init int huawei_wmi_init(void)
 {
 	int err;
 
+	quirks = &quirk_unknown;
+	dmi_check_system(huawei_quirks);
+	quirks->battery_sleep |= battery_sleep;
+	quirks->report_brightness |= report_brightness;
+
 	err = platform_driver_register(&huawei_wmi_driver);
 	if (err)
 		return err;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 5/9] platform/x86: huawei-wmi: Control micmute led through wmi interface
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (2 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 4/9] platform/x86: huawei-wmi: Add quirks and module parameters Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 6/9] platform/x86: huawei-wmi: Add battery charging thresholds Ayman Bagabas
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Now that huawei WMI management interface is implemented, micmute LED can
be controlled easily through this interface. Exception is the Matebook X
(2017) which continue to uses ACPI EC method to control the LED. This
model can control the LED through the legacy WMI interface which is not
implemented ATM.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 86 ++++++++++++++++++-------------
 1 file changed, 49 insertions(+), 37 deletions(-)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 8f918138053a..9013a05d2832 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -46,8 +46,6 @@ static struct quirk_entry *quirks;
 struct huawei_wmi_priv {
 	struct input_dev *idev[2];
 	struct led_classdev cdev;
-	acpi_handle handle;
-	char *acpi_method;
 	struct mutex wmi_lock;
 	struct platform_device *pdev;
 };
@@ -238,49 +236,57 @@ static int huawei_wmi_cmd(struct device *dev, u64 arg, u8 *buf, size_t buflen)
 static int huawei_wmi_micmute_led_set(struct led_classdev *led_cdev,
 		enum led_brightness brightness)
 {
-	struct huawei_wmi_priv *priv = dev_get_drvdata(led_cdev->dev->parent);
-	acpi_status status;
-	union acpi_object args[3];
-	struct acpi_object_list arg_list = {
-		.pointer = args,
-		.count = ARRAY_SIZE(args),
-	};
-
-	args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
-	args[1].integer.value = 0x04;
-
-	if (strcmp(priv->acpi_method, "SPIN") == 0) {
-		args[0].integer.value = 0;
-		args[2].integer.value = brightness ? 1 : 0;
-	} else if (strcmp(priv->acpi_method, "WPIN") == 0) {
-		args[0].integer.value = 1;
-		args[2].integer.value = brightness ? 0 : 1;
+	/* This is a workaround until the "legacy" interface is implemented. */
+	if (quirks && quirks->ec_micmute) {
+		char *acpi_method;
+		acpi_handle handle;
+		acpi_status status;
+		union acpi_object args[3];
+		struct acpi_object_list arg_list = {
+			.pointer = args,
+			.count = ARRAY_SIZE(args),
+		};
+
+		handle = ec_get_handle();
+		if (!handle) {
+			dev_err(led_cdev->dev->parent, "Failed to get EC handle\n");
+			return -ENODEV;
+		}
+
+		args[0].type = args[1].type = args[2].type = ACPI_TYPE_INTEGER;
+		args[1].integer.value = 0x04;
+
+		if (acpi_has_method(handle, "SPIN")) {
+			acpi_method = "SPIN";
+			args[0].integer.value = 0;
+			args[2].integer.value = brightness ? 1 : 0;
+		} else if (acpi_has_method(handle, "WPIN")) {
+			acpi_method = "WPIN";
+			args[0].integer.value = 1;
+			args[2].integer.value = brightness ? 0 : 1;
+		} else {
+			return -ENODEV;
+		}
+
+		status = acpi_evaluate_object(handle, acpi_method, &arg_list, NULL);
+		if (ACPI_FAILURE(status))
+			return -ENODEV;
+
+		return 0;
 	} else {
-		return -EINVAL;
-	}
+		u8 arg[8];
 
-	status = acpi_evaluate_object(priv->handle, priv->acpi_method, &arg_list, NULL);
-	if (ACPI_FAILURE(status))
-		return -ENXIO;
+		*(u64 *)arg = MICMUTE_LED_SET;
+		arg[2] = brightness;
 
-	return 0;
+		return huawei_wmi_cmd(led_cdev->dev->parent, *(u64 *)arg, NULL, NULL);
+	}
 }
 
 static int huawei_wmi_leds_setup(struct device *dev)
 {
 	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
 
-	priv->handle = ec_get_handle();
-	if (!priv->handle)
-		return 0;
-
-	if (acpi_has_method(priv->handle, "SPIN"))
-		priv->acpi_method = "SPIN";
-	else if (acpi_has_method(priv->handle, "WPIN"))
-		priv->acpi_method = "WPIN";
-	else
-		return 0;
-
 	priv->cdev.name = "platform::micmute";
 	priv->cdev.max_brightness = 1;
 	priv->cdev.brightness_set_blocking = huawei_wmi_micmute_led_set;
@@ -412,9 +418,15 @@ static int huawei_wmi_probe(struct platform_device *pdev)
 
 	if (wmi_has_guid(HWMI_METHOD_GUID)) {
 		mutex_init(&priv->wmi_lock);
+
+		err = huawei_wmi_leds_setup(&pdev->dev);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to setup leds\n");
+			return err;
+		}
 	}
 
-	return huawei_wmi_leds_setup(&pdev->dev);
+	return 0;
 }
 
 static int huawei_wmi_remove(struct platform_device *pdev)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 6/9] platform/x86: huawei-wmi: Add battery charging thresholds
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (3 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 5/9] platform/x86: huawei-wmi: Control micmute led through wmi interface Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 7/9] platform/x86: huawei-wmi: Add fn-lock support Ayman Bagabas
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Implement battery charging thresholds functionality to be used with
sysfs interface support that is implemented in this series.

Setting battery charging thresholds can introduce a race condition where
two are trying to read/write values from/to EC memory. Even though a
mutex is used, this doesn't guarantee that these values will make it to
EC so a blocking sleep is necessary.

This sleep is enforced on the MACH-WX9 model since turning off battery
protection using (0,100) doesn't change the values in the EC memory,
instead it only disables the protection. So a workaround is to set the
thresholds to (0,0) before setting it to (0,100). This will ensure
that we update these values in EC memory and then turning it off with
(0,100). Thus, the msleep(1000).

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
In huawei_wmi_battery_get and later in huawei_wmi_fn_lock_get, 256 bytes
buffer is allocated dynamically on the stack. Now I know this is
discouraged, should it be changed to use kmalloc?

 drivers/platform/x86/huawei-wmi.c | 54 +++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 9013a05d2832..da3986cd0428 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
@@ -46,6 +47,7 @@ static struct quirk_entry *quirks;
 struct huawei_wmi_priv {
 	struct input_dev *idev[2];
 	struct led_classdev cdev;
+	struct mutex battery_lock;
 	struct mutex wmi_lock;
 	struct platform_device *pdev;
 };
@@ -298,6 +300,57 @@ static int huawei_wmi_leds_setup(struct device *dev)
 	return devm_led_classdev_register(dev, &priv->cdev);
 }
 
+/* Battery protection */
+
+static int huawei_wmi_battery_get(struct device *dev, int *low, int *high)
+{
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
+	u8 ret[0x100];
+	int err, i;
+
+	mutex_lock(&priv->battery_lock);
+	err = huawei_wmi_cmd(dev, BATTERY_THRESH_GET, ret, 0x100);
+	mutex_unlock(&priv->battery_lock);
+	if (err)
+		return err;
+
+	/* Find the last two non-zero values. Return status is ignored. */
+	i = 0x100;
+	do {
+		*low = ret[i-1];
+		*high = ret[i];
+	} while (i > 2 && !ret[i--]);
+
+	return 0;
+}
+
+static int huawei_wmi_battery_set(struct device *dev, int low, int high)
+{
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
+	u8 arg[8];
+	int err;
+
+	*(u64 *)arg = BATTERY_THRESH_SET;
+	arg[2] = low;
+	arg[3] = high;
+
+	/* This is an edge case were some models turn battery protection
+	 * off without changing their thresholds values. We clear the
+	 * values before turning off protection. Sometimes we need a sleep delay to
+	 * make sure these values make their way to EC memory.
+	 */
+	if (low == 0 && high == 100)
+		huawei_wmi_battery_set(dev, 0, 0);
+
+	mutex_lock(&priv->battery_lock);
+	err = huawei_wmi_cmd(dev, *(u64 *)arg, NULL, NULL);
+	if (quirks && quirks->battery_sleep)
+		msleep(1000);
+	mutex_unlock(&priv->battery_lock);
+
+	return err;
+}
+
 /* Input */
 
 static void huawei_wmi_process_key(struct input_dev *idev, int code)
@@ -418,6 +471,7 @@ static int huawei_wmi_probe(struct platform_device *pdev)
 
 	if (wmi_has_guid(HWMI_METHOD_GUID)) {
 		mutex_init(&priv->wmi_lock);
+		mutex_init(&priv->battery_lock);
 
 		err = huawei_wmi_leds_setup(&pdev->dev);
 		if (err) {
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 7/9] platform/x86: huawei-wmi: Add fn-lock support
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (4 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 6/9] platform/x86: huawei-wmi: Add battery charging thresholds Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 8/9] platform/x86: huawei-wmi: Add sysfs interface support Ayman Bagabas
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Huawei Matebook laptops uses Fn key and toggle to access F1-F12 keys.
Along with that, there is this feature called fn-lock that inverts the
behavior of this Fn key.

Implement the basic functionality of this feature to be used later by
sysfs interface support introduced in this series.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index da3986cd0428..4159e10bda26 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -351,6 +351,36 @@ static int huawei_wmi_battery_set(struct device *dev, int low, int high)
 	return err;
 }
 
+/* Fn lock */
+
+static int huawei_wmi_fn_lock_get(struct device *dev, int *on)
+{
+	u8 ret[0x100] = { 0 };
+	int err, i;
+
+	err = huawei_wmi_cmd(dev, FN_LOCK_GET, ret, 0x100);
+	if (err)
+		return err;
+
+	/* Find the first non-zero value. Return status is ignored. */
+	i = 1;
+	do {
+		*on = ret[i] - 1; // -1 undefined, 0 off, 1 on.
+	} while (i < 0x100 && !ret[i++]);
+
+	return 0;
+}
+
+static int huawei_wmi_fn_lock_set(struct device *dev, int on)
+{
+	u8 arg[8];
+
+	*(u64 *)arg = FN_LOCK_SET;
+	arg[2] = on + 1; // 0 undefined, 1 off, 2 on.
+
+	return huawei_wmi_cmd(dev, *(u64 *)arg, NULL, NULL);
+}
+
 /* Input */
 
 static void huawei_wmi_process_key(struct input_dev *idev, int code)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 8/9] platform/x86: huawei-wmi: Add sysfs interface support
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (5 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 7/9] platform/x86: huawei-wmi: Add fn-lock support Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-07-31 17:52 ` [RFC 9/9] platform/x86: huawei-wmi: Add debugfs support Ayman Bagabas
  2019-08-01  0:21 ` [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name Ayman Bagabas
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Add sysfs interface to enable the use of battery charging thresholds and
fn-lock support introduced in this series.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 82 +++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 4159e10bda26..f7041fb71026 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/sysfs.h>
 #include <linux/wmi.h>
 
 /*
@@ -381,6 +382,80 @@ static int huawei_wmi_fn_lock_set(struct device *dev, int on)
 	return huawei_wmi_cmd(dev, *(u64 *)arg, NULL, NULL);
 }
 
+/* sysfs */
+
+static ssize_t charge_thresholds_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	int err, low, high;
+
+	err = huawei_wmi_battery_get(dev, &low, &high);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%d %d\n", low, high);
+}
+
+static ssize_t charge_thresholds_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t size)
+{
+	int low, high, err;
+
+	if (sscanf(buf, "%d %d", &low, &high) != 2 ||
+			low < 0 || high > 100 ||
+			low > high)
+		return -EINVAL;
+
+	err = huawei_wmi_battery_set(dev, low, high);
+	if (err)
+		return err;
+
+	return size;
+}
+
+static ssize_t fn_lock_state_show(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	int err, on;
+
+	err = huawei_wmi_fn_lock_get(dev, &on);
+	if (err)
+		return err;
+
+	return sprintf(buf, "%d\n", on);
+}
+
+static ssize_t fn_lock_state_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t size)
+{
+	int on, err;
+
+	if (kstrtoint(buf, 10, &on) ||
+			on < 0 || on > 1)
+		return -EINVAL;
+
+	err = huawei_wmi_fn_lock_set(dev, on);
+	if (err)
+		return err;
+
+	return size;
+}
+
+static DEVICE_ATTR_RW(charge_thresholds);
+static DEVICE_ATTR_RW(fn_lock_state);
+
+static struct attribute *huawei_wmi_attrs[] = {
+	&dev_attr_charge_thresholds.attr,
+	&dev_attr_fn_lock_state.attr,
+	NULL
+};
+
+ATTRIBUTE_GROUPS(huawei_wmi);
+
 /* Input */
 
 static void huawei_wmi_process_key(struct input_dev *idev, int code)
@@ -508,6 +583,12 @@ static int huawei_wmi_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "Failed to setup leds\n");
 			return err;
 		}
+
+		err = sysfs_create_groups(&pdev->dev.kobj, huawei_wmi_groups);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to create sysfs interface\n");
+			return err;
+		}
 	}
 
 	return 0;
@@ -522,6 +603,7 @@ static int huawei_wmi_remove(struct platform_device *pdev)
 		wmi_remove_notify_handler(HWMI_EVENT_GUID);
 
 	if (wmi_has_guid(HWMI_METHOD_GUID)) {
+		sysfs_remove_groups(&pdev->dev.kobj, huawei_wmi_groups);
 	}
 
 	return 0;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 9/9] platform/x86: huawei-wmi: Add debugfs support
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (6 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 8/9] platform/x86: huawei-wmi: Add sysfs interface support Ayman Bagabas
@ 2019-07-31 17:52 ` Ayman Bagabas
  2019-08-01  0:21 ` [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name Ayman Bagabas
  8 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 17:52 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Add a debugfs interface that can be used to call the WMI management
interface function.

The WMI interface takes a 64 bit integer and returns 256-260 bytes
buffer. This debugfs interface creates two files, one stores a 64 bit
int and the other calls the WMI interface and dumps out the returned
buffer.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 98 +++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index f7041fb71026..bdca8bd76c8c 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/dmi.h>
 #include <linux/input.h>
@@ -45,7 +46,13 @@ struct quirk_entry {
 
 static struct quirk_entry *quirks;
 
+struct huawei_wmi_debug {
+	struct dentry *root;
+	u64 arg;
+};
+
 struct huawei_wmi_priv {
+	struct huawei_wmi_debug debug;
 	struct input_dev *idev[2];
 	struct led_classdev cdev;
 	struct mutex battery_lock;
@@ -456,6 +463,94 @@ static struct attribute *huawei_wmi_attrs[] = {
 
 ATTRIBUTE_GROUPS(huawei_wmi);
 
+/* debugfs */
+
+static void huawei_wmi_debugfs_call_dump(struct seq_file *m, void *data,
+		union acpi_object *obj)
+{
+	struct huawei_wmi_priv *priv = m->private;
+	int i;
+
+	switch (obj->type) {
+	case ACPI_TYPE_INTEGER:
+		seq_printf(m, "0x%llx", obj->integer.value);
+		break;
+	case ACPI_TYPE_STRING:
+		seq_printf(m, "\"%*s\"", obj->string.length, obj->string.pointer);
+		break;
+	case ACPI_TYPE_BUFFER:
+		seq_puts(m, "{");
+		for (i = 0; i < obj->buffer.length; i++) {
+			seq_printf(m, "0x%02x", obj->buffer.pointer[i]);
+			if (i < obj->buffer.length - 1)
+				seq_puts(m, ",");
+		}
+		seq_puts(m, "}");
+		break;
+	case ACPI_TYPE_PACKAGE:
+		seq_puts(m, "[");
+		for (i = 0; i < obj->package.count; i++) {
+			huawei_wmi_debugfs_call_dump(m, priv, &obj->package.elements[i]);
+			if (i < obj->package.count - 1)
+				seq_puts(m, ",");
+		}
+		seq_puts(m, "]");
+		break;
+	default:
+		dev_err(&priv->pdev->dev, "Unexpected obj type, got %d\n", obj->type);
+		return;
+	}
+}
+
+static int huawei_wmi_debugfs_call_show(struct seq_file *m, void *data)
+{
+	struct huawei_wmi_priv *priv = m->private;
+	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer in;
+	union acpi_object *obj;
+	int err;
+
+	in.length = sizeof(u64);
+	in.pointer = &priv->debug.arg;
+
+	err = huawei_wmi_call(&priv->pdev->dev, &in, &out);
+	if (err)
+		return err;
+
+	obj = out.pointer;
+	if (!obj) {
+		err = -EIO;
+		goto fail_debugfs_call;
+	}
+
+	huawei_wmi_debugfs_call_dump(m, priv, obj);
+
+fail_debugfs_call:
+	kfree(out.pointer);
+	return err;
+}
+
+DEFINE_SHOW_ATTRIBUTE(huawei_wmi_debugfs_call);
+
+static void huawei_wmi_debugfs_exit(struct device *dev)
+{
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
+
+	debugfs_remove_recursive(priv->debug.root);
+}
+
+static void huawei_wmi_debugfs_setup(struct device *dev)
+{
+	struct huawei_wmi_priv *priv = dev_get_drvdata(dev);
+
+	priv->debug.root = debugfs_create_dir("huawei-wmi", NULL);
+
+	debugfs_create_x64("arg", 0644, priv->debug.root,
+		&priv->debug.arg);
+	debugfs_create_file("call", 0400,
+		priv->debug.root, priv, &huawei_wmi_debugfs_call_fops);
+}
+
 /* Input */
 
 static void huawei_wmi_process_key(struct input_dev *idev, int code)
@@ -589,6 +684,8 @@ static int huawei_wmi_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "Failed to create sysfs interface\n");
 			return err;
 		}
+
+		huawei_wmi_debugfs_setup(&pdev->dev);
 	}
 
 	return 0;
@@ -603,6 +700,7 @@ static int huawei_wmi_remove(struct platform_device *pdev)
 		wmi_remove_notify_handler(HWMI_EVENT_GUID);
 
 	if (wmi_has_guid(HWMI_METHOD_GUID)) {
+		huawei_wmi_debugfs_exit(&pdev->dev);
 		sysfs_remove_groups(&pdev->dev.kobj, huawei_wmi_groups);
 	}
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name
  2019-08-01  0:21 ` [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name Ayman Bagabas
@ 2019-07-31 18:06   ` Ayman Bagabas
  0 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31 18:06 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Use WMI device UID, AMW0 has a UID of HWMI. WMI0 is the device name
and doesn't have a UID so keep it as it is.

Change module description to reflect the upcoming changes.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 52fcac5b393a..a1159850a16c 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- *  Huawei WMI hotkeys
+ *  Huawei WMI laptop extras driver
  *
  *  Copyright (C) 2018	      Ayman Bagabas <ayman.bagabas@gmail.com>
  */
@@ -15,10 +15,12 @@
 /*
  * Huawei WMI GUIDs
  */
-#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
-#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+#define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
 
+/* Legacy GUIDs */
 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
+#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+
 
 struct huawei_wmi_priv {
 	struct input_dev *idev;
@@ -37,7 +39,7 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_KEY,    0x289, { KEY_WLAN } },
 	// Huawei |M| key
 	{ KE_KEY,    0x28a, { KEY_CONFIG } },
-	// Keyboard backlight
+	// Keyboard backlit
 	{ KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
 	{ KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
 	{ KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
@@ -186,7 +188,7 @@ static int huawei_wmi_probe(struct wmi_device *wdev)
 
 static const struct wmi_device_id huawei_wmi_id_table[] = {
 	{ .guid_string = WMI0_EVENT_GUID },
-	{ .guid_string = AMW0_EVENT_GUID },
+	{ .guid_string = HWMI_EVENT_GUID },
 	{  }
 };
 
@@ -203,5 +205,5 @@ module_wmi_driver(huawei_wmi_driver);
 
 MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table);
 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
-MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
 MODULE_LICENSE("GPL v2");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name
  2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
                   ` (7 preceding siblings ...)
  2019-07-31 17:52 ` [RFC 9/9] platform/x86: huawei-wmi: Add debugfs support Ayman Bagabas
@ 2019-08-01  0:21 ` Ayman Bagabas
  2019-07-31 18:06   ` Ayman Bagabas
  8 siblings, 1 reply; 15+ messages in thread
From: Ayman Bagabas @ 2019-08-01  0:21 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: Ayman Bagabas

Use WMI device UID, AMW0 has a UID of HWMI. WMI0 is the device name
and doesn't have a UID so keep it as it is.

Change module description to reflect the upcoming changes.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
---
 drivers/platform/x86/huawei-wmi.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 52fcac5b393a..a1159850a16c 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- *  Huawei WMI hotkeys
+ *  Huawei WMI laptop extras driver
  *
  *  Copyright (C) 2018	      Ayman Bagabas <ayman.bagabas@gmail.com>
  */
@@ -15,10 +15,12 @@
 /*
  * Huawei WMI GUIDs
  */
-#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
-#define AMW0_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
+#define HWMI_EVENT_GUID "ABBC0F5C-8EA1-11D1-A000-C90629100000"
 
+/* Legacy GUIDs */
 #define WMI0_EXPENSIVE_GUID "39142400-C6A3-40fa-BADB-8A2652834100"
+#define WMI0_EVENT_GUID "59142400-C6A3-40fa-BADB-8A2652834100"
+
 
 struct huawei_wmi_priv {
 	struct input_dev *idev;
@@ -37,7 +39,7 @@ static const struct key_entry huawei_wmi_keymap[] = {
 	{ KE_KEY,    0x289, { KEY_WLAN } },
 	// Huawei |M| key
 	{ KE_KEY,    0x28a, { KEY_CONFIG } },
-	// Keyboard backlight
+	// Keyboard backlit
 	{ KE_IGNORE, 0x293, { KEY_KBDILLUMTOGGLE } },
 	{ KE_IGNORE, 0x294, { KEY_KBDILLUMUP } },
 	{ KE_IGNORE, 0x295, { KEY_KBDILLUMUP } },
@@ -186,7 +188,7 @@ static int huawei_wmi_probe(struct wmi_device *wdev)
 
 static const struct wmi_device_id huawei_wmi_id_table[] = {
 	{ .guid_string = WMI0_EVENT_GUID },
-	{ .guid_string = AMW0_EVENT_GUID },
+	{ .guid_string = HWMI_EVENT_GUID },
 	{  }
 };
 
@@ -203,5 +205,5 @@ module_wmi_driver(huawei_wmi_driver);
 
 MODULE_DEVICE_TABLE(wmi, huawei_wmi_id_table);
 MODULE_AUTHOR("Ayman Bagabas <ayman.bagabas@gmail.com>");
-MODULE_DESCRIPTION("Huawei WMI hotkeys");
+MODULE_DESCRIPTION("Huawei WMI laptop extras driver");
 MODULE_LICENSE("GPL v2");
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC 0/9] platform/x86: Huawei WMI laptop extras driver
  2019-07-25 20:08   ` Ayman Bagabas
@ 2019-07-31  1:01     ` Ayman Bagabas
  0 siblings, 0 replies; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-31  1:01 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Darren Hart, Andy Shevchenko, Platform Driver, Linux Kernel Mailing List

On 19/07/25 04:05PM, Ayman Bagabas wrote:
> On 19/07/25 08:33PM, Andy Shevchenko wrote:
> > On Sun, Jun 30, 2019 at 8:41 AM Ayman Bagabas <ayman.bagabas@gmail.com> wrote:
> > >
> > > This patch series introduce changes to huawei-wmi driver that includes:
> > > * Move to platform driver
> > > * Implement WMI management interface
> > > * Add micmute LED support through WMI
> > > * Add battery charging protection support through WMI
> > > * Add fn-lock support through WMI
> > > * Implement driver quirks and parameters
> > > * Add a debugfs interface to WMI
> > >
> > > # Move to platform driver
> > >
> > > The current driver offers hotkeys and micmute led support only. With
> > > these changes, a platform driver makes more sense since it handles these
> > > changes pretty nicely.
> > >
> > > # Implement WMI management interface
> > >
> > > Huawei Matebook laptops come with two WMI interfaces. The first being
> > > WMI0 which is considered "legacy" and AFAIK only found on the Matebook X
> > > released in 2017. The second has a UID of "HWMI" and is found in pretty
> > > much all models with a slight difference in implementation except for
> > > the Matebook X (2017). Since this model has two interfaces, some aspects
> > > are controlled through the legacy interface and some through the other
> > > interface. Currently, the legacy interface is not fully implemented and
> > > is only used for hotkeys and further debugging has to be done.
> > >
> > > The WMI interface takes a 64 bit integer, although uses 32 bits most of
> > > the time, and returns a 256-260 bytes buffer consists of either one ACPI
> > > buffer of 260 bytes, in the case of Matebook X (2017), or one ACPI
> > > package of two buffers, one with 4 bytes, and the other with 256 bytes.
> > > We only care about the latter 256 buffer in both cases since the 4 bytes
> > > always return zeros. The first byte of this 256 buffer always has the
> > > return status where 1 indicated error. Some models require calling the
> > > WMI interface twice to execute a command.
> > >
> > > # Add micmute LED support through WMI
> > >
> > > After implementing the WMI interface, micmute LED can be controlled
> > > easily. Models with the legacy interface fall back to ACPI EC method
> > > control since the legacy interface is not implemented.
> > >
> > > # Add battery charging protection support through WMI
> > >
> > > Most models, that has the WMI interface, are capable of battery
> > > protection where it can control battery charging thresholds and limits
> > > charging the battery to certain values.
> > >
> > > # Add fn-lock support through WMI
> > >
> > > The behavior of hotkeys is not the same among all models. Some models
> > > require fn-lock to do things like `Ctrl-Ins` or `Alt-PrtSc`. By default,
> > > hotkeys behave as special keys (media keys, Ins, etc), but if a modifier
> > > is used (ctrl, alt, shift) these keys behave as F1-F12 keys. If the Fn
> > > key is toggled on, the hotkeys with or without a modifier, behave as
> > > F1-F12 keys. This makes it impossible to use a modifier and `PrtSc` or
> > > `Ins`.
> > >
> > > Now, some models fix this by excluding `PrtSc` and `Ins` keys from being
> > > treated as F11 and F12 keys with the use of a modifier. However, some
> > > models do not, and fixes this by the so called fn-lock.
> > >
> > > Fn-lock inverts the behavior of the top row from special keys to F1-F12
> > > keys. So a modifier and a special key would be possible which make
> > > things like `Alt-Ins` possible. Now, with fn-lock we would have 4 modes:
> > >
> > > * Fn-key off & fn-lock off - hotkeys treated as special keys using a
> > >   modifier gives F1-F12 keys.
> > > * Fn-key on & fn-lock off - hotkeys treated as F1-F12 keys and using a
> > >   modifier gives F1-F12.
> > > * Fn-key off & fn-lock on - hotkeys are treated as F1-F12 keys and using
> > >   a modifier gives special keys.
> > > * Fn-key on & fn-lock on - hotkeys are treated as special keys and using
> > >   a modifier gives special keys.
> > >
> > > # Implement driver quirks and parameters
> > >
> > > The driver introduces 3 quirks and 2 parameters that can change the
> > > driver's behavior. These quirks being as:
> > > 1. Fixes reporting brightness keys twice since it's already handled by
> > >    acpi-video.
> > > 2. Some models need a short delay when setting battery thresholds to
> > >    prevent a race condition when two processes read/write.
> > > 3. Matebook X (2017) handles micmute led through the "legacy" interface
> > >    which is not currently implemented. Use ACPI EC method to control
> > >    this led.
> > >
> > > and the 2 parameters can enforce the behavior of quirk 1 & 2.
> > >
> > > # Add a debugfs interface to WMI
> > >
> > > An interface to the WMI management interface that allows easier
> > > debugging.
> > >
> > 
> > It doesn't apply to current for-next.
> 
> Hey Andi,
I'm sorry, I meant Andy.
> 
> I was basing them on the stable branch.
> 
> It doesn't apply because of commit 440c4983de262f78033ec58f6abcd199a664327d
> (platform/x86: wmi: add context argument to the probe function)
> 
> One line change in huawei-wmi.c:
> -static int huawei_wmi_probe(struct wmi_device *wdev)
> +static int huawei_wmi_probe(struct wmi_device *wdev, const void *context)
> 
> I'll address that in the next version. For now, feedback is really
> appreciated.
> 
> > 
> > > Ayman Bagabas (9):
> > >   platform/x86: huawei-wmi: rename guid and driver name
> > >   platform/x86: huawei-wmi: move to platform driver
> > >   platform/x86: huawei-wmi: implement huawei wmi management interface
> > >   platform/x86: huawei-wmi: add quirks and module parameters
> > >   platform/x86: huawei-wmi: control micmute led through wmi interface
> > >   platform/x86: huawei-wmi: add battery charging thresholds
> > >   platform/x86: huawei-wmi: add fn-lock support
> > >   platform/x86: huawei-wmi: add sysfs interface support
> > >   platform/x86: huawei-wmi: add debugfs support
> > >
> > >  drivers/platform/x86/huawei-wmi.c | 710 ++++++++++++++++++++++++++----
> > >  1 file changed, 629 insertions(+), 81 deletions(-)
> > >
> > > --
> > > 2.20.1
> > >
> > 
> > 
> > -- 
> > With Best Regards,
> > Andy Shevchenko
> 
> -- 
> Thank you,
> Ayman

-- 
Thank you,
Ayman

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 0/9] platform/x86: Huawei WMI laptop extras driver
  2019-07-25 17:33 ` Andy Shevchenko
@ 2019-07-25 20:08   ` Ayman Bagabas
  2019-07-31  1:01     ` Ayman Bagabas
  0 siblings, 1 reply; 15+ messages in thread
From: Ayman Bagabas @ 2019-07-25 20:08 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Darren Hart, Andy Shevchenko, Platform Driver, Linux Kernel Mailing List

On 19/07/25 08:33PM, Andy Shevchenko wrote:
> On Sun, Jun 30, 2019 at 8:41 AM Ayman Bagabas <ayman.bagabas@gmail.com> wrote:
> >
> > This patch series introduce changes to huawei-wmi driver that includes:
> > * Move to platform driver
> > * Implement WMI management interface
> > * Add micmute LED support through WMI
> > * Add battery charging protection support through WMI
> > * Add fn-lock support through WMI
> > * Implement driver quirks and parameters
> > * Add a debugfs interface to WMI
> >
> > # Move to platform driver
> >
> > The current driver offers hotkeys and micmute led support only. With
> > these changes, a platform driver makes more sense since it handles these
> > changes pretty nicely.
> >
> > # Implement WMI management interface
> >
> > Huawei Matebook laptops come with two WMI interfaces. The first being
> > WMI0 which is considered "legacy" and AFAIK only found on the Matebook X
> > released in 2017. The second has a UID of "HWMI" and is found in pretty
> > much all models with a slight difference in implementation except for
> > the Matebook X (2017). Since this model has two interfaces, some aspects
> > are controlled through the legacy interface and some through the other
> > interface. Currently, the legacy interface is not fully implemented and
> > is only used for hotkeys and further debugging has to be done.
> >
> > The WMI interface takes a 64 bit integer, although uses 32 bits most of
> > the time, and returns a 256-260 bytes buffer consists of either one ACPI
> > buffer of 260 bytes, in the case of Matebook X (2017), or one ACPI
> > package of two buffers, one with 4 bytes, and the other with 256 bytes.
> > We only care about the latter 256 buffer in both cases since the 4 bytes
> > always return zeros. The first byte of this 256 buffer always has the
> > return status where 1 indicated error. Some models require calling the
> > WMI interface twice to execute a command.
> >
> > # Add micmute LED support through WMI
> >
> > After implementing the WMI interface, micmute LED can be controlled
> > easily. Models with the legacy interface fall back to ACPI EC method
> > control since the legacy interface is not implemented.
> >
> > # Add battery charging protection support through WMI
> >
> > Most models, that has the WMI interface, are capable of battery
> > protection where it can control battery charging thresholds and limits
> > charging the battery to certain values.
> >
> > # Add fn-lock support through WMI
> >
> > The behavior of hotkeys is not the same among all models. Some models
> > require fn-lock to do things like `Ctrl-Ins` or `Alt-PrtSc`. By default,
> > hotkeys behave as special keys (media keys, Ins, etc), but if a modifier
> > is used (ctrl, alt, shift) these keys behave as F1-F12 keys. If the Fn
> > key is toggled on, the hotkeys with or without a modifier, behave as
> > F1-F12 keys. This makes it impossible to use a modifier and `PrtSc` or
> > `Ins`.
> >
> > Now, some models fix this by excluding `PrtSc` and `Ins` keys from being
> > treated as F11 and F12 keys with the use of a modifier. However, some
> > models do not, and fixes this by the so called fn-lock.
> >
> > Fn-lock inverts the behavior of the top row from special keys to F1-F12
> > keys. So a modifier and a special key would be possible which make
> > things like `Alt-Ins` possible. Now, with fn-lock we would have 4 modes:
> >
> > * Fn-key off & fn-lock off - hotkeys treated as special keys using a
> >   modifier gives F1-F12 keys.
> > * Fn-key on & fn-lock off - hotkeys treated as F1-F12 keys and using a
> >   modifier gives F1-F12.
> > * Fn-key off & fn-lock on - hotkeys are treated as F1-F12 keys and using
> >   a modifier gives special keys.
> > * Fn-key on & fn-lock on - hotkeys are treated as special keys and using
> >   a modifier gives special keys.
> >
> > # Implement driver quirks and parameters
> >
> > The driver introduces 3 quirks and 2 parameters that can change the
> > driver's behavior. These quirks being as:
> > 1. Fixes reporting brightness keys twice since it's already handled by
> >    acpi-video.
> > 2. Some models need a short delay when setting battery thresholds to
> >    prevent a race condition when two processes read/write.
> > 3. Matebook X (2017) handles micmute led through the "legacy" interface
> >    which is not currently implemented. Use ACPI EC method to control
> >    this led.
> >
> > and the 2 parameters can enforce the behavior of quirk 1 & 2.
> >
> > # Add a debugfs interface to WMI
> >
> > An interface to the WMI management interface that allows easier
> > debugging.
> >
> 
> It doesn't apply to current for-next.

Hey Andi,

I was basing them on the stable branch.

It doesn't apply because of commit 440c4983de262f78033ec58f6abcd199a664327d
(platform/x86: wmi: add context argument to the probe function)

One line change in huawei-wmi.c:
-static int huawei_wmi_probe(struct wmi_device *wdev)
+static int huawei_wmi_probe(struct wmi_device *wdev, const void *context)

I'll address that in the next version. For now, feedback is really
appreciated.

> 
> > Ayman Bagabas (9):
> >   platform/x86: huawei-wmi: rename guid and driver name
> >   platform/x86: huawei-wmi: move to platform driver
> >   platform/x86: huawei-wmi: implement huawei wmi management interface
> >   platform/x86: huawei-wmi: add quirks and module parameters
> >   platform/x86: huawei-wmi: control micmute led through wmi interface
> >   platform/x86: huawei-wmi: add battery charging thresholds
> >   platform/x86: huawei-wmi: add fn-lock support
> >   platform/x86: huawei-wmi: add sysfs interface support
> >   platform/x86: huawei-wmi: add debugfs support
> >
> >  drivers/platform/x86/huawei-wmi.c | 710 ++++++++++++++++++++++++++----
> >  1 file changed, 629 insertions(+), 81 deletions(-)
> >
> > --
> > 2.20.1
> >
> 
> 
> -- 
> With Best Regards,
> Andy Shevchenko

-- 
Thank you,
Ayman

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC 0/9] platform/x86: Huawei WMI laptop extras driver
  2019-06-30  5:40 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
@ 2019-07-25 17:33 ` Andy Shevchenko
  2019-07-25 20:08   ` Ayman Bagabas
  0 siblings, 1 reply; 15+ messages in thread
From: Andy Shevchenko @ 2019-07-25 17:33 UTC (permalink / raw)
  To: Ayman Bagabas
  Cc: Darren Hart, Andy Shevchenko, Platform Driver, Linux Kernel Mailing List

On Sun, Jun 30, 2019 at 8:41 AM Ayman Bagabas <ayman.bagabas@gmail.com> wrote:
>
> This patch series introduce changes to huawei-wmi driver that includes:
> * Move to platform driver
> * Implement WMI management interface
> * Add micmute LED support through WMI
> * Add battery charging protection support through WMI
> * Add fn-lock support through WMI
> * Implement driver quirks and parameters
> * Add a debugfs interface to WMI
>
> # Move to platform driver
>
> The current driver offers hotkeys and micmute led support only. With
> these changes, a platform driver makes more sense since it handles these
> changes pretty nicely.
>
> # Implement WMI management interface
>
> Huawei Matebook laptops come with two WMI interfaces. The first being
> WMI0 which is considered "legacy" and AFAIK only found on the Matebook X
> released in 2017. The second has a UID of "HWMI" and is found in pretty
> much all models with a slight difference in implementation except for
> the Matebook X (2017). Since this model has two interfaces, some aspects
> are controlled through the legacy interface and some through the other
> interface. Currently, the legacy interface is not fully implemented and
> is only used for hotkeys and further debugging has to be done.
>
> The WMI interface takes a 64 bit integer, although uses 32 bits most of
> the time, and returns a 256-260 bytes buffer consists of either one ACPI
> buffer of 260 bytes, in the case of Matebook X (2017), or one ACPI
> package of two buffers, one with 4 bytes, and the other with 256 bytes.
> We only care about the latter 256 buffer in both cases since the 4 bytes
> always return zeros. The first byte of this 256 buffer always has the
> return status where 1 indicated error. Some models require calling the
> WMI interface twice to execute a command.
>
> # Add micmute LED support through WMI
>
> After implementing the WMI interface, micmute LED can be controlled
> easily. Models with the legacy interface fall back to ACPI EC method
> control since the legacy interface is not implemented.
>
> # Add battery charging protection support through WMI
>
> Most models, that has the WMI interface, are capable of battery
> protection where it can control battery charging thresholds and limits
> charging the battery to certain values.
>
> # Add fn-lock support through WMI
>
> The behavior of hotkeys is not the same among all models. Some models
> require fn-lock to do things like `Ctrl-Ins` or `Alt-PrtSc`. By default,
> hotkeys behave as special keys (media keys, Ins, etc), but if a modifier
> is used (ctrl, alt, shift) these keys behave as F1-F12 keys. If the Fn
> key is toggled on, the hotkeys with or without a modifier, behave as
> F1-F12 keys. This makes it impossible to use a modifier and `PrtSc` or
> `Ins`.
>
> Now, some models fix this by excluding `PrtSc` and `Ins` keys from being
> treated as F11 and F12 keys with the use of a modifier. However, some
> models do not, and fixes this by the so called fn-lock.
>
> Fn-lock inverts the behavior of the top row from special keys to F1-F12
> keys. So a modifier and a special key would be possible which make
> things like `Alt-Ins` possible. Now, with fn-lock we would have 4 modes:
>
> * Fn-key off & fn-lock off - hotkeys treated as special keys using a
>   modifier gives F1-F12 keys.
> * Fn-key on & fn-lock off - hotkeys treated as F1-F12 keys and using a
>   modifier gives F1-F12.
> * Fn-key off & fn-lock on - hotkeys are treated as F1-F12 keys and using
>   a modifier gives special keys.
> * Fn-key on & fn-lock on - hotkeys are treated as special keys and using
>   a modifier gives special keys.
>
> # Implement driver quirks and parameters
>
> The driver introduces 3 quirks and 2 parameters that can change the
> driver's behavior. These quirks being as:
> 1. Fixes reporting brightness keys twice since it's already handled by
>    acpi-video.
> 2. Some models need a short delay when setting battery thresholds to
>    prevent a race condition when two processes read/write.
> 3. Matebook X (2017) handles micmute led through the "legacy" interface
>    which is not currently implemented. Use ACPI EC method to control
>    this led.
>
> and the 2 parameters can enforce the behavior of quirk 1 & 2.
>
> # Add a debugfs interface to WMI
>
> An interface to the WMI management interface that allows easier
> debugging.
>

It doesn't apply to current for-next.

> Ayman Bagabas (9):
>   platform/x86: huawei-wmi: rename guid and driver name
>   platform/x86: huawei-wmi: move to platform driver
>   platform/x86: huawei-wmi: implement huawei wmi management interface
>   platform/x86: huawei-wmi: add quirks and module parameters
>   platform/x86: huawei-wmi: control micmute led through wmi interface
>   platform/x86: huawei-wmi: add battery charging thresholds
>   platform/x86: huawei-wmi: add fn-lock support
>   platform/x86: huawei-wmi: add sysfs interface support
>   platform/x86: huawei-wmi: add debugfs support
>
>  drivers/platform/x86/huawei-wmi.c | 710 ++++++++++++++++++++++++++----
>  1 file changed, 629 insertions(+), 81 deletions(-)
>
> --
> 2.20.1
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC 0/9] platform/x86: Huawei WMI laptop extras driver
@ 2019-06-30  5:40 Ayman Bagabas
  2019-07-25 17:33 ` Andy Shevchenko
  0 siblings, 1 reply; 15+ messages in thread
From: Ayman Bagabas @ 2019-06-30  5:40 UTC (permalink / raw)
  To: Darren Hart, Andy Shevchenko, platform-driver-x86, linux-kernel
  Cc: ayman.bagabas

This patch series introduce changes to huawei-wmi driver that includes:
* Move to platform driver
* Implement WMI management interface
* Add micmute LED support through WMI
* Add battery charging protection support through WMI
* Add fn-lock support through WMI
* Implement driver quirks and parameters
* Add a debugfs interface to WMI

# Move to platform driver

The current driver offers hotkeys and micmute led support only. With
these changes, a platform driver makes more sense since it handles these
changes pretty nicely.

# Implement WMI management interface

Huawei Matebook laptops come with two WMI interfaces. The first being
WMI0 which is considered "legacy" and AFAIK only found on the Matebook X
released in 2017. The second has a UID of "HWMI" and is found in pretty
much all models with a slight difference in implementation except for
the Matebook X (2017). Since this model has two interfaces, some aspects
are controlled through the legacy interface and some through the other
interface. Currently, the legacy interface is not fully implemented and
is only used for hotkeys and further debugging has to be done.

The WMI interface takes a 64 bit integer, although uses 32 bits most of
the time, and returns a 256-260 bytes buffer consists of either one ACPI
buffer of 260 bytes, in the case of Matebook X (2017), or one ACPI
package of two buffers, one with 4 bytes, and the other with 256 bytes.
We only care about the latter 256 buffer in both cases since the 4 bytes
always return zeros. The first byte of this 256 buffer always has the
return status where 1 indicated error. Some models require calling the
WMI interface twice to execute a command.

# Add micmute LED support through WMI

After implementing the WMI interface, micmute LED can be controlled
easily. Models with the legacy interface fall back to ACPI EC method
control since the legacy interface is not implemented.

# Add battery charging protection support through WMI

Most models, that has the WMI interface, are capable of battery
protection where it can control battery charging thresholds and limits
charging the battery to certain values.

# Add fn-lock support through WMI

The behavior of hotkeys is not the same among all models. Some models
require fn-lock to do things like `Ctrl-Ins` or `Alt-PrtSc`. By default,
hotkeys behave as special keys (media keys, Ins, etc), but if a modifier
is used (ctrl, alt, shift) these keys behave as F1-F12 keys. If the Fn
key is toggled on, the hotkeys with or without a modifier, behave as
F1-F12 keys. This makes it impossible to use a modifier and `PrtSc` or
`Ins`.

Now, some models fix this by excluding `PrtSc` and `Ins` keys from being
treated as F11 and F12 keys with the use of a modifier. However, some
models do not, and fixes this by the so called fn-lock.

Fn-lock inverts the behavior of the top row from special keys to F1-F12
keys. So a modifier and a special key would be possible which make
things like `Alt-Ins` possible. Now, with fn-lock we would have 4 modes:

* Fn-key off & fn-lock off - hotkeys treated as special keys using a
  modifier gives F1-F12 keys.
* Fn-key on & fn-lock off - hotkeys treated as F1-F12 keys and using a
  modifier gives F1-F12.
* Fn-key off & fn-lock on - hotkeys are treated as F1-F12 keys and using
  a modifier gives special keys.
* Fn-key on & fn-lock on - hotkeys are treated as special keys and using
  a modifier gives special keys.

# Implement driver quirks and parameters

The driver introduces 3 quirks and 2 parameters that can change the
driver's behavior. These quirks being as:
1. Fixes reporting brightness keys twice since it's already handled by
   acpi-video.
2. Some models need a short delay when setting battery thresholds to
   prevent a race condition when two processes read/write.
3. Matebook X (2017) handles micmute led through the "legacy" interface
   which is not currently implemented. Use ACPI EC method to control
   this led.

and the 2 parameters can enforce the behavior of quirk 1 & 2.

# Add a debugfs interface to WMI

An interface to the WMI management interface that allows easier
debugging.

Ayman Bagabas (9):
  platform/x86: huawei-wmi: rename guid and driver name
  platform/x86: huawei-wmi: move to platform driver
  platform/x86: huawei-wmi: implement huawei wmi management interface
  platform/x86: huawei-wmi: add quirks and module parameters
  platform/x86: huawei-wmi: control micmute led through wmi interface
  platform/x86: huawei-wmi: add battery charging thresholds
  platform/x86: huawei-wmi: add fn-lock support
  platform/x86: huawei-wmi: add sysfs interface support
  platform/x86: huawei-wmi: add debugfs support

 drivers/platform/x86/huawei-wmi.c | 710 ++++++++++++++++++++++++++----
 1 file changed, 629 insertions(+), 81 deletions(-)

-- 
2.20.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-08-01  0:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-31 17:52 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
2019-07-31 17:52 ` [RFC 2/9] platform/x86: huawei-wmi: Move to platform driver Ayman Bagabas
2019-07-31 17:52 ` [RFC 3/9] platform/x86: huawei-wmi: Implement huawei wmi management interface Ayman Bagabas
2019-07-31 17:52 ` [RFC 4/9] platform/x86: huawei-wmi: Add quirks and module parameters Ayman Bagabas
2019-07-31 17:52 ` [RFC 5/9] platform/x86: huawei-wmi: Control micmute led through wmi interface Ayman Bagabas
2019-07-31 17:52 ` [RFC 6/9] platform/x86: huawei-wmi: Add battery charging thresholds Ayman Bagabas
2019-07-31 17:52 ` [RFC 7/9] platform/x86: huawei-wmi: Add fn-lock support Ayman Bagabas
2019-07-31 17:52 ` [RFC 8/9] platform/x86: huawei-wmi: Add sysfs interface support Ayman Bagabas
2019-07-31 17:52 ` [RFC 9/9] platform/x86: huawei-wmi: Add debugfs support Ayman Bagabas
2019-08-01  0:21 ` [RFC 1/9] platform/x86: huawei-wmi: Rename guid and driver name Ayman Bagabas
2019-07-31 18:06   ` Ayman Bagabas
  -- strict thread matches above, loose matches on Subject: below --
2019-06-30  5:40 [RFC 0/9] platform/x86: Huawei WMI laptop extras driver Ayman Bagabas
2019-07-25 17:33 ` Andy Shevchenko
2019-07-25 20:08   ` Ayman Bagabas
2019-07-31  1:01     ` Ayman Bagabas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).