1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Lenovo Capability Data WMI Data Block driver.
4 *
5 * Lenovo Capability Data provides information on tunable attributes used by
6 * the "Other Mode" WMI interface.
7 *
8 * Capability Data 00 includes if the attribute is supported by the hardware,
9 * and the default_value. All attributes are independent of thermal modes.
10 *
11 * Capability Data 01 includes if the attribute is supported by the hardware,
12 * and the default_value, max_value, min_value, and step increment. Each
13 * attribute has multiple pages, one for each of the thermal modes managed by
14 * the Gamezone interface.
15 *
16 * Fan Test Data includes the max/min fan speed RPM for each fan. This is
17 * reference data for self-test. If the fan is in good condition, it is capable
18 * to spin faster than max RPM or slower than min RPM.
19 *
20 * Copyright (C) 2025 Derek J. Clark <derekjohn.clark@gmail.com>
21 * - Initial implementation (formerly named lenovo-wmi-capdata01)
22 *
23 * Copyright (C) 2025 Rong Zhang <i@rong.moe>
24 * - Unified implementation
25 */
26
27 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
28
29 #include <linux/acpi.h>
30 #include <linux/bitfield.h>
31 #include <linux/bug.h>
32 #include <linux/cleanup.h>
33 #include <linux/component.h>
34 #include <linux/container_of.h>
35 #include <linux/device.h>
36 #include <linux/dev_printk.h>
37 #include <linux/err.h>
38 #include <linux/export.h>
39 #include <linux/gfp_types.h>
40 #include <linux/limits.h>
41 #include <linux/module.h>
42 #include <linux/mutex.h>
43 #include <linux/mutex_types.h>
44 #include <linux/notifier.h>
45 #include <linux/overflow.h>
46 #include <linux/stddef.h>
47 #include <linux/types.h>
48 #include <linux/wmi.h>
49
50 #include "wmi-capdata.h"
51
52 #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"
53 #define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
54 #define LENOVO_FAN_TEST_DATA_GUID "B642801B-3D21-45DE-90AE-6E86F164FB21"
55
56 #define ACPI_AC_CLASS "ac_adapter"
57 #define ACPI_AC_NOTIFY_STATUS 0x80
58
59 #define LWMI_FEATURE_ID_FAN_TEST 0x05
60
61 #define LWMI_ATTR_ID_FAN_TEST \
62 (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \
63 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST))
64
65 enum lwmi_cd_type {
66 LENOVO_CAPABILITY_DATA_00,
67 LENOVO_CAPABILITY_DATA_01,
68 LENOVO_FAN_TEST_DATA,
69 CD_TYPE_NONE = -1,
70 };
71
72 #define LWMI_CD_TABLE_ITEM(_type) \
73 [_type] = { \
74 .name = #_type, \
75 .type = _type, \
76 }
77
78 static const struct lwmi_cd_info {
79 const char *name;
80 enum lwmi_cd_type type;
81 } lwmi_cd_table[] = {
82 LWMI_CD_TABLE_ITEM(LENOVO_CAPABILITY_DATA_00),
83 LWMI_CD_TABLE_ITEM(LENOVO_CAPABILITY_DATA_01),
84 LWMI_CD_TABLE_ITEM(LENOVO_FAN_TEST_DATA),
85 };
86
87 struct lwmi_cd_priv {
88 struct notifier_block acpi_nb; /* ACPI events */
89 struct wmi_device *wdev;
90 struct cd_list *list;
91
92 /*
93 * A capdata device may be a component master of another capdata device.
94 * E.g., lenovo-wmi-other <-> capdata00 <-> capdata_fan
95 * |- master |- component
96 * |- sub-master
97 * |- sub-component
98 */
99 struct lwmi_cd_sub_master_priv {
100 struct device *master_dev;
101 cd_list_cb_t master_cb;
102 struct cd_list *sub_component_list; /* ERR_PTR(-ENODEV) implies no sub-component. */
103 bool registered; /* Has the sub-master been registered? */
104 } *sub_master;
105 };
106
107 struct cd_list {
108 struct mutex list_mutex; /* list R/W mutex */
109 enum lwmi_cd_type type;
110 u8 count;
111
112 union {
113 DECLARE_FLEX_ARRAY(struct capdata00, cd00);
114 DECLARE_FLEX_ARRAY(struct capdata01, cd01);
115 DECLARE_FLEX_ARRAY(struct capdata_fan, cd_fan);
116 };
117 };
118
119 static struct wmi_driver lwmi_cd_driver;
120
121 /**
122 * lwmi_cd_match() - Match rule for the master driver.
123 * @dev: Pointer to the capability data parent device.
124 * @type: Pointer to capability data type (enum lwmi_cd_type *) to match.
125 *
126 * Return: int.
127 */
lwmi_cd_match(struct device * dev,void * type)128 static int lwmi_cd_match(struct device *dev, void *type)
129 {
130 struct lwmi_cd_priv *priv;
131
132 if (dev->driver != &lwmi_cd_driver.driver)
133 return false;
134
135 priv = dev_get_drvdata(dev);
136 return priv->list->type == *(enum lwmi_cd_type *)type;
137 }
138
139 /**
140 * lwmi_cd_match_add_all() - Add all match rule for the master driver.
141 * @master: Pointer to the master device.
142 * @matchptr: Pointer to the returned component_match pointer.
143 *
144 * Adds all component matches to the list stored in @matchptr for the @master
145 * device. @matchptr must be initialized to NULL.
146 */
lwmi_cd_match_add_all(struct device * master,struct component_match ** matchptr)147 void lwmi_cd_match_add_all(struct device *master, struct component_match **matchptr)
148 {
149 int i;
150
151 if (WARN_ON(*matchptr))
152 return;
153
154 for (i = 0; i < ARRAY_SIZE(lwmi_cd_table); i++) {
155 /* Skip sub-components. */
156 if (lwmi_cd_table[i].type == LENOVO_FAN_TEST_DATA)
157 continue;
158
159 component_match_add(master, matchptr, lwmi_cd_match,
160 (void *)&lwmi_cd_table[i].type);
161 if (IS_ERR(*matchptr))
162 return;
163 }
164 }
165 EXPORT_SYMBOL_NS_GPL(lwmi_cd_match_add_all, "LENOVO_WMI_CAPDATA");
166
167 /**
168 * lwmi_cd_call_master_cb() - Call the master callback for the sub-component.
169 * @priv: Pointer to the capability data private data.
170 *
171 * Call the master callback and pass the sub-component list to it if the
172 * dependency chain (master <-> sub-master <-> sub-component) is complete.
173 */
lwmi_cd_call_master_cb(struct lwmi_cd_priv * priv)174 static void lwmi_cd_call_master_cb(struct lwmi_cd_priv *priv)
175 {
176 struct cd_list *sub_component_list = priv->sub_master->sub_component_list;
177
178 /*
179 * Call the callback only if the dependency chain is ready:
180 * - Binding between master and sub-master: fills master_dev and master_cb
181 * - Binding between sub-master and sub-component: fills sub_component_list
182 *
183 * If a binding has been unbound before the other binding is bound, the
184 * corresponding members filled by the former are guaranteed to be cleared.
185 *
186 * This function is only called in bind callbacks, and the component
187 * framework guarantees bind/unbind callbacks may never execute
188 * simultaneously, which implies that it's impossible to have a race
189 * condition.
190 *
191 * Hence, this check is sufficient to ensure that the callback is called
192 * at most once and with the correct state, without relying on a specific
193 * sequence of binding establishment.
194 */
195 if (!sub_component_list ||
196 !priv->sub_master->master_dev ||
197 !priv->sub_master->master_cb)
198 return;
199
200 if (PTR_ERR(sub_component_list) == -ENODEV)
201 sub_component_list = NULL;
202 else if (WARN_ON(IS_ERR(sub_component_list)))
203 return;
204
205 priv->sub_master->master_cb(priv->sub_master->master_dev,
206 sub_component_list);
207
208 /*
209 * Userspace may unbind a device from its driver and bind it again
210 * through sysfs. Let's call this operation "reprobe" to distinguish it
211 * from component "rebind".
212 *
213 * When reprobing capdata00/01 or the master device, the master device
214 * is unbound from us with appropriate cleanup before we bind to it and
215 * call master_cb. Everything is fine in this case.
216 *
217 * When reprobing capdata_fan, the master device has never been unbound
218 * from us (hence no cleanup is done)[1], but we call master_cb the
219 * second time. To solve this issue, we clear master_cb and master_dev
220 * so we won't call master_cb twice while a binding is still complete.
221 *
222 * Note that we can't clear sub_component_list, otherwise reprobing
223 * capdata01 or the master device causes master_cb to be never called
224 * after we rebind to the master device.
225 *
226 * [1]: The master device does not need capdata_fan in run time, so
227 * losing capdata_fan will not break the binding to the master device.
228 */
229 priv->sub_master->master_cb = NULL;
230 priv->sub_master->master_dev = NULL;
231 }
232
233 /**
234 * lwmi_cd_component_bind() - Bind component to master device.
235 * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
236 * @om_dev: Pointer to the lenovo-wmi-other driver parent device.
237 * @data: lwmi_cd_binder object pointer used to return the capability data.
238 *
239 * On lenovo-wmi-other's master bind, provide a pointer to the local capdata
240 * list. This is used to call lwmi_cd*_get_data to look up attribute data
241 * from the lenovo-wmi-other driver.
242 *
243 * If cd_dev is a sub-master, try to call the master callback.
244 *
245 * Return: 0
246 */
lwmi_cd_component_bind(struct device * cd_dev,struct device * om_dev,void * data)247 static int lwmi_cd_component_bind(struct device *cd_dev,
248 struct device *om_dev, void *data)
249 {
250 struct lwmi_cd_priv *priv = dev_get_drvdata(cd_dev);
251 struct lwmi_cd_binder *binder = data;
252
253 switch (priv->list->type) {
254 case LENOVO_CAPABILITY_DATA_00:
255 binder->cd00_list = priv->list;
256
257 priv->sub_master->master_dev = om_dev;
258 priv->sub_master->master_cb = binder->cd_fan_list_cb;
259 lwmi_cd_call_master_cb(priv);
260
261 break;
262 case LENOVO_CAPABILITY_DATA_01:
263 binder->cd01_list = priv->list;
264 break;
265 default:
266 return -EINVAL;
267 }
268
269 return 0;
270 }
271
272 /**
273 * lwmi_cd_component_unbind() - Unbind component to master device.
274 * @cd_dev: Pointer to the lenovo-wmi-capdata driver parent device.
275 * @om_dev: Pointer to the lenovo-wmi-other driver parent device.
276 * @data: Unused.
277 *
278 * If cd_dev is a sub-master, clear the collected data from the master device to
279 * prevent the binding establishment between the sub-master and the sub-
280 * component (if it's about to happen) from calling the master callback.
281 */
lwmi_cd_component_unbind(struct device * cd_dev,struct device * om_dev,void * data)282 static void lwmi_cd_component_unbind(struct device *cd_dev,
283 struct device *om_dev, void *data)
284 {
285 struct lwmi_cd_priv *priv = dev_get_drvdata(cd_dev);
286
287 switch (priv->list->type) {
288 case LENOVO_CAPABILITY_DATA_00:
289 priv->sub_master->master_dev = NULL;
290 priv->sub_master->master_cb = NULL;
291 return;
292 default:
293 return;
294 }
295 }
296
297 static const struct component_ops lwmi_cd_component_ops = {
298 .bind = lwmi_cd_component_bind,
299 .unbind = lwmi_cd_component_unbind,
300 };
301
302 /**
303 * lwmi_cd_sub_master_bind() - Bind sub-component of sub-master device
304 * @dev: The sub-master capdata basic device.
305 *
306 * Call component_bind_all to bind the sub-component device to the sub-master
307 * device. On success, collect the pointer to the sub-component list and try
308 * to call the master callback.
309 *
310 * Return: 0 on success, or an error code.
311 */
lwmi_cd_sub_master_bind(struct device * dev)312 static int lwmi_cd_sub_master_bind(struct device *dev)
313 {
314 struct lwmi_cd_priv *priv = dev_get_drvdata(dev);
315 struct cd_list *sub_component_list;
316 int ret;
317
318 ret = component_bind_all(dev, &sub_component_list);
319 if (ret)
320 return ret;
321
322 priv->sub_master->sub_component_list = sub_component_list;
323 lwmi_cd_call_master_cb(priv);
324
325 return 0;
326 }
327
328 /**
329 * lwmi_cd_sub_master_unbind() - Unbind sub-component of sub-master device
330 * @dev: The sub-master capdata basic device
331 *
332 * Clear the collected pointer to the sub-component list to prevent the binding
333 * establishment between the sub-master and the sub-component (if it's about to
334 * happen) from calling the master callback. Then, call component_unbind_all to
335 * unbind the sub-component device from the sub-master device.
336 */
lwmi_cd_sub_master_unbind(struct device * dev)337 static void lwmi_cd_sub_master_unbind(struct device *dev)
338 {
339 struct lwmi_cd_priv *priv = dev_get_drvdata(dev);
340
341 priv->sub_master->sub_component_list = NULL;
342
343 component_unbind_all(dev, NULL);
344 }
345
346 static const struct component_master_ops lwmi_cd_sub_master_ops = {
347 .bind = lwmi_cd_sub_master_bind,
348 .unbind = lwmi_cd_sub_master_unbind,
349 };
350
351 /**
352 * lwmi_cd_sub_master_add() - Register a sub-master with its sub-component
353 * @priv: Pointer to the sub-master capdata device private data.
354 * @sub_component_type: Type of the sub-component.
355 *
356 * Match the sub-component type and register the current capdata device as a
357 * sub-master. If the given sub-component type is CD_TYPE_NONE, mark the sub-
358 * component as non-existent without registering sub-master.
359 *
360 * Return: 0 on success, or an error code.
361 */
lwmi_cd_sub_master_add(struct lwmi_cd_priv * priv,enum lwmi_cd_type sub_component_type)362 static int lwmi_cd_sub_master_add(struct lwmi_cd_priv *priv,
363 enum lwmi_cd_type sub_component_type)
364 {
365 struct component_match *master_match = NULL;
366 int ret;
367
368 priv->sub_master = devm_kzalloc(&priv->wdev->dev, sizeof(*priv->sub_master), GFP_KERNEL);
369 if (!priv->sub_master)
370 return -ENOMEM;
371
372 if (sub_component_type == CD_TYPE_NONE) {
373 /* The master callback will be called with NULL on bind. */
374 priv->sub_master->sub_component_list = ERR_PTR(-ENODEV);
375 priv->sub_master->registered = false;
376 return 0;
377 }
378
379 /*
380 * lwmi_cd_match() needs a pointer to enum lwmi_cd_type, but on-stack
381 * data cannot be used here. Steal one from lwmi_cd_table.
382 */
383 component_match_add(&priv->wdev->dev, &master_match, lwmi_cd_match,
384 (void *)&lwmi_cd_table[sub_component_type].type);
385 if (IS_ERR(master_match))
386 return PTR_ERR(master_match);
387
388 ret = component_master_add_with_match(&priv->wdev->dev, &lwmi_cd_sub_master_ops,
389 master_match);
390 if (ret)
391 return ret;
392
393 priv->sub_master->registered = true;
394 return 0;
395 }
396
397 /**
398 * lwmi_cd_sub_master_del() - Unregister a sub-master if it's registered
399 * @priv: Pointer to the sub-master capdata device private data.
400 */
lwmi_cd_sub_master_del(struct lwmi_cd_priv * priv)401 static void lwmi_cd_sub_master_del(struct lwmi_cd_priv *priv)
402 {
403 if (!priv->sub_master->registered)
404 return;
405
406 component_master_del(&priv->wdev->dev, &lwmi_cd_sub_master_ops);
407 priv->sub_master->registered = false;
408 }
409
410 /**
411 * lwmi_cd_sub_component_bind() - Bind sub-component to sub-master device.
412 * @sc_dev: Pointer to the sub-component capdata parent device.
413 * @sm_dev: Pointer to the sub-master capdata parent device.
414 * @data: Pointer used to return the capability data list pointer.
415 *
416 * On sub-master's bind, provide a pointer to the local capdata list.
417 * This is used by the sub-master to call the master callback.
418 *
419 * Return: 0
420 */
lwmi_cd_sub_component_bind(struct device * sc_dev,struct device * sm_dev,void * data)421 static int lwmi_cd_sub_component_bind(struct device *sc_dev,
422 struct device *sm_dev, void *data)
423 {
424 struct lwmi_cd_priv *priv = dev_get_drvdata(sc_dev);
425 struct cd_list **listp = data;
426
427 *listp = priv->list;
428
429 return 0;
430 }
431
432 static const struct component_ops lwmi_cd_sub_component_ops = {
433 .bind = lwmi_cd_sub_component_bind,
434 };
435
436 /*
437 * lwmi_cd*_get_data - Get the data of the specified attribute
438 * @list: The lenovo-wmi-capdata pointer to its cd_list struct.
439 * @attribute_id: The capdata attribute ID to be found.
440 * @output: Pointer to a capdata* struct to return the data.
441 *
442 * Retrieves the capability data struct pointer for the given
443 * attribute.
444 *
445 * Return: 0 on success, or -EINVAL.
446 */
447 #define DEF_LWMI_CDXX_GET_DATA(_cdxx, _cd_type, _output_t) \
448 int lwmi_##_cdxx##_get_data(struct cd_list *list, u32 attribute_id, _output_t *output) \
449 { \
450 u8 idx; \
451 \
452 if (WARN_ON(list->type != _cd_type)) \
453 return -EINVAL; \
454 \
455 guard(mutex)(&list->list_mutex); \
456 for (idx = 0; idx < list->count; idx++) { \
457 if (list->_cdxx[idx].id != attribute_id) \
458 continue; \
459 memcpy(output, &list->_cdxx[idx], sizeof(list->_cdxx[idx])); \
460 return 0; \
461 } \
462 return -EINVAL; \
463 }
464
465 DEF_LWMI_CDXX_GET_DATA(cd00, LENOVO_CAPABILITY_DATA_00, struct capdata00);
466 EXPORT_SYMBOL_NS_GPL(lwmi_cd00_get_data, "LENOVO_WMI_CAPDATA");
467
468 DEF_LWMI_CDXX_GET_DATA(cd01, LENOVO_CAPABILITY_DATA_01, struct capdata01);
469 EXPORT_SYMBOL_NS_GPL(lwmi_cd01_get_data, "LENOVO_WMI_CAPDATA");
470
471 DEF_LWMI_CDXX_GET_DATA(cd_fan, LENOVO_FAN_TEST_DATA, struct capdata_fan);
472 EXPORT_SYMBOL_NS_GPL(lwmi_cd_fan_get_data, "LENOVO_WMI_CAPDATA");
473
474 /**
475 * lwmi_cd_cache() - Cache all WMI data block information
476 * @priv: lenovo-wmi-capdata driver data.
477 *
478 * Loop through each WMI data block and cache the data.
479 *
480 * Return: 0 on success, or an error.
481 */
lwmi_cd_cache(struct lwmi_cd_priv * priv)482 static int lwmi_cd_cache(struct lwmi_cd_priv *priv)
483 {
484 size_t size;
485 int idx;
486 void *p;
487
488 switch (priv->list->type) {
489 case LENOVO_CAPABILITY_DATA_00:
490 p = &priv->list->cd00[0];
491 size = sizeof(priv->list->cd00[0]);
492 break;
493 case LENOVO_CAPABILITY_DATA_01:
494 p = &priv->list->cd01[0];
495 size = sizeof(priv->list->cd01[0]);
496 break;
497 case LENOVO_FAN_TEST_DATA:
498 /* Done by lwmi_cd_alloc() => lwmi_cd_fan_list_alloc_cache(). */
499 return 0;
500 default:
501 return -EINVAL;
502 }
503
504 guard(mutex)(&priv->list->list_mutex);
505 for (idx = 0; idx < priv->list->count; idx++, p += size) {
506 union acpi_object *ret_obj __free(kfree) = NULL;
507
508 ret_obj = wmidev_block_query(priv->wdev, idx);
509 if (!ret_obj)
510 return -ENODEV;
511
512 if (ret_obj->type != ACPI_TYPE_BUFFER ||
513 ret_obj->buffer.length < size)
514 continue;
515
516 memcpy(p, ret_obj->buffer.pointer, size);
517 }
518
519 return 0;
520 }
521
522 /**
523 * lwmi_cd_fan_list_alloc_cache() - Alloc and cache Fan Test Data list
524 * @priv: lenovo-wmi-capdata driver data.
525 * @listptr: Pointer to returned cd_list pointer.
526 *
527 * Return: count of fans found, or an error.
528 */
lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv * priv,struct cd_list ** listptr)529 static int lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv *priv, struct cd_list **listptr)
530 {
531 struct cd_list *list;
532 size_t size;
533 u32 count;
534 int idx;
535
536 /* Emit unaligned access to u8 buffer with __packed. */
537 struct cd_fan_block {
538 u32 nr;
539 u32 data[]; /* id[nr], max_rpm[nr], min_rpm[nr] */
540 } __packed * block;
541
542 union acpi_object *ret_obj __free(kfree) = wmidev_block_query(priv->wdev, 0);
543 if (!ret_obj)
544 return -ENODEV;
545
546 if (ret_obj->type == ACPI_TYPE_BUFFER) {
547 block = (struct cd_fan_block *)ret_obj->buffer.pointer;
548 size = ret_obj->buffer.length;
549
550 count = size >= sizeof(*block) ? block->nr : 0;
551 if (size < struct_size(block, data, count * 3)) {
552 dev_warn(&priv->wdev->dev,
553 "incomplete fan test data block: %zu < %zu, ignoring\n",
554 size, struct_size(block, data, count * 3));
555 count = 0;
556 } else if (count > U8_MAX) {
557 dev_warn(&priv->wdev->dev,
558 "too many fans reported: %u > %u, truncating\n",
559 count, U8_MAX);
560 count = U8_MAX;
561 }
562 } else {
563 /*
564 * This is usually caused by a dummy ACPI method. Do not return an error
565 * as failing to probe this device will result in sub-master device being
566 * unbound. This behavior aligns with lwmi_cd_cache().
567 */
568 count = 0;
569 }
570
571 list = devm_kzalloc(&priv->wdev->dev, struct_size(list, cd_fan, count), GFP_KERNEL);
572 if (!list)
573 return -ENOMEM;
574
575 for (idx = 0; idx < count; idx++) {
576 /* Do not calculate array index using count, as it may be truncated. */
577 list->cd_fan[idx] = (struct capdata_fan) {
578 .id = block->data[idx],
579 .max_rpm = block->data[idx + block->nr],
580 .min_rpm = block->data[idx + (2 * block->nr)],
581 };
582 }
583
584 *listptr = list;
585 return count;
586 }
587
588 /**
589 * lwmi_cd_alloc() - Allocate a cd_list struct in drvdata
590 * @priv: lenovo-wmi-capdata driver data.
591 * @type: The type of capability data.
592 *
593 * Allocate a cd_list struct large enough to contain data from all WMI data
594 * blocks provided by the interface.
595 *
596 * Return: 0 on success, or an error.
597 */
lwmi_cd_alloc(struct lwmi_cd_priv * priv,enum lwmi_cd_type type)598 static int lwmi_cd_alloc(struct lwmi_cd_priv *priv, enum lwmi_cd_type type)
599 {
600 struct cd_list *list;
601 size_t list_size;
602 int count, ret;
603
604 count = wmidev_instance_count(priv->wdev);
605
606 switch (type) {
607 case LENOVO_CAPABILITY_DATA_00:
608 list_size = struct_size(list, cd00, count);
609 break;
610 case LENOVO_CAPABILITY_DATA_01:
611 list_size = struct_size(list, cd01, count);
612 break;
613 case LENOVO_FAN_TEST_DATA:
614 count = lwmi_cd_fan_list_alloc_cache(priv, &list);
615 if (count < 0)
616 return count;
617
618 goto got_list;
619 default:
620 return -EINVAL;
621 }
622
623 list = devm_kzalloc(&priv->wdev->dev, list_size, GFP_KERNEL);
624 if (!list)
625 return -ENOMEM;
626
627 got_list:
628 ret = devm_mutex_init(&priv->wdev->dev, &list->list_mutex);
629 if (ret)
630 return ret;
631
632 list->type = type;
633 list->count = count;
634 priv->list = list;
635
636 return 0;
637 }
638
639 /**
640 * lwmi_cd_setup() - Cache all WMI data block information
641 * @priv: lenovo-wmi-capdata driver data.
642 * @type: The type of capability data.
643 *
644 * Allocate a cd_list struct large enough to contain data from all WMI data
645 * blocks provided by the interface. Then loop through each data block and
646 * cache the data.
647 *
648 * Return: 0 on success, or an error code.
649 */
lwmi_cd_setup(struct lwmi_cd_priv * priv,enum lwmi_cd_type type)650 static int lwmi_cd_setup(struct lwmi_cd_priv *priv, enum lwmi_cd_type type)
651 {
652 int ret;
653
654 ret = lwmi_cd_alloc(priv, type);
655 if (ret)
656 return ret;
657
658 return lwmi_cd_cache(priv);
659 }
660
661 /**
662 * lwmi_cd01_notifier_call() - Call method for cd01 notifier.
663 * block call chain.
664 * @nb: The notifier_block registered to lenovo-wmi-events driver.
665 * @action: Unused.
666 * @data: The ACPI event.
667 *
668 * For LWMI_EVENT_THERMAL_MODE, set current_mode and notify platform_profile
669 * of a change.
670 *
671 * Return: notifier_block status.
672 */
lwmi_cd01_notifier_call(struct notifier_block * nb,unsigned long action,void * data)673 static int lwmi_cd01_notifier_call(struct notifier_block *nb, unsigned long action,
674 void *data)
675 {
676 struct acpi_bus_event *event = data;
677 struct lwmi_cd_priv *priv;
678 int ret;
679
680 if (strcmp(event->device_class, ACPI_AC_CLASS) != 0)
681 return NOTIFY_DONE;
682
683 priv = container_of(nb, struct lwmi_cd_priv, acpi_nb);
684
685 switch (event->type) {
686 case ACPI_AC_NOTIFY_STATUS:
687 ret = lwmi_cd_cache(priv);
688 if (ret)
689 return NOTIFY_BAD;
690
691 return NOTIFY_OK;
692 default:
693 return NOTIFY_DONE;
694 }
695 }
696
697 /**
698 * lwmi_cd01_unregister() - Unregister the cd01 ACPI notifier_block.
699 * @data: The ACPI event notifier_block to unregister.
700 */
lwmi_cd01_unregister(void * data)701 static void lwmi_cd01_unregister(void *data)
702 {
703 struct notifier_block *acpi_nb = data;
704
705 unregister_acpi_notifier(acpi_nb);
706 }
707
lwmi_cd_probe(struct wmi_device * wdev,const void * context)708 static int lwmi_cd_probe(struct wmi_device *wdev, const void *context)
709 {
710 const struct lwmi_cd_info *info = context;
711 struct lwmi_cd_priv *priv;
712 int ret;
713
714 if (!info)
715 return -EINVAL;
716
717 priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
718 if (!priv)
719 return -ENOMEM;
720
721 priv->wdev = wdev;
722 dev_set_drvdata(&wdev->dev, priv);
723
724 ret = lwmi_cd_setup(priv, info->type);
725 if (ret)
726 goto out;
727
728 switch (info->type) {
729 case LENOVO_CAPABILITY_DATA_00: {
730 enum lwmi_cd_type sub_component_type = LENOVO_FAN_TEST_DATA;
731 struct capdata00 capdata00;
732
733 ret = lwmi_cd00_get_data(priv->list, LWMI_ATTR_ID_FAN_TEST, &capdata00);
734 if (ret || !(capdata00.supported & LWMI_SUPP_VALID)) {
735 dev_dbg(&wdev->dev, "capdata00 declares no fan test support\n");
736 sub_component_type = CD_TYPE_NONE;
737 }
738
739 /* Sub-master (capdata00) <-> sub-component (capdata_fan) */
740 ret = lwmi_cd_sub_master_add(priv, sub_component_type);
741 if (ret)
742 goto out;
743
744 /* Master (lenovo-wmi-other) <-> sub-master (capdata00) */
745 ret = component_add(&wdev->dev, &lwmi_cd_component_ops);
746 if (ret)
747 lwmi_cd_sub_master_del(priv);
748
749 goto out;
750 }
751 case LENOVO_CAPABILITY_DATA_01:
752 priv->acpi_nb.notifier_call = lwmi_cd01_notifier_call;
753
754 ret = register_acpi_notifier(&priv->acpi_nb);
755 if (ret)
756 goto out;
757
758 ret = devm_add_action_or_reset(&wdev->dev, lwmi_cd01_unregister,
759 &priv->acpi_nb);
760 if (ret)
761 goto out;
762
763 ret = component_add(&wdev->dev, &lwmi_cd_component_ops);
764 goto out;
765 case LENOVO_FAN_TEST_DATA:
766 ret = component_add(&wdev->dev, &lwmi_cd_sub_component_ops);
767 goto out;
768 default:
769 return -EINVAL;
770 }
771 out:
772 if (ret) {
773 dev_err(&wdev->dev, "failed to register %s: %d\n",
774 info->name, ret);
775 } else {
776 dev_dbg(&wdev->dev, "registered %s with %u items\n",
777 info->name, priv->list->count);
778 }
779 return ret;
780 }
781
lwmi_cd_remove(struct wmi_device * wdev)782 static void lwmi_cd_remove(struct wmi_device *wdev)
783 {
784 struct lwmi_cd_priv *priv = dev_get_drvdata(&wdev->dev);
785
786 switch (priv->list->type) {
787 case LENOVO_CAPABILITY_DATA_00:
788 lwmi_cd_sub_master_del(priv);
789 fallthrough;
790 case LENOVO_CAPABILITY_DATA_01:
791 component_del(&wdev->dev, &lwmi_cd_component_ops);
792 break;
793 case LENOVO_FAN_TEST_DATA:
794 component_del(&wdev->dev, &lwmi_cd_sub_component_ops);
795 break;
796 default:
797 WARN_ON(1);
798 }
799 }
800
801 #define LWMI_CD_WDEV_ID(_type) \
802 .guid_string = _type##_GUID, \
803 .context = &lwmi_cd_table[_type],
804
805 static const struct wmi_device_id lwmi_cd_id_table[] = {
806 { LWMI_CD_WDEV_ID(LENOVO_CAPABILITY_DATA_00) },
807 { LWMI_CD_WDEV_ID(LENOVO_CAPABILITY_DATA_01) },
808 { LWMI_CD_WDEV_ID(LENOVO_FAN_TEST_DATA) },
809 {}
810 };
811
812 static struct wmi_driver lwmi_cd_driver = {
813 .driver = {
814 .name = "lenovo_wmi_capdata",
815 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
816 },
817 .id_table = lwmi_cd_id_table,
818 .probe = lwmi_cd_probe,
819 .remove = lwmi_cd_remove,
820 .no_singleton = true,
821 };
822
823 module_wmi_driver(lwmi_cd_driver);
824
825 MODULE_DEVICE_TABLE(wmi, lwmi_cd_id_table);
826 MODULE_AUTHOR("Derek J. Clark <derekjohn.clark@gmail.com>");
827 MODULE_AUTHOR("Rong Zhang <i@rong.moe>");
828 MODULE_DESCRIPTION("Lenovo Capability Data WMI Driver");
829 MODULE_LICENSE("GPL");
830