xref: /linux/drivers/platform/x86/lenovo/wmi-other.c (revision 1e38f888f9f070591e54c690e78f2ff8affa8881)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Lenovo Other Mode WMI interface driver.
4  *
5  * This driver uses the fw_attributes class to expose the various WMI functions
6  * provided by the "Other Mode" WMI interface. This enables CPU and GPU power
7  * limit as well as various other attributes for devices that fall under the
8  * "Gaming Series" of Lenovo laptop devices. Each attribute exposed by the
9  * "Other Mode" interface has a corresponding Capability Data struct that
10  * allows the driver to probe details about the attribute such as if it is
11  * supported by the hardware, the default_value, max_value, min_value, and step
12  * increment.
13  *
14  * These attributes typically don't fit anywhere else in the sysfs and are set
15  * in Windows using one of Lenovo's multiple user applications.
16  *
17  * Additionally, this driver also exports tunable fan speed RPM to HWMON.
18  * Min/max RPM are also provided for reference.
19  *
20  * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
21  *   - fw_attributes
22  *   - binding to Capability Data 01
23  *
24  * Copyright (C) 2025 Rong Zhang <i@rong.moe>
25  *   - HWMON
26  *   - binding to Capability Data 00 and Fan
27  */
28 
29 #include <linux/acpi.h>
30 #include <linux/bitfield.h>
31 #include <linux/cleanup.h>
32 #include <linux/component.h>
33 #include <linux/container_of.h>
34 #include <linux/device.h>
35 #include <linux/export.h>
36 #include <linux/gfp_types.h>
37 #include <linux/hwmon.h>
38 #include <linux/idr.h>
39 #include <linux/kdev_t.h>
40 #include <linux/kobject.h>
41 #include <linux/limits.h>
42 #include <linux/module.h>
43 #include <linux/notifier.h>
44 #include <linux/platform_profile.h>
45 #include <linux/types.h>
46 #include <linux/wmi.h>
47 
48 #include "wmi-capdata.h"
49 #include "wmi-events.h"
50 #include "wmi-gamezone.h"
51 #include "wmi-helpers.h"
52 #include "wmi-other.h"
53 #include "../firmware_attributes_class.h"
54 
55 #define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"
56 
57 #define LWMI_DEVICE_ID_CPU 0x01
58 
59 #define LWMI_FEATURE_ID_CPU_SPPT 0x01
60 #define LWMI_FEATURE_ID_CPU_SPL 0x02
61 #define LWMI_FEATURE_ID_CPU_FPPT 0x03
62 
63 #define LWMI_FEATURE_ID_FAN_RPM 0x03
64 
65 #define LWMI_TYPE_ID_NONE 0x00
66 
67 #define LWMI_FEATURE_VALUE_GET 17
68 #define LWMI_FEATURE_VALUE_SET 18
69 
70 #define LWMI_FAN_ID_BASE 1
71 #define LWMI_FAN_NR 4
72 #define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
73 
74 #define LWMI_ATTR_ID_FAN_RPM(x)						\
75 	(FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) |	\
76 	 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) |	\
77 	 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x)))
78 
79 #define LWMI_FAN_DIV 100
80 
81 #define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"
82 #define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
83 
84 static BLOCKING_NOTIFIER_HEAD(om_chain_head);
85 static DEFINE_IDA(lwmi_om_ida);
86 
87 enum attribute_property {
88 	DEFAULT_VAL,
89 	MAX_VAL,
90 	MIN_VAL,
91 	STEP_VAL,
92 	SUPPORTED,
93 };
94 
95 struct lwmi_fan_info {
96 	u32 supported;
97 	u32 last_target;
98 	long min_rpm;
99 	long max_rpm;
100 };
101 
102 struct lwmi_om_priv {
103 	struct component_master_ops *ops;
104 
105 	/* only valid after capdata bind */
106 	struct cd_list *cd00_list;
107 	struct cd_list *cd01_list;
108 
109 	struct device *hwmon_dev;
110 	struct device *fw_attr_dev;
111 	struct kset *fw_attr_kset;
112 	struct notifier_block nb;
113 	struct wmi_device *wdev;
114 	int ida_id;
115 
116 	struct lwmi_fan_info fan_info[LWMI_FAN_NR];
117 
118 	struct {
119 		bool capdata00_collected : 1;
120 		bool capdata_fan_collected : 1;
121 	} fan_flags;
122 };
123 
124 /*
125  * Visibility of fan channels:
126  *
127  * +-------------------+---------+------------------+-----------------------+------------+
128  * |                   | default | +expose_all_fans | +relax_fan_constraint | +both      |
129  * +-------------------+---------+------------------+-----------------------+------------+
130  * | canonical         | RW      | RW               | RW+relaxed            | RW+relaxed |
131  * +-------------------+---------+------------------+-----------------------+------------+
132  * | -capdata_fan[idx] | N       | RO               | N                     | RW+relaxed |
133  * +-------------------+---------+------------------+-----------------------+------------+
134  *
135  * Note:
136  * 1. LWMI_ATTR_ID_FAN_RPM[idx].supported is always checked before exposing a channel.
137  * 2. -capdata_fan implies -capdata_fan[idx].
138  */
139 static bool expose_all_fans;
140 module_param(expose_all_fans, bool, 0444);
141 MODULE_PARM_DESC(expose_all_fans,
142 	"This option skips some capability checks and solely relies on per-channel ones "
143 	"to expose fan attributes. Use with caution.");
144 
145 static bool relax_fan_constraint;
146 module_param(relax_fan_constraint, bool, 0444);
147 MODULE_PARM_DESC(relax_fan_constraint,
148 	"Do not enforce fan RPM constraint (div/min/max) "
149 	"and enables fan tuning when such data is missing. "
150 	"Enabling this may results in HWMON attributes being out-of-sync, "
151 	"and setting a too low RPM stops the fan. Use with caution.");
152 
153 /* ======== HWMON (component: lenovo-wmi-capdata 00 & fan) ======== */
154 
155 /**
156  * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan
157  * @priv: Driver private data structure
158  * @channel: Fan channel index (0-based)
159  * @val: Pointer to value (input for set, output for get)
160  * @set: True to set value, false to get value
161  *
162  * Communicates with WMI interface to either retrieve current fan RPM
163  * or set target fan RPM.
164  *
165  * Return: 0 on success, or an error code.
166  */
lwmi_om_fan_get_set(struct lwmi_om_priv * priv,int channel,u32 * val,bool set)167 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set)
168 {
169 	struct wmi_method_args_32 args;
170 	u32 method_id, retval;
171 	int err;
172 
173 	method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET;
174 	args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel);
175 	args.arg1 = set ? *val : 0;
176 
177 	err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id,
178 				    (unsigned char *)&args, sizeof(args), &retval);
179 	if (err)
180 		return err;
181 
182 	if (!set) {
183 		*val = retval;
184 		return 0;
185 	}
186 
187 	/*
188 	 * It seems that 0 means "no error" and 1 means "done". Apparently
189 	 * different firmware teams have different thoughts on indicating
190 	 * success, so we accepts both.
191 	 */
192 	return (retval == 0 || retval == 1) ? 0 : -EIO;
193 }
194 
195 /**
196  * lwmi_om_hwmon_is_visible() - Determine visibility of HWMON attributes
197  * @drvdata: Driver private data
198  * @type: Sensor type
199  * @attr: Attribute identifier
200  * @channel: Channel index
201  *
202  * Determines whether an HWMON attribute should be visible in sysfs
203  * based on hardware capabilities and current configuration.
204  *
205  * Return: permission mode, or 0 if invisible.
206  */
lwmi_om_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)207 static umode_t lwmi_om_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
208 					u32 attr, int channel)
209 {
210 	struct lwmi_om_priv *priv = (struct lwmi_om_priv *)drvdata;
211 	bool visible = false;
212 
213 	if (type == hwmon_fan) {
214 		if (!(priv->fan_info[channel].supported & LWMI_SUPP_VALID))
215 			return 0;
216 
217 		switch (attr) {
218 		case hwmon_fan_target:
219 			if (!(priv->fan_info[channel].supported & LWMI_SUPP_SET))
220 				return 0;
221 
222 			if (relax_fan_constraint ||
223 			    (priv->fan_info[channel].min_rpm >= 0 &&
224 			     priv->fan_info[channel].max_rpm >= 0))
225 				return 0644;
226 
227 			/*
228 			 * Reaching here implies expose_all_fans is set.
229 			 * See lwmi_om_hwmon_add().
230 			 */
231 			dev_warn_once(&priv->wdev->dev,
232 				      "fan tuning disabled due to missing RPM constraint\n");
233 			return 0;
234 		case hwmon_fan_div:
235 		case hwmon_fan_input:
236 			visible = priv->fan_info[channel].supported & LWMI_SUPP_GET;
237 			break;
238 		case hwmon_fan_min:
239 			visible = priv->fan_info[channel].min_rpm >= 0;
240 			break;
241 		case hwmon_fan_max:
242 			visible = priv->fan_info[channel].max_rpm >= 0;
243 			break;
244 		}
245 	}
246 
247 	return visible ? 0444 : 0;
248 }
249 
250 /**
251  * lwmi_om_hwmon_read() - Read HWMON sensor data
252  * @dev: Device pointer
253  * @type: Sensor type
254  * @attr: Attribute identifier
255  * @channel: Channel index
256  * @val: Pointer to store value
257  *
258  * Reads current sensor values from hardware through WMI interface.
259  *
260  * Return: 0 on success, or an error code.
261  */
lwmi_om_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)262 static int lwmi_om_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
263 			      u32 attr, int channel, long *val)
264 {
265 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
266 	u32 retval = 0;
267 	int err;
268 
269 	if (type == hwmon_fan) {
270 		switch (attr) {
271 		/*
272 		 * The EC has an internal RPM divisor (i.e., the raw register value is
273 		 * RPM / fanY_div). For fanY_input, the WMI method reads the register
274 		 * value and returns raw * fanY_div. For fanY_target, the WMI method
275 		 * divides the written value by fanY_div before writing it to the EC.
276 		 *
277 		 * As a result, reading fanY_input always returns a multiple of fanY_div,
278 		 * while writing to fanY_target loses the remainder.
279 		 */
280 		case hwmon_fan_div:
281 			*val = LWMI_FAN_DIV;
282 			return 0;
283 		case hwmon_fan_input:
284 			err = lwmi_om_fan_get_set(priv, channel, &retval, false);
285 			if (err)
286 				return err;
287 
288 			*val = retval;
289 			return 0;
290 		case hwmon_fan_target:
291 			*val = priv->fan_info[channel].last_target;
292 			return 0;
293 		case hwmon_fan_min:
294 			*val = priv->fan_info[channel].min_rpm;
295 			return 0;
296 		case hwmon_fan_max:
297 			*val = priv->fan_info[channel].max_rpm;
298 			return 0;
299 		}
300 	}
301 
302 	return -EOPNOTSUPP;
303 }
304 
305 /**
306  * lwmi_om_hwmon_write() - Write HWMON sensor data
307  * @dev: Device pointer
308  * @type: Sensor type
309  * @attr: Attribute identifier
310  * @channel: Channel index
311  * @val: Value to write
312  *
313  * Writes configuration values to hardware through WMI interface.
314  *
315  * Return: 0 on success, or an error code.
316  */
lwmi_om_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)317 static int lwmi_om_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
318 			       u32 attr, int channel, long val)
319 {
320 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
321 	u32 raw, min_rpm, max_rpm;
322 	int err;
323 
324 	if (type == hwmon_fan) {
325 		switch (attr) {
326 		case hwmon_fan_target:
327 			if (relax_fan_constraint) {
328 				min_rpm = 1;
329 				max_rpm = U16_MAX;
330 			} else {
331 				min_rpm = priv->fan_info[channel].min_rpm;
332 				max_rpm = priv->fan_info[channel].max_rpm;
333 			}
334 
335 			/* 0 means "auto". */
336 			if (val != 0 && (val < min_rpm || val > max_rpm))
337 				return -EINVAL;
338 
339 			/*
340 			 * The effective fanY_target is always a multiple of fanY_div
341 			 * due to the EC's internal RPM divisor (see lwmi_om_hwmon_read).
342 			 *
343 			 * Round down the written value to the nearest multiple of fanY_div
344 			 * to prevent mismatch between the effective value and last_target.
345 			 *
346 			 * For relax_fan_constraint, skip this conversion as setting a
347 			 * sub-fanY_div value is necessary to completely stop the fan on
348 			 * some devices.
349 			 */
350 			if (!relax_fan_constraint)
351 				raw = val / LWMI_FAN_DIV * LWMI_FAN_DIV;
352 			else
353 				raw = val;
354 
355 			err = lwmi_om_fan_get_set(priv, channel, &raw, true);
356 			if (err)
357 				return err;
358 
359 			priv->fan_info[channel].last_target = raw;
360 			return 0;
361 		}
362 	}
363 
364 	return -EOPNOTSUPP;
365 }
366 
367 static const struct hwmon_channel_info * const lwmi_om_hwmon_info[] = {
368 	/* Must match LWMI_FAN_NR. */
369 	HWMON_CHANNEL_INFO(fan,
370 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
371 			   HWMON_F_MIN | HWMON_F_MAX,
372 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
373 			   HWMON_F_MIN | HWMON_F_MAX,
374 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
375 			   HWMON_F_MIN | HWMON_F_MAX,
376 			   HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
377 			   HWMON_F_MIN | HWMON_F_MAX),
378 	NULL
379 };
380 
381 static const struct hwmon_ops lwmi_om_hwmon_ops = {
382 	.is_visible = lwmi_om_hwmon_is_visible,
383 	.read = lwmi_om_hwmon_read,
384 	.write = lwmi_om_hwmon_write,
385 };
386 
387 static const struct hwmon_chip_info lwmi_om_hwmon_chip_info = {
388 	.ops = &lwmi_om_hwmon_ops,
389 	.info = lwmi_om_hwmon_info,
390 };
391 
392 /**
393  * lwmi_om_hwmon_add() - Register HWMON device if all info is collected
394  * @priv: Driver private data
395  */
lwmi_om_hwmon_add(struct lwmi_om_priv * priv)396 static void lwmi_om_hwmon_add(struct lwmi_om_priv *priv)
397 {
398 	int i, valid;
399 
400 	if (WARN_ON(priv->hwmon_dev))
401 		return;
402 
403 	if (!priv->fan_flags.capdata00_collected || !priv->fan_flags.capdata_fan_collected) {
404 		dev_dbg(&priv->wdev->dev, "HWMON registration pending (00: %d, fan: %d)\n",
405 			priv->fan_flags.capdata00_collected,
406 			priv->fan_flags.capdata_fan_collected);
407 		return;
408 	}
409 
410 	if (expose_all_fans)
411 		dev_warn(&priv->wdev->dev, "all fans exposed. Use with caution\n");
412 
413 	if (relax_fan_constraint)
414 		dev_warn(&priv->wdev->dev, "fan RPM constraint relaxed. Use with caution\n");
415 
416 	valid = 0;
417 	for (i = 0; i < LWMI_FAN_NR; i++) {
418 		if (!(priv->fan_info[i].supported & LWMI_SUPP_VALID))
419 			continue;
420 
421 		valid++;
422 
423 		if (!expose_all_fans &&
424 		    (priv->fan_info[i].min_rpm < 0 || priv->fan_info[i].max_rpm < 0)) {
425 			dev_dbg(&priv->wdev->dev, "missing RPM constraint for fan%d, hiding\n",
426 				LWMI_FAN_ID(i));
427 			priv->fan_info[i].supported = 0;
428 			valid--;
429 		}
430 	}
431 
432 	if (valid == 0) {
433 		dev_warn(&priv->wdev->dev,
434 			 "fan reporting/tuning is unsupported on this device\n");
435 		return;
436 	}
437 
438 	priv->hwmon_dev = hwmon_device_register_with_info(&priv->wdev->dev,
439 							  LWMI_OM_HWMON_NAME, priv,
440 							  &lwmi_om_hwmon_chip_info,
441 							  NULL);
442 	if (IS_ERR(priv->hwmon_dev)) {
443 		dev_warn(&priv->wdev->dev, "failed to register HWMON device: %ld\n",
444 			 PTR_ERR(priv->hwmon_dev));
445 		priv->hwmon_dev = NULL;
446 		return;
447 	}
448 
449 	dev_dbg(&priv->wdev->dev, "registered HWMON device\n");
450 }
451 
452 /**
453  * lwmi_om_hwmon_remove() - Unregister HWMON device
454  * @priv: Driver private data
455  *
456  * Unregisters the HWMON device if applicable.
457  */
lwmi_om_hwmon_remove(struct lwmi_om_priv * priv)458 static void lwmi_om_hwmon_remove(struct lwmi_om_priv *priv)
459 {
460 	if (!priv->hwmon_dev)
461 		return;
462 
463 	hwmon_device_unregister(priv->hwmon_dev);
464 	priv->hwmon_dev = NULL;
465 }
466 
467 /**
468  * lwmi_om_fan_info_init() - Initialzie fan info
469  * @priv: Driver private data
470  *
471  * lwmi_om_fan_info_collect_cd00() and lwmi_om_fan_info_collect_cd_fan() may be
472  * called in an arbitrary order. Hence, initializion must be done before.
473  */
lwmi_om_fan_info_init(struct lwmi_om_priv * priv)474 static void lwmi_om_fan_info_init(struct lwmi_om_priv *priv)
475 {
476 	int i;
477 
478 	for (i = 0; i < LWMI_FAN_NR; i++) {
479 		priv->fan_info[i] = (struct lwmi_fan_info) {
480 			.supported = 0,
481 			/*
482 			 * Assume 0 on probe as the EC resets all fans to auto mode on (re)boot.
483 			 *
484 			 * Note that S0ix (s2idle) preserves the RPM target, so we don't need
485 			 * suspend/resume callbacks. This behavior has not been tested on S3-
486 			 * capable devices, but I doubt if such devices even have this interface.
487 			 */
488 			.last_target = 0,
489 			.min_rpm = -ENODATA,
490 			.max_rpm = -ENODATA,
491 		};
492 	}
493 
494 	priv->fan_flags.capdata00_collected = false;
495 	priv->fan_flags.capdata_fan_collected = false;
496 }
497 
498 /**
499  * lwmi_om_fan_info_collect_cd00() - Collect fan info from capdata 00
500  * @priv: Driver private data
501  */
lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv * priv)502 static void lwmi_om_fan_info_collect_cd00(struct lwmi_om_priv *priv)
503 {
504 	struct capdata00 capdata00;
505 	int i, err;
506 
507 	dev_dbg(&priv->wdev->dev, "Collecting fan info from capdata00\n");
508 
509 	for (i = 0; i < LWMI_FAN_NR; i++) {
510 		err = lwmi_cd00_get_data(priv->cd00_list, LWMI_ATTR_ID_FAN_RPM(i), &capdata00);
511 		priv->fan_info[i].supported = err ? 0 : capdata00.supported;
512 	}
513 
514 	priv->fan_flags.capdata00_collected = true;
515 	lwmi_om_hwmon_add(priv);
516 }
517 
518 /**
519  * lwmi_om_fan_info_collect_cd_fan() - Collect fan info from capdata fan
520  * @dev: Pointer to the lenovo-wmi-other device
521  * @cd_fan_list: Pointer to the capdata fan list
522  */
lwmi_om_fan_info_collect_cd_fan(struct device * dev,struct cd_list * cd_fan_list)523 static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *cd_fan_list)
524 {
525 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
526 	struct capdata_fan capdata_fan;
527 	int i, err;
528 
529 	dev_dbg(dev, "Collecting fan info from capdata_fan\n");
530 
531 	if (!cd_fan_list)
532 		goto out;
533 
534 	for (i = 0; i < LWMI_FAN_NR; i++) {
535 		err = lwmi_cd_fan_get_data(cd_fan_list, LWMI_FAN_ID(i), &capdata_fan);
536 		if (err)
537 			continue;
538 
539 		priv->fan_info[i].min_rpm = capdata_fan.min_rpm;
540 		priv->fan_info[i].max_rpm = capdata_fan.max_rpm;
541 	}
542 
543 out:
544 	priv->fan_flags.capdata_fan_collected = true;
545 	lwmi_om_hwmon_add(priv);
546 }
547 
548 /* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */
549 
550 struct tunable_attr_01 {
551 	struct capdata01 *capdata;
552 	struct device *dev;
553 	u32 feature_id;
554 	u32 device_id;
555 	u32 type_id;
556 };
557 
558 static struct tunable_attr_01 ppt_pl1_spl = {
559 	.device_id = LWMI_DEVICE_ID_CPU,
560 	.feature_id = LWMI_FEATURE_ID_CPU_SPL,
561 	.type_id = LWMI_TYPE_ID_NONE,
562 };
563 
564 static struct tunable_attr_01 ppt_pl2_sppt = {
565 	.device_id = LWMI_DEVICE_ID_CPU,
566 	.feature_id = LWMI_FEATURE_ID_CPU_SPPT,
567 	.type_id = LWMI_TYPE_ID_NONE,
568 };
569 
570 static struct tunable_attr_01 ppt_pl3_fppt = {
571 	.device_id = LWMI_DEVICE_ID_CPU,
572 	.feature_id = LWMI_FEATURE_ID_CPU_FPPT,
573 	.type_id = LWMI_TYPE_ID_NONE,
574 };
575 
576 struct capdata01_attr_group {
577 	const struct attribute_group *attr_group;
578 	struct tunable_attr_01 *tunable_attr;
579 };
580 
581 /**
582  * lwmi_om_register_notifier() - Add a notifier to the blocking notifier chain
583  * @nb: The notifier_block struct to register
584  *
585  * Call blocking_notifier_chain_register to register the notifier block to the
586  * lenovo-wmi-other driver notifier chain.
587  *
588  * Return: 0 on success, %-EEXIST on error.
589  */
lwmi_om_register_notifier(struct notifier_block * nb)590 int lwmi_om_register_notifier(struct notifier_block *nb)
591 {
592 	return blocking_notifier_chain_register(&om_chain_head, nb);
593 }
594 EXPORT_SYMBOL_NS_GPL(lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
595 
596 /**
597  * lwmi_om_unregister_notifier() - Remove a notifier from the blocking notifier
598  * chain.
599  * @nb: The notifier_block struct to register
600  *
601  * Call blocking_notifier_chain_unregister to unregister the notifier block from the
602  * lenovo-wmi-other driver notifier chain.
603  *
604  * Return: 0 on success, %-ENOENT on error.
605  */
lwmi_om_unregister_notifier(struct notifier_block * nb)606 int lwmi_om_unregister_notifier(struct notifier_block *nb)
607 {
608 	return blocking_notifier_chain_unregister(&om_chain_head, nb);
609 }
610 EXPORT_SYMBOL_NS_GPL(lwmi_om_unregister_notifier, "LENOVO_WMI_OTHER");
611 
612 /**
613  * devm_lwmi_om_unregister_notifier() - Remove a notifier from the blocking
614  * notifier chain.
615  * @data: Void pointer to the notifier_block struct to register.
616  *
617  * Call lwmi_om_unregister_notifier to unregister the notifier block from the
618  * lenovo-wmi-other driver notifier chain.
619  *
620  * Return: 0 on success, %-ENOENT on error.
621  */
devm_lwmi_om_unregister_notifier(void * data)622 static void devm_lwmi_om_unregister_notifier(void *data)
623 {
624 	struct notifier_block *nb = data;
625 
626 	lwmi_om_unregister_notifier(nb);
627 }
628 
629 /**
630  * devm_lwmi_om_register_notifier() - Add a notifier to the blocking notifier
631  * chain.
632  * @dev: The parent device of the notifier_block struct.
633  * @nb: The notifier_block struct to register
634  *
635  * Call lwmi_om_register_notifier to register the notifier block to the
636  * lenovo-wmi-other driver notifier chain. Then add devm_lwmi_om_unregister_notifier
637  * as a device managed action to automatically unregister the notifier block
638  * upon parent device removal.
639  *
640  * Return: 0 on success, or an error code.
641  */
devm_lwmi_om_register_notifier(struct device * dev,struct notifier_block * nb)642 int devm_lwmi_om_register_notifier(struct device *dev,
643 				   struct notifier_block *nb)
644 {
645 	int ret;
646 
647 	ret = lwmi_om_register_notifier(nb);
648 	if (ret < 0)
649 		return ret;
650 
651 	return devm_add_action_or_reset(dev, devm_lwmi_om_unregister_notifier,
652 					nb);
653 }
654 EXPORT_SYMBOL_NS_GPL(devm_lwmi_om_register_notifier, "LENOVO_WMI_OTHER");
655 
656 /**
657  * lwmi_om_notifier_call() - Call functions for the notifier call chain.
658  * @mode: Pointer to a thermal mode enum to retrieve the data from.
659  *
660  * Call blocking_notifier_call_chain to retrieve the thermal mode from the
661  * lenovo-wmi-gamezone driver.
662  *
663  * Return: 0 on success, or an error code.
664  */
lwmi_om_notifier_call(enum thermal_mode * mode)665 static int lwmi_om_notifier_call(enum thermal_mode *mode)
666 {
667 	int ret;
668 
669 	ret = blocking_notifier_call_chain(&om_chain_head,
670 					   LWMI_GZ_GET_THERMAL_MODE, &mode);
671 	if ((ret & ~NOTIFY_STOP_MASK) != NOTIFY_OK)
672 		return -EINVAL;
673 
674 	return 0;
675 }
676 
677 /* Attribute Methods */
678 
679 /**
680  * int_type_show() - Emit the data type for an integer attribute
681  * @kobj: Pointer to the driver object.
682  * @kattr: Pointer to the attribute calling this function.
683  * @buf: The buffer to write to.
684  *
685  * Return: Number of characters written to buf.
686  */
int_type_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf)687 static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *kattr,
688 			     char *buf)
689 {
690 	return sysfs_emit(buf, "integer\n");
691 }
692 
693 /**
694  * attr_capdata01_show() - Get the value of the specified attribute property
695  *
696  * @kobj: Pointer to the driver object.
697  * @kattr: Pointer to the attribute calling this function.
698  * @buf: The buffer to write to.
699  * @tunable_attr: The attribute to be read.
700  * @prop: The property of this attribute to be read.
701  *
702  * Retrieves the given property from the capability data 01 struct for the
703  * specified attribute's "custom" thermal mode. This function is intended
704  * to be generic so it can be called from any integer attributes "_show"
705  * function.
706  *
707  * If the WMI is success the sysfs attribute is notified.
708  *
709  * Return: Either number of characters written to buf, or an error code.
710  */
attr_capdata01_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr,enum attribute_property prop)711 static ssize_t attr_capdata01_show(struct kobject *kobj,
712 				   struct kobj_attribute *kattr, char *buf,
713 				   struct tunable_attr_01 *tunable_attr,
714 				   enum attribute_property prop)
715 {
716 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
717 	struct capdata01 capdata;
718 	u32 attribute_id;
719 	int value, ret;
720 
721 	attribute_id =
722 		FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
723 		FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
724 		FIELD_PREP(LWMI_ATTR_MODE_ID_MASK,
725 			   LWMI_GZ_THERMAL_MODE_CUSTOM) |
726 		FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
727 
728 	ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
729 	if (ret)
730 		return ret;
731 
732 	switch (prop) {
733 	case DEFAULT_VAL:
734 		value = capdata.default_value;
735 		break;
736 	case MAX_VAL:
737 		value = capdata.max_value;
738 		break;
739 	case MIN_VAL:
740 		value = capdata.min_value;
741 		break;
742 	case STEP_VAL:
743 		value = capdata.step;
744 		break;
745 	default:
746 		return -EINVAL;
747 	}
748 
749 	return sysfs_emit(buf, "%d\n", value);
750 }
751 
752 /**
753  * attr_current_value_store() - Set the current value of the given attribute
754  * @kobj: Pointer to the driver object.
755  * @kattr: Pointer to the attribute calling this function.
756  * @buf: The buffer to read from, this is parsed to `int` type.
757  * @count: Required by sysfs attribute macros, pass in from the callee attr.
758  * @tunable_attr: The attribute to be stored.
759  *
760  * Sets the value of the given attribute when operating under the "custom"
761  * smartfan profile. The current smartfan profile is retrieved from the
762  * lenovo-wmi-gamezone driver and error is returned if the result is not
763  * "custom". This function is intended to be generic so it can be called from
764  * any integer attribute's "_store" function. The integer to be sent to the WMI
765  * method is range checked and an error code is returned if out of range.
766  *
767  * If the value is valid and WMI is success, then the sysfs attribute is
768  * notified.
769  *
770  * Return: Either count, or an error code.
771  */
attr_current_value_store(struct kobject * kobj,struct kobj_attribute * kattr,const char * buf,size_t count,struct tunable_attr_01 * tunable_attr)772 static ssize_t attr_current_value_store(struct kobject *kobj,
773 					struct kobj_attribute *kattr,
774 					const char *buf, size_t count,
775 					struct tunable_attr_01 *tunable_attr)
776 {
777 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
778 	struct wmi_method_args_32 args;
779 	struct capdata01 capdata;
780 	enum thermal_mode mode;
781 	u32 attribute_id;
782 	u32 value;
783 	int ret;
784 
785 	ret = lwmi_om_notifier_call(&mode);
786 	if (ret)
787 		return ret;
788 
789 	if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
790 		return -EBUSY;
791 
792 	attribute_id =
793 		FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
794 		FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
795 		FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
796 		FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
797 
798 	ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
799 	if (ret)
800 		return ret;
801 
802 	ret = kstrtouint(buf, 10, &value);
803 	if (ret)
804 		return ret;
805 
806 	if (value < capdata.min_value || value > capdata.max_value)
807 		return -EINVAL;
808 
809 	args.arg0 = attribute_id;
810 	args.arg1 = value;
811 
812 	ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
813 				    (unsigned char *)&args, sizeof(args), NULL);
814 	if (ret)
815 		return ret;
816 
817 	return count;
818 };
819 
820 /**
821  * attr_current_value_show() - Get the current value of the given attribute
822  * @kobj: Pointer to the driver object.
823  * @kattr: Pointer to the attribute calling this function.
824  * @buf: The buffer to write to.
825  * @tunable_attr: The attribute to be read.
826  *
827  * Retrieves the value of the given attribute for the current smartfan profile.
828  * The current smartfan profile is retrieved from the lenovo-wmi-gamezone driver.
829  * This function is intended to be generic so it can be called from any integer
830  * attribute's "_show" function.
831  *
832  * If the WMI is success the sysfs attribute is notified.
833  *
834  * Return: Either number of characters written to buf, or an error code.
835  */
attr_current_value_show(struct kobject * kobj,struct kobj_attribute * kattr,char * buf,struct tunable_attr_01 * tunable_attr)836 static ssize_t attr_current_value_show(struct kobject *kobj,
837 				       struct kobj_attribute *kattr, char *buf,
838 				       struct tunable_attr_01 *tunable_attr)
839 {
840 	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
841 	struct wmi_method_args_32 args;
842 	enum thermal_mode mode;
843 	u32 attribute_id;
844 	int retval;
845 	int ret;
846 
847 	ret = lwmi_om_notifier_call(&mode);
848 	if (ret)
849 		return ret;
850 
851 	attribute_id =
852 		FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, tunable_attr->device_id) |
853 		FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, tunable_attr->feature_id) |
854 		FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) |
855 		FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, tunable_attr->type_id);
856 
857 	args.arg0 = attribute_id;
858 
859 	ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET,
860 				    (unsigned char *)&args, sizeof(args),
861 				    &retval);
862 	if (ret)
863 		return ret;
864 
865 	return sysfs_emit(buf, "%d\n", retval);
866 }
867 
868 /* Lenovo WMI Other Mode Attribute macros */
869 #define __LWMI_ATTR_RO(_func, _name)                                  \
870 	{                                                             \
871 		.attr = { .name = __stringify(_name), .mode = 0444 }, \
872 		.show = _func##_##_name##_show,                       \
873 	}
874 
875 #define __LWMI_ATTR_RO_AS(_name, _show)                               \
876 	{                                                             \
877 		.attr = { .name = __stringify(_name), .mode = 0444 }, \
878 		.show = _show,                                        \
879 	}
880 
881 #define __LWMI_ATTR_RW(_func, _name) \
882 	__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
883 
884 /* Shows a formatted static variable */
885 #define __LWMI_ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                     \
886 	static ssize_t _attrname##_##_prop##_show(                             \
887 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
888 	{                                                                      \
889 		return sysfs_emit(buf, _fmt, _val);                            \
890 	}                                                                      \
891 	static struct kobj_attribute attr_##_attrname##_##_prop =              \
892 		__LWMI_ATTR_RO(_attrname, _prop)
893 
894 /* Attribute current value read/write */
895 #define __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname)                          \
896 	static ssize_t _attrname##_current_value_store(                        \
897 		struct kobject *kobj, struct kobj_attribute *kattr,            \
898 		const char *buf, size_t count)                                 \
899 	{                                                                      \
900 		return attr_current_value_store(kobj, kattr, buf, count,       \
901 						&_attrname);                   \
902 	}                                                                      \
903 	static ssize_t _attrname##_current_value_show(                         \
904 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
905 	{                                                                      \
906 		return attr_current_value_show(kobj, kattr, buf, &_attrname);  \
907 	}                                                                      \
908 	static struct kobj_attribute attr_##_attrname##_current_value =        \
909 		__LWMI_ATTR_RW(_attrname, current_value)
910 
911 /* Attribute property read only */
912 #define __LWMI_TUNABLE_RO_CAP01(_prop, _attrname, _prop_type)                  \
913 	static ssize_t _attrname##_##_prop##_show(                             \
914 		struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
915 	{                                                                      \
916 		return attr_capdata01_show(kobj, kattr, buf, &_attrname,       \
917 					   _prop_type);                        \
918 	}                                                                      \
919 	static struct kobj_attribute attr_##_attrname##_##_prop =              \
920 		__LWMI_ATTR_RO(_attrname, _prop)
921 
922 #define LWMI_ATTR_GROUP_TUNABLE_CAP01(_attrname, _fsname, _dispname)      \
923 	__LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname);                    \
924 	__LWMI_TUNABLE_RO_CAP01(default_value, _attrname, DEFAULT_VAL);   \
925 	__LWMI_ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
926 	__LWMI_TUNABLE_RO_CAP01(max_value, _attrname, MAX_VAL);           \
927 	__LWMI_TUNABLE_RO_CAP01(min_value, _attrname, MIN_VAL);           \
928 	__LWMI_TUNABLE_RO_CAP01(scalar_increment, _attrname, STEP_VAL);   \
929 	static struct kobj_attribute attr_##_attrname##_type =            \
930 		__LWMI_ATTR_RO_AS(type, int_type_show);                   \
931 	static struct attribute *_attrname##_attrs[] = {                  \
932 		&attr_##_attrname##_current_value.attr,                   \
933 		&attr_##_attrname##_default_value.attr,                   \
934 		&attr_##_attrname##_display_name.attr,                    \
935 		&attr_##_attrname##_max_value.attr,                       \
936 		&attr_##_attrname##_min_value.attr,                       \
937 		&attr_##_attrname##_scalar_increment.attr,                \
938 		&attr_##_attrname##_type.attr,                            \
939 		NULL,                                                     \
940 	};                                                                \
941 	static const struct attribute_group _attrname##_attr_group = {    \
942 		.name = _fsname, .attrs = _attrname##_attrs               \
943 	}
944 
945 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
946 			      "Set the CPU sustained power limit");
947 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
948 			      "Set the CPU slow package power tracking limit");
949 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
950 			      "Set the CPU fast package power tracking limit");
951 
952 static struct capdata01_attr_group cd01_attr_groups[] = {
953 	{ &ppt_pl1_spl_attr_group, &ppt_pl1_spl },
954 	{ &ppt_pl2_sppt_attr_group, &ppt_pl2_sppt },
955 	{ &ppt_pl3_fppt_attr_group, &ppt_pl3_fppt },
956 	{},
957 };
958 
959 /**
960  * lwmi_om_fw_attr_add() - Register all firmware_attributes_class members
961  * @priv: The Other Mode driver data.
962  *
963  * Return: Either 0, or an error code.
964  */
lwmi_om_fw_attr_add(struct lwmi_om_priv * priv)965 static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
966 {
967 	unsigned int i;
968 	int err;
969 
970 	priv->ida_id = ida_alloc(&lwmi_om_ida, GFP_KERNEL);
971 	if (priv->ida_id < 0)
972 		return priv->ida_id;
973 
974 	priv->fw_attr_dev = device_create(&firmware_attributes_class, NULL,
975 					  MKDEV(0, 0), NULL, "%s-%u",
976 					  LWMI_OM_FW_ATTR_BASE_PATH,
977 					  priv->ida_id);
978 	if (IS_ERR(priv->fw_attr_dev)) {
979 		err = PTR_ERR(priv->fw_attr_dev);
980 		goto err_free_ida;
981 	}
982 
983 	priv->fw_attr_kset = kset_create_and_add("attributes", NULL,
984 						 &priv->fw_attr_dev->kobj);
985 	if (!priv->fw_attr_kset) {
986 		err = -ENOMEM;
987 		goto err_destroy_classdev;
988 	}
989 
990 	for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
991 		err = sysfs_create_group(&priv->fw_attr_kset->kobj,
992 					 cd01_attr_groups[i].attr_group);
993 		if (err)
994 			goto err_remove_groups;
995 
996 		cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev;
997 	}
998 	return 0;
999 
1000 err_remove_groups:
1001 	while (i--)
1002 		sysfs_remove_group(&priv->fw_attr_kset->kobj,
1003 				   cd01_attr_groups[i].attr_group);
1004 
1005 	kset_unregister(priv->fw_attr_kset);
1006 
1007 err_destroy_classdev:
1008 	device_unregister(priv->fw_attr_dev);
1009 
1010 err_free_ida:
1011 	ida_free(&lwmi_om_ida, priv->ida_id);
1012 	return err;
1013 }
1014 
1015 /**
1016  * lwmi_om_fw_attr_remove() - Unregister all capability data attribute groups
1017  * @priv: the lenovo-wmi-other driver data.
1018  */
lwmi_om_fw_attr_remove(struct lwmi_om_priv * priv)1019 static void lwmi_om_fw_attr_remove(struct lwmi_om_priv *priv)
1020 {
1021 	for (unsigned int i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++)
1022 		sysfs_remove_group(&priv->fw_attr_kset->kobj,
1023 				   cd01_attr_groups[i].attr_group);
1024 
1025 	kset_unregister(priv->fw_attr_kset);
1026 	device_unregister(priv->fw_attr_dev);
1027 }
1028 
1029 /* ======== Self (master: lenovo-wmi-other) ======== */
1030 
1031 /**
1032  * lwmi_om_master_bind() - Bind all components of the other mode driver
1033  * @dev: The lenovo-wmi-other driver basic device.
1034  *
1035  * Call component_bind_all to bind the lenovo-wmi-capdata devices to the
1036  * lenovo-wmi-other master driver, with a callback to collect fan info from
1037  * capdata_fan. On success, assign the capability data list pointers to the
1038  * driver data struct for later access. These pointers are only valid while the
1039  * capdata interfaces exist. Finally, collect fan info from capdata00 and
1040  * register all firmware attribute groups. Note that the HWMON device is
1041  * registered only if all fan info is collected. Hence, it is not registered
1042  * here. See lwmi_om_fan_info_collect_cd00() and
1043  * lwmi_om_fan_info_collect_cd_fan().
1044  *
1045  * Return: 0 on success, or an error code.
1046  */
lwmi_om_master_bind(struct device * dev)1047 static int lwmi_om_master_bind(struct device *dev)
1048 {
1049 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1050 	struct lwmi_cd_binder binder = {
1051 		.cd_fan_list_cb = lwmi_om_fan_info_collect_cd_fan,
1052 	};
1053 	int ret;
1054 
1055 	lwmi_om_fan_info_init(priv);
1056 
1057 	ret = component_bind_all(dev, &binder);
1058 	if (ret)
1059 		return ret;
1060 
1061 	priv->cd00_list = binder.cd00_list;
1062 	priv->cd01_list = binder.cd01_list;
1063 	if (!priv->cd00_list || !priv->cd01_list)
1064 		return -ENODEV;
1065 
1066 	lwmi_om_fan_info_collect_cd00(priv);
1067 
1068 	return lwmi_om_fw_attr_add(priv);
1069 }
1070 
1071 /**
1072  * lwmi_om_master_unbind() - Unbind all components of the other mode driver
1073  * @dev: The lenovo-wmi-other driver basic device
1074  *
1075  * Unregister all firmware attribute groups and the HWMON device. Then call
1076  * component_unbind_all to unbind lenovo-wmi-capdata devices from the
1077  * lenovo-wmi-other master driver.
1078  */
lwmi_om_master_unbind(struct device * dev)1079 static void lwmi_om_master_unbind(struct device *dev)
1080 {
1081 	struct lwmi_om_priv *priv = dev_get_drvdata(dev);
1082 
1083 	lwmi_om_fw_attr_remove(priv);
1084 
1085 	lwmi_om_hwmon_remove(priv);
1086 
1087 	component_unbind_all(dev, NULL);
1088 }
1089 
1090 static const struct component_master_ops lwmi_om_master_ops = {
1091 	.bind = lwmi_om_master_bind,
1092 	.unbind = lwmi_om_master_unbind,
1093 };
1094 
lwmi_other_probe(struct wmi_device * wdev,const void * context)1095 static int lwmi_other_probe(struct wmi_device *wdev, const void *context)
1096 {
1097 	struct component_match *master_match = NULL;
1098 	struct lwmi_om_priv *priv;
1099 
1100 	priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
1101 	if (!priv)
1102 		return -ENOMEM;
1103 
1104 	/* Sentinel for on-demand ida_free(). */
1105 	priv->ida_id = -EIDRM;
1106 
1107 	priv->wdev = wdev;
1108 	dev_set_drvdata(&wdev->dev, priv);
1109 
1110 	lwmi_cd_match_add_all(&wdev->dev, &master_match);
1111 	if (IS_ERR(master_match))
1112 		return PTR_ERR(master_match);
1113 
1114 	return component_master_add_with_match(&wdev->dev, &lwmi_om_master_ops,
1115 					       master_match);
1116 }
1117 
lwmi_other_remove(struct wmi_device * wdev)1118 static void lwmi_other_remove(struct wmi_device *wdev)
1119 {
1120 	struct lwmi_om_priv *priv = dev_get_drvdata(&wdev->dev);
1121 
1122 	component_master_del(&wdev->dev, &lwmi_om_master_ops);
1123 
1124 	/* No IDA to free if the driver is never bound to its components. */
1125 	if (priv->ida_id >= 0)
1126 		ida_free(&lwmi_om_ida, priv->ida_id);
1127 }
1128 
1129 static const struct wmi_device_id lwmi_other_id_table[] = {
1130 	{ LENOVO_OTHER_MODE_GUID, NULL },
1131 	{}
1132 };
1133 
1134 static struct wmi_driver lwmi_other_driver = {
1135 	.driver = {
1136 		.name = "lenovo_wmi_other",
1137 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
1138 	},
1139 	.id_table = lwmi_other_id_table,
1140 	.probe = lwmi_other_probe,
1141 	.remove = lwmi_other_remove,
1142 	.no_singleton = true,
1143 };
1144 
1145 module_wmi_driver(lwmi_other_driver);
1146 
1147 MODULE_IMPORT_NS("LENOVO_WMI_CAPDATA");
1148 MODULE_IMPORT_NS("LENOVO_WMI_HELPERS");
1149 MODULE_DEVICE_TABLE(wmi, lwmi_other_id_table);
1150 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
1151 MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
1152 MODULE_DESCRIPTION("Lenovo Other Mode WMI Driver");
1153 MODULE_LICENSE("GPL");
1154