diff mbox series

[v2] platform/x86: support to store/show powermode value for Inspur

Message ID 20231014032844.3823198-1-aichao@kylinos.cn (mailing list archive)
State Changes Requested, archived
Headers show
Series [v2] platform/x86: support to store/show powermode value for Inspur | expand

Commit Message

Ai Chao Oct. 14, 2023, 3:28 a.m. UTC
Support to store/show powermode value for Inspur by WMI interface.
This driver provides support for Inspur WMI hotkeys. User used Fn+Q to
change the power mode. If desktop applications receive hotkey(Fn+Q)
event, then it get the currently power mode and change the power mode.
The desktop applications modify brightness and cpufreq based on
power mode.

change for v2
- Remove Event GUID, remove inspur_wmi_notify and inspur_wmi_notify.
- Add more explanation.

Signed-off-by: Ai Chao <aichao@kylinos.cn>
---
 drivers/platform/x86/Kconfig      |  14 ++
 drivers/platform/x86/Makefile     |   3 +
 drivers/platform/x86/inspur-wmi.c | 210 ++++++++++++++++++++++++++++++
 3 files changed, 227 insertions(+)
 create mode 100644 drivers/platform/x86/inspur-wmi.c

Comments

Armin Wolf Oct. 14, 2023, 11:39 p.m. UTC | #1
Am 14.10.23 um 05:28 schrieb Ai Chao:

> Support to store/show powermode value for Inspur by WMI interface.
> This driver provides support for Inspur WMI hotkeys. User used Fn+Q to
> change the power mode. If desktop applications receive hotkey(Fn+Q)
> event, then it get the currently power mode and change the power mode.
> The desktop applications modify brightness and cpufreq based on
> power mode.
>
> change for v2
> - Remove Event GUID, remove inspur_wmi_notify and inspur_wmi_notify.
> - Add more explanation.
>
> Signed-off-by: Ai Chao <aichao@kylinos.cn>
> ---
>   drivers/platform/x86/Kconfig      |  14 ++
>   drivers/platform/x86/Makefile     |   3 +
>   drivers/platform/x86/inspur-wmi.c | 210 ++++++++++++++++++++++++++++++
>   3 files changed, 227 insertions(+)
>   create mode 100644 drivers/platform/x86/inspur-wmi.c
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 2a1070543391..fa2a4335c83d 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -988,6 +988,20 @@ config TOUCHSCREEN_DMI
>   	  the OS-image for the device. This option supplies the missing info.
>   	  Enable this for x86 tablets with Silead or Chipone touchscreens.
>
> +config INSPUR_WMI
> +	tristate "Inspur WMI hotkeys driver"
> +	depends on ACPI_WMI
> +	depends on INPUT

The driver does not provide a input device anymore, please remove the
dependency on CONFIG_INPUT.

> +	help
> +	This driver provides support for Inspur WMI hotkeys.
> +	User used Fn+Q to change the power mode. If desktop applications
> +	receive hotkeys(Fn+Q) event, then it get the currently power mode
> +	and change the power mode. The desktop applications modify brightness
> +	and cpufreq based on power mode.
> +

I assume the whole hotkey stuff uses the other WMI GUID, right? In this case the
current driver should not be called "Inspur WMI hotkeys driver", since it does not
handle those hotkey notifications. Better call it "Inspur WMI power mode driver",
and remove all references to the hotkeys.

> +	To compile this driver as a module, choose M here: the module
> +	will be called inspur-wmi.
> +
>   source "drivers/platform/x86/x86-android-tablets/Kconfig"
>
>   config FW_ATTR_CLASS
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index b457de5abf7d..9285c252757e 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI)	+= toshiba-wmi.o
>   # before toshiba_acpi initializes
>   obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
>
> +# Inspur
> +obj-$(CONFIG_INSPUR_WMI)	+= inspur-wmi.o
> +
>   # Laptop drivers
>   obj-$(CONFIG_ACPI_CMPC)		+= classmate-laptop.o
>   obj-$(CONFIG_COMPAL_LAPTOP)	+= compal-laptop.o
> diff --git a/drivers/platform/x86/inspur-wmi.c b/drivers/platform/x86/inspur-wmi.c
> new file mode 100644
> index 000000000000..ef6cfd87f074
> --- /dev/null
> +++ b/drivers/platform/x86/inspur-wmi.c
> @@ -0,0 +1,210 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  Inspur WMI hotkeys
> + *
> + *  Copyright (C) 2018	      Ai Chao <aichao@kylinos.cn>
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/device.h>
> +#include <linux/input.h>
> +#include <linux/module.h>
> +#include <linux/wmi.h>
> +
> +#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D"
> +
> +enum inspur_wmi_method_ids {
> +	INSPUR_WMI_GET_POWERMODE = 0x02,
> +	INSPUR_WMI_SET_POWERMODE = 0x03,
> +};
> +
> +struct inspur_wmi_priv {
> +	struct input_dev *idev;
> +	struct wmi_device *wdev;
> +};
> +
> +static int inspur_wmi_perform_query(struct wmi_device *wdev,
> +				    enum inspur_wmi_method_ids query_id,
> +				    void *buffer, size_t insize,
> +				    size_t outsize)
> +{
> +	union acpi_object *obj;
> +	acpi_status status;
> +	int ret = 0;
> +	struct acpi_buffer input = { insize, buffer};
> +	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };

Please order the variable declarations in a reverse xmas tree order,
seeDocumentation/process/maintainer-netdev.rst#Local variable ordering for
details.

> +
> +	status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output);
> +	if (ACPI_FAILURE(status)) {
> +		dev_err(&wdev->dev, "EC Powermode control failed: %s\n",
> +			acpi_format_exception(status));
> +		return -EIO;
> +	}
> +
> +	obj = output.pointer;
> +	if (!obj)
> +		return -EINVAL;
> +
> +	if (obj->type != ACPI_TYPE_BUFFER) {
> +		ret = -EINVAL;
> +		goto out_free;
> +	}
> +
> +	/* Ignore output data of zero size */
> +	if (!outsize)
> +		goto out_free;

Since all users of this functions set outsize to something greater than zero,
this check is pointless. Please remove it.

> +
> +	if (obj->buffer.length != outsize) {
> +		ret = -EINVAL;
> +		goto out_free;
> +	}
> +
> +	memcpy(buffer, obj->buffer.pointer, obj->buffer.length);
> +
> +out_free:
> +	kfree(obj);
> +	return ret;
> +}
> +
> +/**
> + * Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
> + * return error
> + * Method ID: 0x3
> + * Arg: 4 Bytes
> + * Byte [0]: Power Mode:
> + *         0x0: Balance Mode
> + *         0x1: Performance Mode
> + *         0x2: Power Saver Mode
> + * Return Value: 4 Bytes
> + * Byte [0]: Return Code
> + *         0x0: No Error
> + *         0x1: Error
> + */

Now i understand what this power mode means. Why not use the platform profile interface
for this? All tree modes (Balance, Performance, Power Saver) would perfectly map to standard
platform profiles (BALANCED, PERFORMANCE, LOW_POWER), and using the platform profile interface
would allow userspace software to control the power mode over a standard interface.

I believe drivers/platform/surface/surface_platform_profile.c is a good example for such a driver,
_except_ that it ignores the return value of platform_profile_register().

> +static ssize_t powermode_store(struct device *dev,
> +			       struct device_attribute *attr,
> +			       const char *buf, size_t count)
> +{
> +	struct inspur_wmi_priv *priv = dev_get_drvdata(dev);
> +	int ret;
> +	u32 mode;

Since the buffer passed to the WMI method is structured in bytes, maybe you could use a
byte array in those cases? This would remove the need to cast "mode" to a "u8 *".

> +	u8 *ret_code;
> +
> +	ret = kstrtoint(buf, 0, &mode);
> +	if (ret)
> +		return ret;
> +
> +	ret = inspur_wmi_perform_query(priv->wdev,
> +				       INSPUR_WMI_SET_POWERMODE,
> +				       &mode, sizeof(mode), sizeof(mode));
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	ret_code = (u8 *)(&mode);
> +	if (ret_code[0])
> +		return -EBADRQC;
> +
> +	return count;
> +}
> +
> +/**
> + * Get Power Mode from EC RAM, If Power Mode value greater than 0x3,
> + * return error
> + * Method ID: 0x2
> + * Return Value: 4 Bytes
> + * Byte [0]: Return Code
> + *         0x0: No Error
> + *         0x1: Error
> + * Byte [1]: Power Mode
> + *         0x0: Balance Mode
> + *         0x1: Performance Mode
> + *         0x2: Power Saver Mode
> + */
> +static ssize_t powermode_show(struct device *dev,
> +			      struct device_attribute *attr,
> +			      char *buf)
> +{
> +	struct inspur_wmi_priv *priv = dev_get_drvdata(dev);
> +	u32 mode = 0;

Same as above.

> +	int ret;
> +	u8 *ret_code;
> +
> +	ret = inspur_wmi_perform_query(priv->wdev,
> +				       INSPUR_WMI_GET_POWERMODE,
> +				       &mode, sizeof(mode), sizeof(mode));
> +	if (ret < 0)
> +		return ret;
> +
> +	ret_code = (u8 *)(&mode);
> +	if (ret_code[0])
> +		return -EBADRQC;
> +
> +	return sprintf(buf, "%u\n", ret_code[1]);
> +}
> +
> +static DEVICE_ATTR_RW(powermode);
> +
> +static struct attribute *inspur_wmi_attrs[] = {
> +	&dev_attr_powermode.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group inspur_wmi_group = {
> +	.attrs = inspur_wmi_attrs,
> +};
> +
> +static const struct attribute_group *inspur_wmi_groups[] = {
> +	&inspur_wmi_group,
> +	NULL,
> +};
> +
> +static int inspur_wmi_input_setup(struct wmi_device *wdev)
> +{
> +	struct inspur_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
> +
> +	priv->idev = devm_input_allocate_device(&wdev->dev);
> +	if (!priv->idev)
> +		return -ENOMEM;
> +
> +	priv->idev->name = "Inspur WMI hotkeys";
> +	priv->idev->phys = "wmi/input0";
> +	priv->idev->id.bustype = BUS_HOST;
> +	priv->idev->dev.parent = &wdev->dev;
> +
> +	return input_register_device(priv->idev);
> +}

Please remove all remains of the hotkey handling.

> +
> +static int inspur_wmi_probe(struct wmi_device *wdev, const void *context)
> +{
> +	struct inspur_wmi_priv *priv;
> +
> +	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->wdev = wdev;
> +	dev_set_drvdata(&wdev->dev, priv);
> +
> +	return inspur_wmi_input_setup(wdev);
> +}
> +
> +static const struct wmi_device_id inspur_wmi_id_table[] = {
> +	{ .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID },
> +	{  }
> +};
> +
> +static struct wmi_driver inspur_wmi_driver = {
> +	.driver = {
> +		.name = "inspur-wmi",
> +		.dev_groups = inspur_wmi_groups,
> +	},
> +	.id_table = inspur_wmi_id_table,
> +	.probe = inspur_wmi_probe,
> +};
> +
> +module_wmi_driver(inspur_wmi_driver);
> +
> +MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table);

Can you move this right below "inspur_wmi_id_table" please?

> +MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");
> +MODULE_DESCRIPTION("Inspur WMI hotkeys");
> +MODULE_LICENSE("GPL");
kernel test robot Oct. 20, 2023, 4:13 p.m. UTC | #2
Hi Ai,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.6-rc6 next-20231020]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ai-Chao/platform-x86-support-to-store-show-powermode-value-for-Inspur/20231017-125537
base:   linus/master
patch link:    https://lore.kernel.org/r/20231014032844.3823198-1-aichao%40kylinos.cn
patch subject: [PATCH v2] platform/x86: support to store/show powermode value for Inspur
config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20231020/202310202354.NjaAKTX2-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231020/202310202354.NjaAKTX2-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202310202354.NjaAKTX2-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/inspur-wmi.c:70: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
   drivers/platform/x86/inspur-wmi.c:111: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst
    * Get Power Mode from EC RAM, If Power Mode value greater than 0x3,


vim +70 drivers/platform/x86/inspur-wmi.c

    68	
    69	/**
  > 70	 * Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
    71	 * return error
    72	 * Method ID: 0x3
    73	 * Arg: 4 Bytes
    74	 * Byte [0]: Power Mode:
    75	 *         0x0: Balance Mode
    76	 *         0x1: Performance Mode
    77	 *         0x2: Power Saver Mode
    78	 * Return Value: 4 Bytes
    79	 * Byte [0]: Return Code
    80	 *         0x0: No Error
    81	 *         0x1: Error
    82	 */
    83	static ssize_t powermode_store(struct device *dev,
    84				       struct device_attribute *attr,
    85				       const char *buf, size_t count)
    86	{
    87		struct inspur_wmi_priv *priv = dev_get_drvdata(dev);
    88		int ret;
    89		u32 mode;
    90		u8 *ret_code;
    91	
    92		ret = kstrtoint(buf, 0, &mode);
    93		if (ret)
    94			return ret;
    95	
    96		ret = inspur_wmi_perform_query(priv->wdev,
    97					       INSPUR_WMI_SET_POWERMODE,
    98					       &mode, sizeof(mode), sizeof(mode));
    99	
   100		if (ret < 0)
   101			return ret;
   102	
   103		ret_code = (u8 *)(&mode);
   104		if (ret_code[0])
   105			return -EBADRQC;
   106	
   107		return count;
   108	}
   109
diff mbox series

Patch

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 2a1070543391..fa2a4335c83d 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -988,6 +988,20 @@  config TOUCHSCREEN_DMI
 	  the OS-image for the device. This option supplies the missing info.
 	  Enable this for x86 tablets with Silead or Chipone touchscreens.
 
+config INSPUR_WMI
+	tristate "Inspur WMI hotkeys driver"
+	depends on ACPI_WMI
+	depends on INPUT
+	help
+	This driver provides support for Inspur WMI hotkeys.
+	User used Fn+Q to change the power mode. If desktop applications
+	receive hotkeys(Fn+Q) event, then it get the currently power mode
+	and change the power mode. The desktop applications modify brightness
+	and cpufreq based on power mode.
+
+	To compile this driver as a module, choose M here: the module
+	will be called inspur-wmi.
+
 source "drivers/platform/x86/x86-android-tablets/Kconfig"
 
 config FW_ATTR_CLASS
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index b457de5abf7d..9285c252757e 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -98,6 +98,9 @@  obj-$(CONFIG_TOSHIBA_WMI)	+= toshiba-wmi.o
 # before toshiba_acpi initializes
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 
+# Inspur
+obj-$(CONFIG_INSPUR_WMI)	+= inspur-wmi.o
+
 # Laptop drivers
 obj-$(CONFIG_ACPI_CMPC)		+= classmate-laptop.o
 obj-$(CONFIG_COMPAL_LAPTOP)	+= compal-laptop.o
diff --git a/drivers/platform/x86/inspur-wmi.c b/drivers/platform/x86/inspur-wmi.c
new file mode 100644
index 000000000000..ef6cfd87f074
--- /dev/null
+++ b/drivers/platform/x86/inspur-wmi.c
@@ -0,0 +1,210 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Inspur WMI hotkeys
+ *
+ *  Copyright (C) 2018	      Ai Chao <aichao@kylinos.cn>
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/wmi.h>
+
+#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D"
+
+enum inspur_wmi_method_ids {
+	INSPUR_WMI_GET_POWERMODE = 0x02,
+	INSPUR_WMI_SET_POWERMODE = 0x03,
+};
+
+struct inspur_wmi_priv {
+	struct input_dev *idev;
+	struct wmi_device *wdev;
+};
+
+static int inspur_wmi_perform_query(struct wmi_device *wdev,
+				    enum inspur_wmi_method_ids query_id,
+				    void *buffer, size_t insize,
+				    size_t outsize)
+{
+	union acpi_object *obj;
+	acpi_status status;
+	int ret = 0;
+	struct acpi_buffer input = { insize, buffer};
+	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+
+	status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output);
+	if (ACPI_FAILURE(status)) {
+		dev_err(&wdev->dev, "EC Powermode control failed: %s\n",
+			acpi_format_exception(status));
+		return -EIO;
+	}
+
+	obj = output.pointer;
+	if (!obj)
+		return -EINVAL;
+
+	if (obj->type != ACPI_TYPE_BUFFER) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	/* Ignore output data of zero size */
+	if (!outsize)
+		goto out_free;
+
+	if (obj->buffer.length != outsize) {
+		ret = -EINVAL;
+		goto out_free;
+	}
+
+	memcpy(buffer, obj->buffer.pointer, obj->buffer.length);
+
+out_free:
+	kfree(obj);
+	return ret;
+}
+
+/**
+ * Set Power Mode to EC RAM. If Power Mode value greater than 0x3,
+ * return error
+ * Method ID: 0x3
+ * Arg: 4 Bytes
+ * Byte [0]: Power Mode:
+ *         0x0: Balance Mode
+ *         0x1: Performance Mode
+ *         0x2: Power Saver Mode
+ * Return Value: 4 Bytes
+ * Byte [0]: Return Code
+ *         0x0: No Error
+ *         0x1: Error
+ */
+static ssize_t powermode_store(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct inspur_wmi_priv *priv = dev_get_drvdata(dev);
+	int ret;
+	u32 mode;
+	u8 *ret_code;
+
+	ret = kstrtoint(buf, 0, &mode);
+	if (ret)
+		return ret;
+
+	ret = inspur_wmi_perform_query(priv->wdev,
+				       INSPUR_WMI_SET_POWERMODE,
+				       &mode, sizeof(mode), sizeof(mode));
+
+	if (ret < 0)
+		return ret;
+
+	ret_code = (u8 *)(&mode);
+	if (ret_code[0])
+		return -EBADRQC;
+
+	return count;
+}
+
+/**
+ * Get Power Mode from EC RAM, If Power Mode value greater than 0x3,
+ * return error
+ * Method ID: 0x2
+ * Return Value: 4 Bytes
+ * Byte [0]: Return Code
+ *         0x0: No Error
+ *         0x1: Error
+ * Byte [1]: Power Mode
+ *         0x0: Balance Mode
+ *         0x1: Performance Mode
+ *         0x2: Power Saver Mode
+ */
+static ssize_t powermode_show(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct inspur_wmi_priv *priv = dev_get_drvdata(dev);
+	u32 mode = 0;
+	int ret;
+	u8 *ret_code;
+
+	ret = inspur_wmi_perform_query(priv->wdev,
+				       INSPUR_WMI_GET_POWERMODE,
+				       &mode, sizeof(mode), sizeof(mode));
+	if (ret < 0)
+		return ret;
+
+	ret_code = (u8 *)(&mode);
+	if (ret_code[0])
+		return -EBADRQC;
+
+	return sprintf(buf, "%u\n", ret_code[1]);
+}
+
+static DEVICE_ATTR_RW(powermode);
+
+static struct attribute *inspur_wmi_attrs[] = {
+	&dev_attr_powermode.attr,
+	NULL,
+};
+
+static const struct attribute_group inspur_wmi_group = {
+	.attrs = inspur_wmi_attrs,
+};
+
+static const struct attribute_group *inspur_wmi_groups[] = {
+	&inspur_wmi_group,
+	NULL,
+};
+
+static int inspur_wmi_input_setup(struct wmi_device *wdev)
+{
+	struct inspur_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
+
+	priv->idev = devm_input_allocate_device(&wdev->dev);
+	if (!priv->idev)
+		return -ENOMEM;
+
+	priv->idev->name = "Inspur WMI hotkeys";
+	priv->idev->phys = "wmi/input0";
+	priv->idev->id.bustype = BUS_HOST;
+	priv->idev->dev.parent = &wdev->dev;
+
+	return input_register_device(priv->idev);
+}
+
+static int inspur_wmi_probe(struct wmi_device *wdev, const void *context)
+{
+	struct inspur_wmi_priv *priv;
+
+	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->wdev = wdev;
+	dev_set_drvdata(&wdev->dev, priv);
+
+	return inspur_wmi_input_setup(wdev);
+}
+
+static const struct wmi_device_id inspur_wmi_id_table[] = {
+	{ .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID },
+	{  }
+};
+
+static struct wmi_driver inspur_wmi_driver = {
+	.driver = {
+		.name = "inspur-wmi",
+		.dev_groups = inspur_wmi_groups,
+	},
+	.id_table = inspur_wmi_id_table,
+	.probe = inspur_wmi_probe,
+};
+
+module_wmi_driver(inspur_wmi_driver);
+
+MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table);
+MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>");
+MODULE_DESCRIPTION("Inspur WMI hotkeys");
+MODULE_LICENSE("GPL");