1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * hwmon driver for HP (and some HP Compaq) business-class computers that
4 * report numeric sensor data via Windows Management Instrumentation (WMI).
5 *
6 * Copyright (C) 2023 James Seo <james@equiv.tech>
7 *
8 * References:
9 * [1] Hewlett-Packard Development Company, L.P.,
10 * "HP Client Management Interface Technical White Paper", 2005. [Online].
11 * Available: https://h20331.www2.hp.com/hpsub/downloads/cmi_whitepaper.pdf
12 * [2] Hewlett-Packard Development Company, L.P.,
13 * "HP Retail Manageability", 2012. [Online].
14 * Available: http://h10032.www1.hp.com/ctg/Manual/c03291135.pdf
15 * [3] Linux Hardware Project, A. Ponomarenko et al.,
16 * "linuxhw/ACPI - Collect ACPI table dumps", 2018. [Online].
17 * Available: https://github.com/linuxhw/ACPI
18 * [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer",
19 * 2017. [Online]. Available: https://github.com/pali/bmfdec
20 * [5] Microsoft Corporation, "Driver-Defined WMI Data Items", 2017. [Online].
21 * Available: https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/driver-defined-wmi-data-items
22 */
23
24 #include <linux/acpi.h>
25 #include <linux/debugfs.h>
26 #include <linux/hwmon.h>
27 #include <linux/jiffies.h>
28 #include <linux/mutex.h>
29 #include <linux/nls.h>
30 #include <linux/units.h>
31 #include <linux/wmi.h>
32
33 #define HP_WMI_EVENT_NAMESPACE "root\\WMI"
34 #define HP_WMI_EVENT_CLASS "HPBIOS_BIOSEvent"
35 #define HP_WMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
36 #define HP_WMI_NUMERIC_SENSOR_GUID "8F1F6435-9F42-42C8-BADC-0E9424F20C9A"
37 #define HP_WMI_PLATFORM_EVENTS_GUID "41227C2D-80E1-423F-8B8E-87E32755A0EB"
38
39 /* Patterns for recognizing sensors and matching events to channels. */
40
41 #define HP_WMI_PATTERN_SYS_TEMP "Chassis Thermal Index"
42 #define HP_WMI_PATTERN_SYS_TEMP2 "System Ambient Temperature"
43 #define HP_WMI_PATTERN_CPU_TEMP "CPU Thermal Index"
44 #define HP_WMI_PATTERN_CPU_TEMP2 "CPU Temperature"
45 #define HP_WMI_PATTERN_TEMP_SENSOR "Thermal Index"
46 #define HP_WMI_PATTERN_TEMP_ALARM "Thermal Critical"
47 #define HP_WMI_PATTERN_INTRUSION_ALARM "Hood Intrusion"
48 #define HP_WMI_PATTERN_FAN_ALARM "Stall"
49 #define HP_WMI_PATTERN_TEMP "Temperature"
50 #define HP_WMI_PATTERN_CPU "CPU"
51
52 /* These limits are arbitrary. The WMI implementation may vary by system. */
53
54 #define HP_WMI_MAX_STR_SIZE 128U
55 #define HP_WMI_MAX_PROPERTIES 32U
56 #define HP_WMI_MAX_INSTANCES 32U
57
58 enum hp_wmi_type {
59 HP_WMI_TYPE_OTHER = 1,
60 HP_WMI_TYPE_TEMPERATURE = 2,
61 HP_WMI_TYPE_VOLTAGE = 3,
62 HP_WMI_TYPE_CURRENT = 4,
63 HP_WMI_TYPE_AIR_FLOW = 12,
64 HP_WMI_TYPE_INTRUSION = 0xabadb01, /* Custom. */
65 };
66
67 enum hp_wmi_category {
68 HP_WMI_CATEGORY_SENSOR = 3,
69 };
70
71 enum hp_wmi_severity {
72 HP_WMI_SEVERITY_UNKNOWN = 0,
73 HP_WMI_SEVERITY_OK = 5,
74 HP_WMI_SEVERITY_DEGRADED_WARNING = 10,
75 HP_WMI_SEVERITY_MINOR_FAILURE = 15,
76 HP_WMI_SEVERITY_MAJOR_FAILURE = 20,
77 HP_WMI_SEVERITY_CRITICAL_FAILURE = 25,
78 HP_WMI_SEVERITY_NON_RECOVERABLE_ERROR = 30,
79 };
80
81 enum hp_wmi_status {
82 HP_WMI_STATUS_OK = 2,
83 HP_WMI_STATUS_DEGRADED = 3,
84 HP_WMI_STATUS_STRESSED = 4,
85 HP_WMI_STATUS_PREDICTIVE_FAILURE = 5,
86 HP_WMI_STATUS_ERROR = 6,
87 HP_WMI_STATUS_NON_RECOVERABLE_ERROR = 7,
88 HP_WMI_STATUS_NO_CONTACT = 12,
89 HP_WMI_STATUS_LOST_COMMUNICATION = 13,
90 HP_WMI_STATUS_ABORTED = 14,
91 HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16,
92
93 /* Occurs combined with one of "OK", "Degraded", and "Error" [1]. */
94 HP_WMI_STATUS_COMPLETED = 17,
95 };
96
97 enum hp_wmi_units {
98 HP_WMI_UNITS_OTHER = 1,
99 HP_WMI_UNITS_DEGREES_C = 2,
100 HP_WMI_UNITS_DEGREES_F = 3,
101 HP_WMI_UNITS_DEGREES_K = 4,
102 HP_WMI_UNITS_VOLTS = 5,
103 HP_WMI_UNITS_AMPS = 6,
104 HP_WMI_UNITS_RPM = 19,
105 };
106
107 enum hp_wmi_property {
108 HP_WMI_PROPERTY_NAME = 0,
109 HP_WMI_PROPERTY_DESCRIPTION = 1,
110 HP_WMI_PROPERTY_SENSOR_TYPE = 2,
111 HP_WMI_PROPERTY_OTHER_SENSOR_TYPE = 3,
112 HP_WMI_PROPERTY_OPERATIONAL_STATUS = 4,
113 HP_WMI_PROPERTY_SIZE = 5,
114 HP_WMI_PROPERTY_POSSIBLE_STATES = 6,
115 HP_WMI_PROPERTY_CURRENT_STATE = 7,
116 HP_WMI_PROPERTY_BASE_UNITS = 8,
117 HP_WMI_PROPERTY_UNIT_MODIFIER = 9,
118 HP_WMI_PROPERTY_CURRENT_READING = 10,
119 HP_WMI_PROPERTY_RATE_UNITS = 11,
120 };
121
122 static const acpi_object_type hp_wmi_property_map[] = {
123 [HP_WMI_PROPERTY_NAME] = ACPI_TYPE_STRING,
124 [HP_WMI_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING,
125 [HP_WMI_PROPERTY_SENSOR_TYPE] = ACPI_TYPE_INTEGER,
126 [HP_WMI_PROPERTY_OTHER_SENSOR_TYPE] = ACPI_TYPE_STRING,
127 [HP_WMI_PROPERTY_OPERATIONAL_STATUS] = ACPI_TYPE_INTEGER,
128 [HP_WMI_PROPERTY_SIZE] = ACPI_TYPE_INTEGER,
129 [HP_WMI_PROPERTY_POSSIBLE_STATES] = ACPI_TYPE_STRING,
130 [HP_WMI_PROPERTY_CURRENT_STATE] = ACPI_TYPE_STRING,
131 [HP_WMI_PROPERTY_BASE_UNITS] = ACPI_TYPE_INTEGER,
132 [HP_WMI_PROPERTY_UNIT_MODIFIER] = ACPI_TYPE_INTEGER,
133 [HP_WMI_PROPERTY_CURRENT_READING] = ACPI_TYPE_INTEGER,
134 [HP_WMI_PROPERTY_RATE_UNITS] = ACPI_TYPE_INTEGER,
135 };
136
137 enum hp_wmi_platform_events_property {
138 HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME = 0,
139 HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION = 1,
140 HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE = 2,
141 HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS = 3,
142 HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY = 4,
143 HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY = 5,
144 HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS = 6,
145 };
146
147 static const acpi_object_type hp_wmi_platform_events_property_map[] = {
148 [HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME] = ACPI_TYPE_STRING,
149 [HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING,
150 [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE] = ACPI_TYPE_STRING,
151 [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS] = ACPI_TYPE_STRING,
152 [HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY] = ACPI_TYPE_INTEGER,
153 [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY] = ACPI_TYPE_INTEGER,
154 [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS] = ACPI_TYPE_INTEGER,
155 };
156
157 enum hp_wmi_event_property {
158 HP_WMI_EVENT_PROPERTY_NAME = 0,
159 HP_WMI_EVENT_PROPERTY_DESCRIPTION = 1,
160 HP_WMI_EVENT_PROPERTY_CATEGORY = 2,
161 HP_WMI_EVENT_PROPERTY_SEVERITY = 3,
162 HP_WMI_EVENT_PROPERTY_STATUS = 4,
163 };
164
165 static const acpi_object_type hp_wmi_event_property_map[] = {
166 [HP_WMI_EVENT_PROPERTY_NAME] = ACPI_TYPE_STRING,
167 [HP_WMI_EVENT_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING,
168 [HP_WMI_EVENT_PROPERTY_CATEGORY] = ACPI_TYPE_INTEGER,
169 [HP_WMI_EVENT_PROPERTY_SEVERITY] = ACPI_TYPE_INTEGER,
170 [HP_WMI_EVENT_PROPERTY_STATUS] = ACPI_TYPE_INTEGER,
171 };
172
173 static const enum hwmon_sensor_types hp_wmi_hwmon_type_map[] = {
174 [HP_WMI_TYPE_TEMPERATURE] = hwmon_temp,
175 [HP_WMI_TYPE_VOLTAGE] = hwmon_in,
176 [HP_WMI_TYPE_CURRENT] = hwmon_curr,
177 [HP_WMI_TYPE_AIR_FLOW] = hwmon_fan,
178 };
179
180 static const u32 hp_wmi_hwmon_attributes[hwmon_max] = {
181 [hwmon_chip] = HWMON_C_REGISTER_TZ,
182 [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_FAULT,
183 [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL,
184 [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL,
185 [hwmon_fan] = HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_FAULT,
186 [hwmon_intrusion] = HWMON_INTRUSION_ALARM,
187 };
188
189 /*
190 * struct hp_wmi_numeric_sensor - a HPBIOS_BIOSNumericSensor instance
191 *
192 * Two variants of HPBIOS_BIOSNumericSensor are known. The first is specified
193 * in [1] and appears to be much more widespread. The second was discovered by
194 * decoding BMOF blobs [4], seems to be found only in some newer ZBook systems
195 * [3], and has two new properties and a slightly different property order.
196 *
197 * These differences don't matter on Windows, where WMI object properties are
198 * accessed by name. For us, supporting both variants gets ugly and hacky at
199 * times. The fun begins now; this struct is defined as per the new variant.
200 *
201 * Effective MOF definition:
202 *
203 * #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS");
204 * class HPBIOS_BIOSNumericSensor {
205 * [read] string Name;
206 * [read] string Description;
207 * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
208 * "10","11","12"}, Values {"Unknown","Other","Temperature",
209 * "Voltage","Current","Tachometer","Counter","Switch","Lock",
210 * "Humidity","Smoke Detection","Presence","Air Flow"}]
211 * uint32 SensorType;
212 * [read] string OtherSensorType;
213 * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
214 * "10","11","12","13","14","15","16","17","18","..",
215 * "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
216 * "Stressed","Predictive Failure","Error",
217 * "Non-Recoverable Error","Starting","Stopping","Stopped",
218 * "In Service","No Contact","Lost Communication","Aborted",
219 * "Dormant","Supporting Entity in Error","Completed",
220 * "Power Mode","DMTF Reserved","Vendor Reserved"}]
221 * uint32 OperationalStatus;
222 * [read] uint32 Size;
223 * [read] string PossibleStates[];
224 * [read] string CurrentState;
225 * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
226 * "10","11","12","13","14","15","16","17","18","19","20",
227 * "21","22","23","24","25","26","27","28","29","30","31",
228 * "32","33","34","35","36","37","38","39","40","41","42",
229 * "43","44","45","46","47","48","49","50","51","52","53",
230 * "54","55","56","57","58","59","60","61","62","63","64",
231 * "65"}, Values {"Unknown","Other","Degrees C","Degrees F",
232 * "Degrees K","Volts","Amps","Watts","Joules","Coulombs",
233 * "VA","Nits","Lumens","Lux","Candelas","kPa","PSI",
234 * "Newtons","CFM","RPM","Hertz","Seconds","Minutes",
235 * "Hours","Days","Weeks","Mils","Inches","Feet",
236 * "Cubic Inches","Cubic Feet","Meters","Cubic Centimeters",
237 * "Cubic Meters","Liters","Fluid Ounces","Radians",
238 * "Steradians","Revolutions","Cycles","Gravities","Ounces",
239 * "Pounds","Foot-Pounds","Ounce-Inches","Gauss","Gilberts",
240 * "Henries","Farads","Ohms","Siemens","Moles","Becquerels",
241 * "PPM (parts/million)","Decibels","DbA","DbC","Grays",
242 * "Sieverts","Color Temperature Degrees K","Bits","Bytes",
243 * "Words (data)","DoubleWords","QuadWords","Percentage"}]
244 * uint32 BaseUnits;
245 * [read] sint32 UnitModifier;
246 * [read] uint32 CurrentReading;
247 * [read] uint32 RateUnits;
248 * };
249 *
250 * Effective MOF definition of old variant [1] (sans redundant info):
251 *
252 * class HPBIOS_BIOSNumericSensor {
253 * [read] string Name;
254 * [read] string Description;
255 * [read] uint32 SensorType;
256 * [read] string OtherSensorType;
257 * [read] uint32 OperationalStatus;
258 * [read] string CurrentState;
259 * [read] string PossibleStates[];
260 * [read] uint32 BaseUnits;
261 * [read] sint32 UnitModifier;
262 * [read] uint32 CurrentReading;
263 * };
264 */
265 struct hp_wmi_numeric_sensor {
266 const char *name;
267 const char *description;
268 u32 sensor_type;
269 const char *other_sensor_type; /* Explains "Other" SensorType. */
270 u32 operational_status;
271 u8 size; /* Count of PossibleStates[]. */
272 const char **possible_states;
273 const char *current_state;
274 u32 base_units;
275 s32 unit_modifier;
276 u32 current_reading;
277 u32 rate_units;
278 };
279
280 /*
281 * struct hp_wmi_platform_events - a HPBIOS_PlatformEvents instance
282 *
283 * Instances of this object reveal the set of possible HPBIOS_BIOSEvent
284 * instances for the current system, but it may not always be present.
285 *
286 * Effective MOF definition:
287 *
288 * #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS");
289 * class HPBIOS_PlatformEvents {
290 * [read] string Name;
291 * [read] string Description;
292 * [read] string SourceNamespace;
293 * [read] string SourceClass;
294 * [read, ValueMap {"0","1","2","3","4",".."}, Values {
295 * "Unknown","Configuration Change","Button Pressed",
296 * "Sensor","BIOS Settings","Reserved"}]
297 * uint32 Category;
298 * [read, ValueMap{"0","5","10","15","20","25","30",".."},
299 * Values{"Unknown","OK","Degraded/Warning","Minor Failure",
300 * "Major Failure","Critical Failure","Non-recoverable Error",
301 * "DMTF Reserved"}]
302 * uint32 PossibleSeverity;
303 * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
304 * "10","11","12","13","14","15","16","17","18","..",
305 * "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
306 * "Stressed","Predictive Failure","Error",
307 * "Non-Recoverable Error","Starting","Stopping","Stopped",
308 * "In Service","No Contact","Lost Communication","Aborted",
309 * "Dormant","Supporting Entity in Error","Completed",
310 * "Power Mode","DMTF Reserved","Vendor Reserved"}]
311 * uint32 PossibleStatus;
312 * };
313 */
314 struct hp_wmi_platform_events {
315 const char *name;
316 const char *description;
317 const char *source_namespace;
318 const char *source_class;
319 u32 category;
320 u32 possible_severity;
321 u32 possible_status;
322 };
323
324 /*
325 * struct hp_wmi_event - a HPBIOS_BIOSEvent instance
326 *
327 * Effective MOF definition [1] (corrected below from original):
328 *
329 * #pragma namespace("\\\\.\\root\\WMI");
330 * class HPBIOS_BIOSEvent : WMIEvent {
331 * [read] string Name;
332 * [read] string Description;
333 * [read ValueMap {"0","1","2","3","4"}, Values {"Unknown",
334 * "Configuration Change","Button Pressed","Sensor",
335 * "BIOS Settings"}]
336 * uint32 Category;
337 * [read, ValueMap {"0","5","10","15","20","25","30"},
338 * Values {"Unknown","OK","Degraded/Warning",
339 * "Minor Failure","Major Failure","Critical Failure",
340 * "Non-recoverable Error"}]
341 * uint32 Severity;
342 * [read, ValueMap {"0","1","2","3","4","5","6","7","8",
343 * "9","10","11","12","13","14","15","16","17","18","..",
344 * "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
345 * "Stressed","Predictive Failure","Error",
346 * "Non-Recoverable Error","Starting","Stopping","Stopped",
347 * "In Service","No Contact","Lost Communication","Aborted",
348 * "Dormant","Supporting Entity in Error","Completed",
349 * "Power Mode","DMTF Reserved","Vendor Reserved"}]
350 * uint32 Status;
351 * };
352 */
353 struct hp_wmi_event {
354 const char *name;
355 const char *description;
356 u32 category;
357 };
358
359 /*
360 * struct hp_wmi_info - sensor info
361 * @nsensor: numeric sensor properties
362 * @instance: its WMI instance number
363 * @state: pointer to driver state
364 * @has_alarm: whether sensor has an alarm flag
365 * @alarm: alarm flag
366 * @type: its hwmon sensor type
367 * @cached_val: current sensor reading value, scaled for hwmon
368 * @last_updated: when these readings were last updated
369 */
370 struct hp_wmi_info {
371 struct hp_wmi_numeric_sensor nsensor;
372 u8 instance;
373 void *state; /* void *: Avoid forward declaration. */
374 bool has_alarm;
375 bool alarm;
376 enum hwmon_sensor_types type;
377 long cached_val;
378 unsigned long last_updated; /* In jiffies. */
379
380 };
381
382 /*
383 * struct hp_wmi_sensors - driver state
384 * @wdev: pointer to the parent WMI device
385 * @info_map: sensor info structs by hwmon type and channel number
386 * @channel_count: count of hwmon channels by hwmon type
387 * @has_intrusion: whether an intrusion sensor is present
388 * @intrusion: intrusion flag
389 * @lock: mutex to lock polling WMI and changes to driver state
390 */
391 struct hp_wmi_sensors {
392 struct wmi_device *wdev;
393 struct hp_wmi_info **info_map[hwmon_max];
394 u8 channel_count[hwmon_max];
395 bool has_intrusion;
396 bool intrusion;
397
398 struct mutex lock; /* Lock polling WMI and driver state changes. */
399 };
400
is_raw_wmi_string(const u8 * pointer,u32 length)401 static bool is_raw_wmi_string(const u8 *pointer, u32 length)
402 {
403 const u16 *ptr;
404 u16 len;
405
406 /* WMI strings are length-prefixed UTF-16 [5]. */
407 if (length <= sizeof(*ptr))
408 return false;
409
410 length -= sizeof(*ptr);
411 ptr = (const u16 *)pointer;
412 len = *ptr;
413
414 return len <= length && !(len & 1);
415 }
416
convert_raw_wmi_string(const u8 * buf)417 static char *convert_raw_wmi_string(const u8 *buf)
418 {
419 const wchar_t *src;
420 unsigned int cps;
421 unsigned int len;
422 char *dst;
423 int i;
424
425 src = (const wchar_t *)buf;
426
427 /* Count UTF-16 code points. Exclude trailing null padding. */
428 cps = *src / sizeof(*src);
429 while (cps && !src[cps])
430 cps--;
431
432 /* Each code point becomes up to 3 UTF-8 characters. */
433 len = min(cps * 3, HP_WMI_MAX_STR_SIZE - 1);
434
435 dst = kmalloc((len + 1) * sizeof(*dst), GFP_KERNEL);
436 if (!dst)
437 return NULL;
438
439 i = utf16s_to_utf8s(++src, cps, UTF16_LITTLE_ENDIAN, dst, len);
440 dst[i] = '\0';
441
442 return dst;
443 }
444
445 /* hp_wmi_strdup - devm_kstrdup, but length-limited */
hp_wmi_strdup(struct device * dev,const char * src)446 static char *hp_wmi_strdup(struct device *dev, const char *src)
447 {
448 char *dst;
449 size_t len;
450
451 len = strnlen(src, HP_WMI_MAX_STR_SIZE - 1);
452
453 dst = devm_kmalloc(dev, (len + 1) * sizeof(*dst), GFP_KERNEL);
454 if (!dst)
455 return NULL;
456
457 strscpy(dst, src, len + 1);
458
459 return dst;
460 }
461
462 /* hp_wmi_wstrdup - hp_wmi_strdup, but for a raw WMI string */
hp_wmi_wstrdup(struct device * dev,const u8 * buf)463 static char *hp_wmi_wstrdup(struct device *dev, const u8 *buf)
464 {
465 char *src;
466 char *dst;
467
468 src = convert_raw_wmi_string(buf);
469 if (!src)
470 return NULL;
471
472 dst = hp_wmi_strdup(dev, strim(src)); /* Note: Copy is trimmed. */
473
474 kfree(src);
475
476 return dst;
477 }
478
479 /*
480 * hp_wmi_get_wobj - poll WMI for a WMI object instance
481 * @guid: WMI object GUID
482 * @instance: WMI object instance number
483 *
484 * Returns a new WMI object instance on success, or NULL on error.
485 * Caller must kfree() the result.
486 */
hp_wmi_get_wobj(const char * guid,u8 instance)487 static union acpi_object *hp_wmi_get_wobj(const char *guid, u8 instance)
488 {
489 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
490 acpi_status err;
491
492 err = wmi_query_block(guid, instance, &out);
493 if (ACPI_FAILURE(err))
494 return NULL;
495
496 return out.pointer;
497 }
498
499 /* hp_wmi_wobj_instance_count - find count of WMI object instances */
hp_wmi_wobj_instance_count(const char * guid)500 static u8 hp_wmi_wobj_instance_count(const char *guid)
501 {
502 int count;
503
504 count = wmi_instance_count(guid);
505
506 return clamp(count, 0, (int)HP_WMI_MAX_INSTANCES);
507 }
508
check_wobj(const union acpi_object * wobj,const acpi_object_type property_map[],int last_prop)509 static int check_wobj(const union acpi_object *wobj,
510 const acpi_object_type property_map[], int last_prop)
511 {
512 acpi_object_type type = wobj->type;
513 acpi_object_type valid_type;
514 union acpi_object *elements;
515 u32 elem_count;
516 int prop;
517
518 if (type != ACPI_TYPE_PACKAGE)
519 return -EINVAL;
520
521 elem_count = wobj->package.count;
522 if (elem_count != last_prop + 1)
523 return -EINVAL;
524
525 elements = wobj->package.elements;
526 for (prop = 0; prop <= last_prop; prop++) {
527 type = elements[prop].type;
528 valid_type = property_map[prop];
529 if (type == ACPI_TYPE_BUFFER &&
530 is_raw_wmi_string(elements[prop].buffer.pointer,
531 elements[prop].buffer.length))
532 type = ACPI_TYPE_STRING;
533 if (type != valid_type)
534 return -EINVAL;
535 }
536
537 return 0;
538 }
539
extract_acpi_value(struct device * dev,union acpi_object * element,acpi_object_type type,u32 * out_value,char ** out_string)540 static int extract_acpi_value(struct device *dev,
541 union acpi_object *element,
542 acpi_object_type type,
543 u32 *out_value, char **out_string)
544 {
545 switch (type) {
546 case ACPI_TYPE_INTEGER:
547 *out_value = element->integer.value;
548 break;
549
550 case ACPI_TYPE_STRING:
551 *out_string = element->type == ACPI_TYPE_BUFFER ?
552 hp_wmi_wstrdup(dev, element->buffer.pointer) :
553 hp_wmi_strdup(dev, strim(element->string.pointer));
554 if (!*out_string)
555 return -ENOMEM;
556 break;
557
558 default:
559 return -EINVAL;
560 }
561
562 return 0;
563 }
564
565 /*
566 * check_numeric_sensor_wobj - validate a HPBIOS_BIOSNumericSensor instance
567 * @wobj: pointer to WMI object instance to check
568 * @out_size: out pointer to count of possible states
569 * @out_is_new: out pointer to whether this is a "new" variant object
570 *
571 * Returns 0 on success, or a negative error code on error.
572 */
check_numeric_sensor_wobj(const union acpi_object * wobj,u8 * out_size,bool * out_is_new)573 static int check_numeric_sensor_wobj(const union acpi_object *wobj,
574 u8 *out_size, bool *out_is_new)
575 {
576 acpi_object_type type = wobj->type;
577 int prop = HP_WMI_PROPERTY_NAME;
578 acpi_object_type valid_type;
579 union acpi_object *elements;
580 union acpi_object *element;
581 u32 elem_count;
582 int last_prop;
583 bool is_new;
584 u8 count;
585 u32 j;
586 u32 i;
587
588 if (type != ACPI_TYPE_PACKAGE)
589 return -EINVAL;
590
591 /*
592 * elements is a variable-length array of ACPI objects, one for
593 * each property of the WMI object instance, except that the
594 * strings in PossibleStates[] are flattened into this array
595 * as if each individual string were a property by itself.
596 */
597 elements = wobj->package.elements;
598
599 elem_count = wobj->package.count;
600 if (elem_count <= HP_WMI_PROPERTY_SIZE ||
601 elem_count > HP_WMI_MAX_PROPERTIES)
602 return -EINVAL;
603
604 element = &elements[HP_WMI_PROPERTY_SIZE];
605 type = element->type;
606 switch (type) {
607 case ACPI_TYPE_INTEGER:
608 is_new = true;
609 last_prop = HP_WMI_PROPERTY_RATE_UNITS;
610 break;
611
612 case ACPI_TYPE_BUFFER:
613 if (!is_raw_wmi_string(element->buffer.pointer,
614 element->buffer.length))
615 return -EINVAL;
616 fallthrough;
617
618 case ACPI_TYPE_STRING:
619 is_new = false;
620 last_prop = HP_WMI_PROPERTY_CURRENT_READING;
621 break;
622
623 default:
624 return -EINVAL;
625 }
626
627 /*
628 * In general, the count of PossibleStates[] must be > 0.
629 * Also, the old variant lacks the Size property, so we may need to
630 * reduce the value of last_prop by 1 when doing arithmetic with it.
631 */
632 if (elem_count < last_prop - !is_new + 1)
633 return -EINVAL;
634
635 count = elem_count - (last_prop - !is_new);
636
637 for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) {
638 type = elements[i].type;
639 valid_type = hp_wmi_property_map[prop];
640 if (type == ACPI_TYPE_BUFFER &&
641 is_raw_wmi_string(elements[i].buffer.pointer,
642 elements[i].buffer.length))
643 type = ACPI_TYPE_STRING;
644 if (type != valid_type)
645 return -EINVAL;
646
647 switch (prop) {
648 case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
649 /* Old variant: CurrentState follows OperationalStatus. */
650 if (!is_new)
651 prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;
652 break;
653
654 case HP_WMI_PROPERTY_SIZE:
655 /* New variant: Size == count of PossibleStates[]. */
656 if (count != elements[i].integer.value)
657 return -EINVAL;
658 break;
659
660 case HP_WMI_PROPERTY_POSSIBLE_STATES:
661 /* PossibleStates[0] has already been type-checked. */
662 for (j = 0; i + 1 < elem_count && j + 1 < count; j++) {
663 type = elements[++i].type;
664 if (type == ACPI_TYPE_BUFFER &&
665 is_raw_wmi_string(elements[i].buffer.pointer,
666 elements[i].buffer.length))
667 type = ACPI_TYPE_STRING;
668 if (type != valid_type)
669 return -EINVAL;
670 }
671
672 /* Old variant: BaseUnits follows PossibleStates[]. */
673 if (!is_new)
674 prop = HP_WMI_PROPERTY_BASE_UNITS - 1;
675 break;
676
677 case HP_WMI_PROPERTY_CURRENT_STATE:
678 /* Old variant: PossibleStates[] follows CurrentState. */
679 if (!is_new)
680 prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;
681 break;
682 }
683 }
684
685 if (prop != last_prop + 1)
686 return -EINVAL;
687
688 *out_size = count;
689 *out_is_new = is_new;
690
691 return 0;
692 }
693
694 static int
numeric_sensor_is_connected(const struct hp_wmi_numeric_sensor * nsensor)695 numeric_sensor_is_connected(const struct hp_wmi_numeric_sensor *nsensor)
696 {
697 u32 operational_status = nsensor->operational_status;
698
699 return operational_status != HP_WMI_STATUS_NO_CONTACT;
700 }
701
numeric_sensor_has_fault(const struct hp_wmi_numeric_sensor * nsensor)702 static int numeric_sensor_has_fault(const struct hp_wmi_numeric_sensor *nsensor)
703 {
704 u32 operational_status = nsensor->operational_status;
705
706 switch (operational_status) {
707 case HP_WMI_STATUS_DEGRADED:
708 case HP_WMI_STATUS_STRESSED: /* e.g. Overload, overtemp. */
709 case HP_WMI_STATUS_PREDICTIVE_FAILURE: /* e.g. Fan removed. */
710 case HP_WMI_STATUS_ERROR:
711 case HP_WMI_STATUS_NON_RECOVERABLE_ERROR:
712 case HP_WMI_STATUS_NO_CONTACT:
713 case HP_WMI_STATUS_LOST_COMMUNICATION:
714 case HP_WMI_STATUS_ABORTED:
715 case HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR:
716
717 /* Assume combination by addition; bitwise OR doesn't make sense. */
718 case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_DEGRADED:
719 case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_ERROR:
720 return true;
721 }
722
723 return false;
724 }
725
726 /* scale_numeric_sensor - scale sensor reading for hwmon */
scale_numeric_sensor(const struct hp_wmi_numeric_sensor * nsensor)727 static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
728 {
729 u32 current_reading = nsensor->current_reading;
730 s32 unit_modifier = nsensor->unit_modifier;
731 u32 sensor_type = nsensor->sensor_type;
732 u32 base_units = nsensor->base_units;
733 s32 target_modifier;
734 long val;
735
736 /* Fan readings are in RPM units; others are in milliunits. */
737 target_modifier = sensor_type == HP_WMI_TYPE_AIR_FLOW ? 0 : -3;
738
739 val = current_reading;
740
741 for (; unit_modifier < target_modifier; unit_modifier++)
742 val = DIV_ROUND_CLOSEST(val, 10);
743
744 for (; unit_modifier > target_modifier; unit_modifier--) {
745 if (val > LONG_MAX / 10) {
746 val = LONG_MAX;
747 break;
748 }
749 val *= 10;
750 }
751
752 if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
753 switch (base_units) {
754 case HP_WMI_UNITS_DEGREES_F:
755 val -= MILLI * 32;
756 val = val <= LONG_MAX / 5 ?
757 DIV_ROUND_CLOSEST(val * 5, 9) :
758 DIV_ROUND_CLOSEST(val, 9) * 5;
759 break;
760
761 case HP_WMI_UNITS_DEGREES_K:
762 val = milli_kelvin_to_millicelsius(val);
763 break;
764 }
765 }
766
767 return val;
768 }
769
770 /*
771 * classify_numeric_sensor - classify a numeric sensor
772 * @nsensor: pointer to numeric sensor struct
773 *
774 * Returns an enum hp_wmi_type value on success,
775 * or a negative value if the sensor type is unsupported.
776 */
classify_numeric_sensor(const struct hp_wmi_numeric_sensor * nsensor)777 static int classify_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
778 {
779 u32 sensor_type = nsensor->sensor_type;
780 u32 base_units = nsensor->base_units;
781 const char *name = nsensor->name;
782
783 switch (sensor_type) {
784 case HP_WMI_TYPE_TEMPERATURE:
785 /*
786 * Some systems have sensors named "X Thermal Index" in "Other"
787 * units. Tested CPU sensor examples were found to be in °C,
788 * albeit perhaps "differently" accurate; e.g. readings were
789 * reliably -6°C vs. coretemp on a HP Compaq Elite 8300, and
790 * +8°C on an EliteOne G1 800. But this is still within the
791 * realm of plausibility for cheaply implemented motherboard
792 * sensors, and chassis readings were about as expected.
793 */
794 if ((base_units == HP_WMI_UNITS_OTHER &&
795 strstr(name, HP_WMI_PATTERN_TEMP_SENSOR)) ||
796 base_units == HP_WMI_UNITS_DEGREES_C ||
797 base_units == HP_WMI_UNITS_DEGREES_F ||
798 base_units == HP_WMI_UNITS_DEGREES_K)
799 return HP_WMI_TYPE_TEMPERATURE;
800 break;
801
802 case HP_WMI_TYPE_VOLTAGE:
803 if (base_units == HP_WMI_UNITS_VOLTS)
804 return HP_WMI_TYPE_VOLTAGE;
805 break;
806
807 case HP_WMI_TYPE_CURRENT:
808 if (base_units == HP_WMI_UNITS_AMPS)
809 return HP_WMI_TYPE_CURRENT;
810 break;
811
812 case HP_WMI_TYPE_AIR_FLOW:
813 /*
814 * Strangely, HP considers fan RPM sensor type to be
815 * "Air Flow" instead of the more intuitive "Tachometer".
816 */
817 if (base_units == HP_WMI_UNITS_RPM)
818 return HP_WMI_TYPE_AIR_FLOW;
819 break;
820 }
821
822 return -EINVAL;
823 }
824
825 static int
populate_numeric_sensor_from_wobj(struct device * dev,struct hp_wmi_numeric_sensor * nsensor,union acpi_object * wobj,bool * out_is_new)826 populate_numeric_sensor_from_wobj(struct device *dev,
827 struct hp_wmi_numeric_sensor *nsensor,
828 union acpi_object *wobj, bool *out_is_new)
829 {
830 int last_prop = HP_WMI_PROPERTY_RATE_UNITS;
831 int prop = HP_WMI_PROPERTY_NAME;
832 const char **possible_states;
833 union acpi_object *element;
834 acpi_object_type type;
835 char *string;
836 bool is_new;
837 u32 value;
838 u8 size;
839 int err;
840
841 err = check_numeric_sensor_wobj(wobj, &size, &is_new);
842 if (err)
843 return err;
844
845 possible_states = devm_kcalloc(dev, size, sizeof(*possible_states),
846 GFP_KERNEL);
847 if (!possible_states)
848 return -ENOMEM;
849
850 element = wobj->package.elements;
851 nsensor->possible_states = possible_states;
852 nsensor->size = size;
853
854 if (!is_new)
855 last_prop = HP_WMI_PROPERTY_CURRENT_READING;
856
857 for (; prop <= last_prop; prop++) {
858 type = hp_wmi_property_map[prop];
859
860 err = extract_acpi_value(dev, element, type, &value, &string);
861 if (err)
862 return err;
863
864 element++;
865
866 switch (prop) {
867 case HP_WMI_PROPERTY_NAME:
868 nsensor->name = string;
869 break;
870
871 case HP_WMI_PROPERTY_DESCRIPTION:
872 nsensor->description = string;
873 break;
874
875 case HP_WMI_PROPERTY_SENSOR_TYPE:
876 if (value > HP_WMI_TYPE_AIR_FLOW)
877 return -EINVAL;
878
879 nsensor->sensor_type = value;
880 break;
881
882 case HP_WMI_PROPERTY_OTHER_SENSOR_TYPE:
883 nsensor->other_sensor_type = string;
884 break;
885
886 case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
887 nsensor->operational_status = value;
888
889 /* Old variant: CurrentState follows OperationalStatus. */
890 if (!is_new)
891 prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;
892 break;
893
894 case HP_WMI_PROPERTY_SIZE:
895 break; /* Already set. */
896
897 case HP_WMI_PROPERTY_POSSIBLE_STATES:
898 *possible_states++ = string;
899 if (--size)
900 prop--;
901
902 /* Old variant: BaseUnits follows PossibleStates[]. */
903 if (!is_new && !size)
904 prop = HP_WMI_PROPERTY_BASE_UNITS - 1;
905 break;
906
907 case HP_WMI_PROPERTY_CURRENT_STATE:
908 nsensor->current_state = string;
909
910 /* Old variant: PossibleStates[] follows CurrentState. */
911 if (!is_new)
912 prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;
913 break;
914
915 case HP_WMI_PROPERTY_BASE_UNITS:
916 nsensor->base_units = value;
917 break;
918
919 case HP_WMI_PROPERTY_UNIT_MODIFIER:
920 /* UnitModifier is signed. */
921 nsensor->unit_modifier = (s32)value;
922 break;
923
924 case HP_WMI_PROPERTY_CURRENT_READING:
925 nsensor->current_reading = value;
926 break;
927
928 case HP_WMI_PROPERTY_RATE_UNITS:
929 nsensor->rate_units = value;
930 break;
931
932 default:
933 return -EINVAL;
934 }
935 }
936
937 *out_is_new = is_new;
938
939 return 0;
940 }
941
942 /* update_numeric_sensor_from_wobj - update fungible sensor properties */
943 static void
update_numeric_sensor_from_wobj(struct device * dev,struct hp_wmi_numeric_sensor * nsensor,const union acpi_object * wobj)944 update_numeric_sensor_from_wobj(struct device *dev,
945 struct hp_wmi_numeric_sensor *nsensor,
946 const union acpi_object *wobj)
947 {
948 const union acpi_object *elements;
949 const union acpi_object *element;
950 const char *new_string;
951 char *trimmed;
952 char *string;
953 bool is_new;
954 int offset;
955 u8 size;
956 int err;
957
958 err = check_numeric_sensor_wobj(wobj, &size, &is_new);
959 if (err)
960 return;
961
962 elements = wobj->package.elements;
963
964 element = &elements[HP_WMI_PROPERTY_OPERATIONAL_STATUS];
965 nsensor->operational_status = element->integer.value;
966
967 /*
968 * In general, an index offset is needed after PossibleStates[0].
969 * On a new variant, CurrentState is after PossibleStates[]. This is
970 * not the case on an old variant, but we still need to offset the
971 * read because CurrentState is where Size would be on a new variant.
972 */
973 offset = is_new ? size - 1 : -2;
974
975 element = &elements[HP_WMI_PROPERTY_CURRENT_STATE + offset];
976 string = element->type == ACPI_TYPE_BUFFER ?
977 convert_raw_wmi_string(element->buffer.pointer) :
978 element->string.pointer;
979
980 if (string) {
981 trimmed = strim(string);
982 if (strcmp(trimmed, nsensor->current_state)) {
983 new_string = hp_wmi_strdup(dev, trimmed);
984 if (new_string) {
985 devm_kfree(dev, nsensor->current_state);
986 nsensor->current_state = new_string;
987 }
988 }
989 if (element->type == ACPI_TYPE_BUFFER)
990 kfree(string);
991 }
992
993 /* Old variant: -2 (not -1) because it lacks the Size property. */
994 if (!is_new)
995 offset = (int)size - 2; /* size is > 0, i.e. may be 1. */
996
997 element = &elements[HP_WMI_PROPERTY_UNIT_MODIFIER + offset];
998 nsensor->unit_modifier = (s32)element->integer.value;
999
1000 element = &elements[HP_WMI_PROPERTY_CURRENT_READING + offset];
1001 nsensor->current_reading = element->integer.value;
1002 }
1003
1004 /*
1005 * check_platform_events_wobj - validate a HPBIOS_PlatformEvents instance
1006 * @wobj: pointer to WMI object instance to check
1007 *
1008 * Returns 0 on success, or a negative error code on error.
1009 */
check_platform_events_wobj(const union acpi_object * wobj)1010 static int check_platform_events_wobj(const union acpi_object *wobj)
1011 {
1012 return check_wobj(wobj, hp_wmi_platform_events_property_map,
1013 HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS);
1014 }
1015
1016 static int
populate_platform_events_from_wobj(struct device * dev,struct hp_wmi_platform_events * pevents,union acpi_object * wobj)1017 populate_platform_events_from_wobj(struct device *dev,
1018 struct hp_wmi_platform_events *pevents,
1019 union acpi_object *wobj)
1020 {
1021 int last_prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS;
1022 int prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME;
1023 union acpi_object *element;
1024 acpi_object_type type;
1025 char *string;
1026 u32 value;
1027 int err;
1028
1029 err = check_platform_events_wobj(wobj);
1030 if (err)
1031 return err;
1032
1033 element = wobj->package.elements;
1034
1035 for (; prop <= last_prop; prop++, element++) {
1036 type = hp_wmi_platform_events_property_map[prop];
1037
1038 err = extract_acpi_value(dev, element, type, &value, &string);
1039 if (err)
1040 return err;
1041
1042 switch (prop) {
1043 case HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME:
1044 pevents->name = string;
1045 break;
1046
1047 case HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION:
1048 pevents->description = string;
1049 break;
1050
1051 case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE:
1052 if (strcasecmp(HP_WMI_EVENT_NAMESPACE, string))
1053 return -EINVAL;
1054
1055 pevents->source_namespace = string;
1056 break;
1057
1058 case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS:
1059 if (strcasecmp(HP_WMI_EVENT_CLASS, string))
1060 return -EINVAL;
1061
1062 pevents->source_class = string;
1063 break;
1064
1065 case HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY:
1066 pevents->category = value;
1067 break;
1068
1069 case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY:
1070 pevents->possible_severity = value;
1071 break;
1072
1073 case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS:
1074 pevents->possible_status = value;
1075 break;
1076
1077 default:
1078 return -EINVAL;
1079 }
1080 }
1081
1082 return 0;
1083 }
1084
1085 /*
1086 * check_event_wobj - validate a HPBIOS_BIOSEvent instance
1087 * @wobj: pointer to WMI object instance to check
1088 *
1089 * Returns 0 on success, or a negative error code on error.
1090 */
check_event_wobj(const union acpi_object * wobj)1091 static int check_event_wobj(const union acpi_object *wobj)
1092 {
1093 return check_wobj(wobj, hp_wmi_event_property_map,
1094 HP_WMI_EVENT_PROPERTY_STATUS);
1095 }
1096
populate_event_from_wobj(struct device * dev,struct hp_wmi_event * event,union acpi_object * wobj)1097 static int populate_event_from_wobj(struct device *dev,
1098 struct hp_wmi_event *event,
1099 union acpi_object *wobj)
1100 {
1101 int prop = HP_WMI_EVENT_PROPERTY_NAME;
1102 union acpi_object *element;
1103 acpi_object_type type;
1104 char *string;
1105 u32 value;
1106 int err;
1107
1108 err = check_event_wobj(wobj);
1109 if (err)
1110 return err;
1111
1112 element = wobj->package.elements;
1113
1114 for (; prop <= HP_WMI_EVENT_PROPERTY_CATEGORY; prop++, element++) {
1115 type = hp_wmi_event_property_map[prop];
1116
1117 err = extract_acpi_value(dev, element, type, &value, &string);
1118 if (err)
1119 return err;
1120
1121 switch (prop) {
1122 case HP_WMI_EVENT_PROPERTY_NAME:
1123 event->name = string;
1124 break;
1125
1126 case HP_WMI_EVENT_PROPERTY_DESCRIPTION:
1127 event->description = string;
1128 break;
1129
1130 case HP_WMI_EVENT_PROPERTY_CATEGORY:
1131 event->category = value;
1132 break;
1133
1134 default:
1135 return -EINVAL;
1136 }
1137 }
1138
1139 return 0;
1140 }
1141
1142 /*
1143 * classify_event - classify an event
1144 * @name: event name
1145 * @category: event category
1146 *
1147 * Classify instances of both HPBIOS_PlatformEvents and HPBIOS_BIOSEvent from
1148 * property values. Recognition criteria are based on multiple ACPI dumps [3].
1149 *
1150 * Returns an enum hp_wmi_type value on success,
1151 * or a negative value if the event type is unsupported.
1152 */
classify_event(const char * event_name,u32 category)1153 static int classify_event(const char *event_name, u32 category)
1154 {
1155 if (category != HP_WMI_CATEGORY_SENSOR)
1156 return -EINVAL;
1157
1158 /* Fan events have Name "X Stall". */
1159 if (strstr(event_name, HP_WMI_PATTERN_FAN_ALARM))
1160 return HP_WMI_TYPE_AIR_FLOW;
1161
1162 /* Intrusion events have Name "Hood Intrusion". */
1163 if (!strcmp(event_name, HP_WMI_PATTERN_INTRUSION_ALARM))
1164 return HP_WMI_TYPE_INTRUSION;
1165
1166 /*
1167 * Temperature events have Name either "Thermal Caution" or
1168 * "Thermal Critical". Deal only with "Thermal Critical" events.
1169 *
1170 * "Thermal Caution" events have Status "Stressed", informing us that
1171 * the OperationalStatus of the related sensor has become "Stressed".
1172 * However, this is already a fault condition that will clear itself
1173 * when the sensor recovers, so we have no further interest in them.
1174 */
1175 if (!strcmp(event_name, HP_WMI_PATTERN_TEMP_ALARM))
1176 return HP_WMI_TYPE_TEMPERATURE;
1177
1178 return -EINVAL;
1179 }
1180
1181 /*
1182 * interpret_info - interpret sensor for hwmon
1183 * @info: pointer to sensor info struct
1184 *
1185 * Should be called after the numeric sensor member has been updated.
1186 */
interpret_info(struct hp_wmi_info * info)1187 static void interpret_info(struct hp_wmi_info *info)
1188 {
1189 const struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;
1190
1191 info->cached_val = scale_numeric_sensor(nsensor);
1192 info->last_updated = jiffies;
1193 }
1194
1195 /*
1196 * hp_wmi_update_info - poll WMI to update sensor info
1197 * @state: pointer to driver state
1198 * @info: pointer to sensor info struct
1199 *
1200 * Returns 0 on success, or a negative error code on error.
1201 */
hp_wmi_update_info(struct hp_wmi_sensors * state,struct hp_wmi_info * info)1202 static int hp_wmi_update_info(struct hp_wmi_sensors *state,
1203 struct hp_wmi_info *info)
1204 {
1205 struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;
1206 struct device *dev = &state->wdev->dev;
1207 const union acpi_object *wobj;
1208 u8 instance = info->instance;
1209 int ret = 0;
1210
1211 if (time_after(jiffies, info->last_updated + HZ)) {
1212 mutex_lock(&state->lock);
1213
1214 wobj = wmidev_block_query(state->wdev, instance);
1215 if (!wobj) {
1216 ret = -EIO;
1217 goto out_unlock;
1218 }
1219
1220 update_numeric_sensor_from_wobj(dev, nsensor, wobj);
1221
1222 interpret_info(info);
1223
1224 kfree(wobj);
1225
1226 out_unlock:
1227 mutex_unlock(&state->lock);
1228 }
1229
1230 return ret;
1231 }
1232
basic_string_show(struct seq_file * seqf,void * ignored)1233 static int basic_string_show(struct seq_file *seqf, void *ignored)
1234 {
1235 const char *str = seqf->private;
1236
1237 seq_printf(seqf, "%s\n", str);
1238
1239 return 0;
1240 }
1241 DEFINE_SHOW_ATTRIBUTE(basic_string);
1242
fungible_show(struct seq_file * seqf,enum hp_wmi_property prop)1243 static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop)
1244 {
1245 struct hp_wmi_numeric_sensor *nsensor;
1246 struct hp_wmi_sensors *state;
1247 struct hp_wmi_info *info;
1248 int err;
1249
1250 info = seqf->private;
1251 state = info->state;
1252 nsensor = &info->nsensor;
1253
1254 err = hp_wmi_update_info(state, info);
1255 if (err)
1256 return err;
1257
1258 switch (prop) {
1259 case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
1260 seq_printf(seqf, "%u\n", nsensor->operational_status);
1261 break;
1262
1263 case HP_WMI_PROPERTY_CURRENT_STATE:
1264 mutex_lock(&state->lock);
1265 seq_printf(seqf, "%s\n", nsensor->current_state);
1266 mutex_unlock(&state->lock);
1267 break;
1268
1269 case HP_WMI_PROPERTY_UNIT_MODIFIER:
1270 seq_printf(seqf, "%d\n", nsensor->unit_modifier);
1271 break;
1272
1273 case HP_WMI_PROPERTY_CURRENT_READING:
1274 seq_printf(seqf, "%u\n", nsensor->current_reading);
1275 break;
1276
1277 default:
1278 return -EOPNOTSUPP;
1279 }
1280
1281 return 0;
1282 }
1283
operational_status_show(struct seq_file * seqf,void * ignored)1284 static int operational_status_show(struct seq_file *seqf, void *ignored)
1285 {
1286 return fungible_show(seqf, HP_WMI_PROPERTY_OPERATIONAL_STATUS);
1287 }
1288 DEFINE_SHOW_ATTRIBUTE(operational_status);
1289
current_state_show(struct seq_file * seqf,void * ignored)1290 static int current_state_show(struct seq_file *seqf, void *ignored)
1291 {
1292 return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_STATE);
1293 }
1294 DEFINE_SHOW_ATTRIBUTE(current_state);
1295
possible_states_show(struct seq_file * seqf,void * ignored)1296 static int possible_states_show(struct seq_file *seqf, void *ignored)
1297 {
1298 struct hp_wmi_numeric_sensor *nsensor = seqf->private;
1299 u8 i;
1300
1301 for (i = 0; i < nsensor->size; i++)
1302 seq_printf(seqf, "%s%s", i ? "," : "",
1303 nsensor->possible_states[i]);
1304
1305 seq_puts(seqf, "\n");
1306
1307 return 0;
1308 }
1309 DEFINE_SHOW_ATTRIBUTE(possible_states);
1310
unit_modifier_show(struct seq_file * seqf,void * ignored)1311 static int unit_modifier_show(struct seq_file *seqf, void *ignored)
1312 {
1313 return fungible_show(seqf, HP_WMI_PROPERTY_UNIT_MODIFIER);
1314 }
1315 DEFINE_SHOW_ATTRIBUTE(unit_modifier);
1316
current_reading_show(struct seq_file * seqf,void * ignored)1317 static int current_reading_show(struct seq_file *seqf, void *ignored)
1318 {
1319 return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_READING);
1320 }
1321 DEFINE_SHOW_ATTRIBUTE(current_reading);
1322
1323 /* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */
hp_wmi_devm_debugfs_remove(void * res)1324 static void hp_wmi_devm_debugfs_remove(void *res)
1325 {
1326 debugfs_remove_recursive(res);
1327 }
1328
1329 /* hp_wmi_debugfs_init - create and populate debugfs directory tree */
hp_wmi_debugfs_init(struct device * dev,struct hp_wmi_info * info,struct hp_wmi_platform_events * pevents,u8 icount,u8 pcount,bool is_new)1330 static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info,
1331 struct hp_wmi_platform_events *pevents,
1332 u8 icount, u8 pcount, bool is_new)
1333 {
1334 struct hp_wmi_numeric_sensor *nsensor;
1335 char buf[HP_WMI_MAX_STR_SIZE];
1336 struct dentry *debugfs;
1337 struct dentry *entries;
1338 struct dentry *dir;
1339 int err;
1340 u8 i;
1341
1342 /* dev_name() gives a not-very-friendly GUID for WMI devices. */
1343 scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id);
1344
1345 debugfs = debugfs_create_dir(buf, NULL);
1346 if (IS_ERR(debugfs))
1347 return;
1348
1349 err = devm_add_action_or_reset(dev, hp_wmi_devm_debugfs_remove,
1350 debugfs);
1351 if (err)
1352 return;
1353
1354 entries = debugfs_create_dir("sensor", debugfs);
1355
1356 for (i = 0; i < icount; i++, info++) {
1357 nsensor = &info->nsensor;
1358
1359 scnprintf(buf, sizeof(buf), "%u", i);
1360 dir = debugfs_create_dir(buf, entries);
1361
1362 debugfs_create_file("name", 0444, dir,
1363 (void *)nsensor->name,
1364 &basic_string_fops);
1365
1366 debugfs_create_file("description", 0444, dir,
1367 (void *)nsensor->description,
1368 &basic_string_fops);
1369
1370 debugfs_create_u32("sensor_type", 0444, dir,
1371 &nsensor->sensor_type);
1372
1373 debugfs_create_file("other_sensor_type", 0444, dir,
1374 (void *)nsensor->other_sensor_type,
1375 &basic_string_fops);
1376
1377 debugfs_create_file("operational_status", 0444, dir,
1378 info, &operational_status_fops);
1379
1380 debugfs_create_file("possible_states", 0444, dir,
1381 nsensor, &possible_states_fops);
1382
1383 debugfs_create_file("current_state", 0444, dir,
1384 info, ¤t_state_fops);
1385
1386 debugfs_create_u32("base_units", 0444, dir,
1387 &nsensor->base_units);
1388
1389 debugfs_create_file("unit_modifier", 0444, dir,
1390 info, &unit_modifier_fops);
1391
1392 debugfs_create_file("current_reading", 0444, dir,
1393 info, ¤t_reading_fops);
1394
1395 if (is_new)
1396 debugfs_create_u32("rate_units", 0444, dir,
1397 &nsensor->rate_units);
1398 }
1399
1400 if (!pcount)
1401 return;
1402
1403 entries = debugfs_create_dir("platform_events", debugfs);
1404
1405 for (i = 0; i < pcount; i++, pevents++) {
1406 scnprintf(buf, sizeof(buf), "%u", i);
1407 dir = debugfs_create_dir(buf, entries);
1408
1409 debugfs_create_file("name", 0444, dir,
1410 (void *)pevents->name,
1411 &basic_string_fops);
1412
1413 debugfs_create_file("description", 0444, dir,
1414 (void *)pevents->description,
1415 &basic_string_fops);
1416
1417 debugfs_create_file("source_namespace", 0444, dir,
1418 (void *)pevents->source_namespace,
1419 &basic_string_fops);
1420
1421 debugfs_create_file("source_class", 0444, dir,
1422 (void *)pevents->source_class,
1423 &basic_string_fops);
1424
1425 debugfs_create_u32("category", 0444, dir,
1426 &pevents->category);
1427
1428 debugfs_create_u32("possible_severity", 0444, dir,
1429 &pevents->possible_severity);
1430
1431 debugfs_create_u32("possible_status", 0444, dir,
1432 &pevents->possible_status);
1433 }
1434 }
1435
hp_wmi_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)1436 static umode_t hp_wmi_hwmon_is_visible(const void *drvdata,
1437 enum hwmon_sensor_types type,
1438 u32 attr, int channel)
1439 {
1440 const struct hp_wmi_sensors *state = drvdata;
1441 const struct hp_wmi_info *info;
1442
1443 if (type == hwmon_intrusion)
1444 return state->has_intrusion ? 0644 : 0;
1445
1446 if (!state->info_map[type] || !state->info_map[type][channel])
1447 return 0;
1448
1449 info = state->info_map[type][channel];
1450
1451 if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
1452 (type == hwmon_fan && attr == hwmon_fan_alarm))
1453 return info->has_alarm ? 0444 : 0;
1454
1455 return 0444;
1456 }
1457
hp_wmi_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * out_val)1458 static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
1459 u32 attr, int channel, long *out_val)
1460 {
1461 struct hp_wmi_sensors *state = dev_get_drvdata(dev);
1462 const struct hp_wmi_numeric_sensor *nsensor;
1463 struct hp_wmi_info *info;
1464 int err;
1465
1466 if (type == hwmon_intrusion) {
1467 *out_val = state->intrusion ? 1 : 0;
1468
1469 return 0;
1470 }
1471
1472 info = state->info_map[type][channel];
1473
1474 if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
1475 (type == hwmon_fan && attr == hwmon_fan_alarm)) {
1476 *out_val = info->alarm ? 1 : 0;
1477 info->alarm = false;
1478
1479 return 0;
1480 }
1481
1482 nsensor = &info->nsensor;
1483
1484 err = hp_wmi_update_info(state, info);
1485 if (err)
1486 return err;
1487
1488 if ((type == hwmon_temp && attr == hwmon_temp_fault) ||
1489 (type == hwmon_fan && attr == hwmon_fan_fault))
1490 *out_val = numeric_sensor_has_fault(nsensor);
1491 else
1492 *out_val = info->cached_val;
1493
1494 return 0;
1495 }
1496
hp_wmi_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** out_str)1497 static int hp_wmi_hwmon_read_string(struct device *dev,
1498 enum hwmon_sensor_types type, u32 attr,
1499 int channel, const char **out_str)
1500 {
1501 const struct hp_wmi_sensors *state = dev_get_drvdata(dev);
1502 const struct hp_wmi_info *info;
1503
1504 info = state->info_map[type][channel];
1505 *out_str = info->nsensor.name;
1506
1507 return 0;
1508 }
1509
hp_wmi_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)1510 static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
1511 u32 attr, int channel, long val)
1512 {
1513 struct hp_wmi_sensors *state = dev_get_drvdata(dev);
1514
1515 if (val)
1516 return -EINVAL;
1517
1518 mutex_lock(&state->lock);
1519
1520 state->intrusion = false;
1521
1522 mutex_unlock(&state->lock);
1523
1524 return 0;
1525 }
1526
1527 static const struct hwmon_ops hp_wmi_hwmon_ops = {
1528 .is_visible = hp_wmi_hwmon_is_visible,
1529 .read = hp_wmi_hwmon_read,
1530 .read_string = hp_wmi_hwmon_read_string,
1531 .write = hp_wmi_hwmon_write,
1532 };
1533
1534 static struct hwmon_chip_info hp_wmi_chip_info = {
1535 .ops = &hp_wmi_hwmon_ops,
1536 .info = NULL,
1537 };
1538
match_fan_event(struct hp_wmi_sensors * state,const char * event_description)1539 static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
1540 const char *event_description)
1541 {
1542 struct hp_wmi_info **ptr_info = state->info_map[hwmon_fan];
1543 u8 fan_count = state->channel_count[hwmon_fan];
1544 struct hp_wmi_info *info;
1545 const char *name;
1546 u8 i;
1547
1548 /* Fan event has Description "X Speed". Sensor has Name "X[ Speed]". */
1549
1550 for (i = 0; i < fan_count; i++, ptr_info++) {
1551 info = *ptr_info;
1552 name = info->nsensor.name;
1553
1554 if (strstr(event_description, name))
1555 return info;
1556 }
1557
1558 return NULL;
1559 }
1560
match_temp_events(struct hp_wmi_sensors * state,const char * event_description,struct hp_wmi_info * temp_info[])1561 static u8 match_temp_events(struct hp_wmi_sensors *state,
1562 const char *event_description,
1563 struct hp_wmi_info *temp_info[])
1564 {
1565 struct hp_wmi_info **ptr_info = state->info_map[hwmon_temp];
1566 u8 temp_count = state->channel_count[hwmon_temp];
1567 struct hp_wmi_info *info;
1568 const char *name;
1569 u8 count = 0;
1570 bool is_cpu;
1571 bool is_sys;
1572 u8 i;
1573
1574 /* Description is either "CPU Thermal Index" or "Chassis Thermal Index". */
1575
1576 is_cpu = !strcmp(event_description, HP_WMI_PATTERN_CPU_TEMP);
1577 is_sys = !strcmp(event_description, HP_WMI_PATTERN_SYS_TEMP);
1578 if (!is_cpu && !is_sys)
1579 return 0;
1580
1581 /*
1582 * CPU event: Match one sensor with Name either "CPU Thermal Index" or
1583 * "CPU Temperature", or multiple with Name(s) "CPU[#] Temperature".
1584 *
1585 * Chassis event: Match one sensor with Name either
1586 * "Chassis Thermal Index" or "System Ambient Temperature".
1587 */
1588
1589 for (i = 0; i < temp_count; i++, ptr_info++) {
1590 info = *ptr_info;
1591 name = info->nsensor.name;
1592
1593 if ((is_cpu && (!strcmp(name, HP_WMI_PATTERN_CPU_TEMP) ||
1594 !strcmp(name, HP_WMI_PATTERN_CPU_TEMP2))) ||
1595 (is_sys && (!strcmp(name, HP_WMI_PATTERN_SYS_TEMP) ||
1596 !strcmp(name, HP_WMI_PATTERN_SYS_TEMP2)))) {
1597 temp_info[0] = info;
1598 return 1;
1599 }
1600
1601 if (is_cpu && (strstr(name, HP_WMI_PATTERN_CPU) &&
1602 strstr(name, HP_WMI_PATTERN_TEMP)))
1603 temp_info[count++] = info;
1604 }
1605
1606 return count;
1607 }
1608
1609 /* hp_wmi_devm_debugfs_remove - devm callback for WMI event handler removal */
hp_wmi_devm_notify_remove(void * ignored)1610 static void hp_wmi_devm_notify_remove(void *ignored)
1611 {
1612 wmi_remove_notify_handler(HP_WMI_EVENT_GUID);
1613 }
1614
1615 /* hp_wmi_notify - WMI event notification handler */
hp_wmi_notify(union acpi_object * wobj,void * context)1616 static void hp_wmi_notify(union acpi_object *wobj, void *context)
1617 {
1618 struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};
1619 struct hp_wmi_sensors *state = context;
1620 struct device *dev = &state->wdev->dev;
1621 struct hp_wmi_event event = {};
1622 struct hp_wmi_info *fan_info;
1623 acpi_status err;
1624 int event_type;
1625 u8 count;
1626
1627 /*
1628 * The following warning may occur in the kernel log:
1629 *
1630 * ACPI Warning: \_SB.WMID._WED: Return type mismatch -
1631 * found Package, expected Integer/String/Buffer
1632 *
1633 * After using [4] to decode BMOF blobs found in [3], careless copying
1634 * of BIOS code seems the most likely explanation for this warning.
1635 * HP_WMI_EVENT_GUID refers to \\.\root\WMI\HPBIOS_BIOSEvent on
1636 * business-class systems, but it refers to \\.\root\WMI\hpqBEvnt on
1637 * non-business-class systems. Per the existing hp-wmi driver, it
1638 * looks like an instance of hpqBEvnt delivered as event data may
1639 * indeed take the form of a raw ACPI_BUFFER on non-business-class
1640 * systems ("may" because ASL shows some BIOSes do strange things).
1641 *
1642 * In any case, we can ignore this warning, because we always validate
1643 * the event data to ensure it is an ACPI_PACKAGE containing a
1644 * HPBIOS_BIOSEvent instance.
1645 */
1646
1647 if (!wobj)
1648 return;
1649
1650 mutex_lock(&state->lock);
1651
1652 err = populate_event_from_wobj(dev, &event, wobj);
1653 if (err) {
1654 dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type);
1655 goto out_free;
1656 }
1657
1658 event_type = classify_event(event.name, event.category);
1659 switch (event_type) {
1660 case HP_WMI_TYPE_AIR_FLOW:
1661 fan_info = match_fan_event(state, event.description);
1662 if (fan_info)
1663 fan_info->alarm = true;
1664 break;
1665
1666 case HP_WMI_TYPE_INTRUSION:
1667 state->intrusion = true;
1668 break;
1669
1670 case HP_WMI_TYPE_TEMPERATURE:
1671 count = match_temp_events(state, event.description, temp_info);
1672 while (count)
1673 temp_info[--count]->alarm = true;
1674 break;
1675
1676 default:
1677 break;
1678 }
1679
1680 out_free:
1681 devm_kfree(dev, event.name);
1682 devm_kfree(dev, event.description);
1683
1684 mutex_unlock(&state->lock);
1685 }
1686
init_platform_events(struct device * dev,struct hp_wmi_platform_events ** out_pevents,u8 * out_pcount)1687 static int init_platform_events(struct device *dev,
1688 struct hp_wmi_platform_events **out_pevents,
1689 u8 *out_pcount)
1690 {
1691 struct hp_wmi_platform_events *pevents_arr;
1692 struct hp_wmi_platform_events *pevents;
1693 union acpi_object *wobj;
1694 u8 count;
1695 int err;
1696 u8 i;
1697
1698 count = hp_wmi_wobj_instance_count(HP_WMI_PLATFORM_EVENTS_GUID);
1699 if (!count) {
1700 *out_pcount = 0;
1701
1702 dev_dbg(dev, "No platform events\n");
1703
1704 return 0;
1705 }
1706
1707 pevents_arr = devm_kcalloc(dev, count, sizeof(*pevents), GFP_KERNEL);
1708 if (!pevents_arr)
1709 return -ENOMEM;
1710
1711 for (i = 0, pevents = pevents_arr; i < count; i++, pevents++) {
1712 wobj = hp_wmi_get_wobj(HP_WMI_PLATFORM_EVENTS_GUID, i);
1713 if (!wobj)
1714 return -EIO;
1715
1716 err = populate_platform_events_from_wobj(dev, pevents, wobj);
1717
1718 kfree(wobj);
1719
1720 if (err)
1721 return err;
1722 }
1723
1724 *out_pevents = pevents_arr;
1725 *out_pcount = count;
1726
1727 dev_dbg(dev, "Found %u platform events\n", count);
1728
1729 return 0;
1730 }
1731
init_numeric_sensors(struct hp_wmi_sensors * state,struct hp_wmi_info * connected[],struct hp_wmi_info ** out_info,u8 * out_icount,u8 * out_count,bool * out_is_new)1732 static int init_numeric_sensors(struct hp_wmi_sensors *state,
1733 struct hp_wmi_info *connected[],
1734 struct hp_wmi_info **out_info,
1735 u8 *out_icount, u8 *out_count,
1736 bool *out_is_new)
1737 {
1738 struct hp_wmi_info ***info_map = state->info_map;
1739 u8 *channel_count = state->channel_count;
1740 struct device *dev = &state->wdev->dev;
1741 struct hp_wmi_numeric_sensor *nsensor;
1742 u8 channel_index[hwmon_max] = {};
1743 enum hwmon_sensor_types type;
1744 struct hp_wmi_info *info_arr;
1745 struct hp_wmi_info *info;
1746 union acpi_object *wobj;
1747 u8 count = 0;
1748 bool is_new;
1749 u8 icount;
1750 int wtype;
1751 int err;
1752 u8 c;
1753 u8 i;
1754
1755 icount = hp_wmi_wobj_instance_count(HP_WMI_NUMERIC_SENSOR_GUID);
1756 if (!icount)
1757 return -ENODATA;
1758
1759 info_arr = devm_kcalloc(dev, icount, sizeof(*info), GFP_KERNEL);
1760 if (!info_arr)
1761 return -ENOMEM;
1762
1763 for (i = 0, info = info_arr; i < icount; i++, info++) {
1764 wobj = wmidev_block_query(state->wdev, i);
1765 if (!wobj)
1766 return -EIO;
1767
1768 info->instance = i;
1769 info->state = state;
1770 nsensor = &info->nsensor;
1771
1772 err = populate_numeric_sensor_from_wobj(dev, nsensor, wobj,
1773 &is_new);
1774
1775 kfree(wobj);
1776
1777 if (err)
1778 return err;
1779
1780 if (!numeric_sensor_is_connected(nsensor))
1781 continue;
1782
1783 wtype = classify_numeric_sensor(nsensor);
1784 if (wtype < 0)
1785 continue;
1786
1787 type = hp_wmi_hwmon_type_map[wtype];
1788
1789 channel_count[type]++;
1790
1791 info->type = type;
1792
1793 interpret_info(info);
1794
1795 connected[count++] = info;
1796 }
1797
1798 dev_dbg(dev, "Found %u sensors (%u connected)\n", i, count);
1799
1800 for (i = 0; i < count; i++) {
1801 info = connected[i];
1802 type = info->type;
1803 c = channel_index[type]++;
1804
1805 if (!info_map[type]) {
1806 info_map[type] = devm_kcalloc(dev, channel_count[type],
1807 sizeof(*info_map),
1808 GFP_KERNEL);
1809 if (!info_map[type])
1810 return -ENOMEM;
1811 }
1812
1813 info_map[type][c] = info;
1814 }
1815
1816 *out_info = info_arr;
1817 *out_icount = icount;
1818 *out_count = count;
1819 *out_is_new = is_new;
1820
1821 return 0;
1822 }
1823
find_event_attributes(struct hp_wmi_sensors * state,struct hp_wmi_platform_events * pevents,u8 pevents_count)1824 static bool find_event_attributes(struct hp_wmi_sensors *state,
1825 struct hp_wmi_platform_events *pevents,
1826 u8 pevents_count)
1827 {
1828 /*
1829 * The existence of this HPBIOS_PlatformEvents instance:
1830 *
1831 * {
1832 * Name = "Rear Chassis Fan0 Stall";
1833 * Description = "Rear Chassis Fan0 Speed";
1834 * Category = 3; // "Sensor"
1835 * PossibleSeverity = 25; // "Critical Failure"
1836 * PossibleStatus = 5; // "Predictive Failure"
1837 * [...]
1838 * }
1839 *
1840 * means that this HPBIOS_BIOSEvent instance may occur:
1841 *
1842 * {
1843 * Name = "Rear Chassis Fan0 Stall";
1844 * Description = "Rear Chassis Fan0 Speed";
1845 * Category = 3; // "Sensor"
1846 * Severity = 25; // "Critical Failure"
1847 * Status = 5; // "Predictive Failure"
1848 * }
1849 *
1850 * After the event occurs (e.g. because the fan was unplugged),
1851 * polling the related HPBIOS_BIOSNumericSensor instance gives:
1852 *
1853 * {
1854 * Name = "Rear Chassis Fan0";
1855 * Description = "Reports rear chassis fan0 speed";
1856 * OperationalStatus = 5; // "Predictive Failure", was 3 ("OK")
1857 * CurrentReading = 0;
1858 * [...]
1859 * }
1860 *
1861 * In this example, the hwmon fan channel for "Rear Chassis Fan0"
1862 * should support the alarm flag and have it be set if the related
1863 * HPBIOS_BIOSEvent instance occurs.
1864 *
1865 * In addition to fan events, temperature (CPU/chassis) and intrusion
1866 * events are relevant to hwmon [2]. Note that much information in [2]
1867 * is unreliable; it is referenced in addition to ACPI dumps [3] merely
1868 * to support the conclusion that sensor and event names/descriptions
1869 * are systematic enough to allow this driver to match them.
1870 *
1871 * Complications and limitations:
1872 *
1873 * - Strings are freeform and may vary, cf. sensor Name "CPU0 Fan"
1874 * on a Z420 vs. "CPU Fan Speed" on an EliteOne 800 G1.
1875 * - Leading/trailing whitespace is a rare but real possibility [3].
1876 * - The HPBIOS_PlatformEvents object may not exist or its instances
1877 * may show that the system only has e.g. BIOS setting-related
1878 * events (cf. the ProBook 4540s and ProBook 470 G0 [3]).
1879 */
1880
1881 struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};
1882 const char *event_description;
1883 struct hp_wmi_info *fan_info;
1884 bool has_events = false;
1885 const char *event_name;
1886 u32 event_category;
1887 int event_type;
1888 u8 count;
1889 u8 i;
1890
1891 for (i = 0; i < pevents_count; i++, pevents++) {
1892 event_name = pevents->name;
1893 event_description = pevents->description;
1894 event_category = pevents->category;
1895
1896 event_type = classify_event(event_name, event_category);
1897 switch (event_type) {
1898 case HP_WMI_TYPE_AIR_FLOW:
1899 fan_info = match_fan_event(state, event_description);
1900 if (!fan_info)
1901 break;
1902
1903 fan_info->has_alarm = true;
1904 has_events = true;
1905 break;
1906
1907 case HP_WMI_TYPE_INTRUSION:
1908 state->has_intrusion = true;
1909 has_events = true;
1910 break;
1911
1912 case HP_WMI_TYPE_TEMPERATURE:
1913 count = match_temp_events(state, event_description,
1914 temp_info);
1915 if (!count)
1916 break;
1917
1918 while (count)
1919 temp_info[--count]->has_alarm = true;
1920 has_events = true;
1921 break;
1922
1923 default:
1924 break;
1925 }
1926 }
1927
1928 return has_events;
1929 }
1930
make_chip_info(struct hp_wmi_sensors * state,bool has_events)1931 static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
1932 {
1933 const struct hwmon_channel_info **ptr_channel_info;
1934 struct hp_wmi_info ***info_map = state->info_map;
1935 u8 *channel_count = state->channel_count;
1936 struct hwmon_channel_info *channel_info;
1937 struct device *dev = &state->wdev->dev;
1938 enum hwmon_sensor_types type;
1939 u8 type_count = 0;
1940 u32 *config;
1941 u32 attr;
1942 u8 count;
1943 u8 i;
1944
1945 if (channel_count[hwmon_temp])
1946 channel_count[hwmon_chip] = 1;
1947
1948 if (has_events && state->has_intrusion)
1949 channel_count[hwmon_intrusion] = 1;
1950
1951 for (type = hwmon_chip; type < hwmon_max; type++)
1952 if (channel_count[type])
1953 type_count++;
1954
1955 channel_info = devm_kcalloc(dev, type_count,
1956 sizeof(*channel_info), GFP_KERNEL);
1957 if (!channel_info)
1958 return -ENOMEM;
1959
1960 ptr_channel_info = devm_kcalloc(dev, type_count + 1,
1961 sizeof(*ptr_channel_info), GFP_KERNEL);
1962 if (!ptr_channel_info)
1963 return -ENOMEM;
1964
1965 hp_wmi_chip_info.info = ptr_channel_info;
1966
1967 for (type = hwmon_chip; type < hwmon_max; type++) {
1968 count = channel_count[type];
1969 if (!count)
1970 continue;
1971
1972 config = devm_kcalloc(dev, count + 1,
1973 sizeof(*config), GFP_KERNEL);
1974 if (!config)
1975 return -ENOMEM;
1976
1977 attr = hp_wmi_hwmon_attributes[type];
1978 channel_info->type = type;
1979 channel_info->config = config;
1980 memset32(config, attr, count);
1981
1982 *ptr_channel_info++ = channel_info++;
1983
1984 if (!has_events || (type != hwmon_temp && type != hwmon_fan))
1985 continue;
1986
1987 attr = type == hwmon_temp ? HWMON_T_ALARM : HWMON_F_ALARM;
1988
1989 for (i = 0; i < count; i++)
1990 if (info_map[type][i]->has_alarm)
1991 config[i] |= attr;
1992 }
1993
1994 return 0;
1995 }
1996
add_event_handler(struct hp_wmi_sensors * state)1997 static bool add_event_handler(struct hp_wmi_sensors *state)
1998 {
1999 struct device *dev = &state->wdev->dev;
2000 int err;
2001
2002 err = wmi_install_notify_handler(HP_WMI_EVENT_GUID,
2003 hp_wmi_notify, state);
2004 if (err) {
2005 dev_info(dev, "Failed to subscribe to WMI event\n");
2006 return false;
2007 }
2008
2009 err = devm_add_action_or_reset(dev, hp_wmi_devm_notify_remove, NULL);
2010 if (err)
2011 return false;
2012
2013 return true;
2014 }
2015
hp_wmi_sensors_init(struct hp_wmi_sensors * state)2016 static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
2017 {
2018 struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES];
2019 struct hp_wmi_platform_events *pevents = NULL;
2020 struct device *dev = &state->wdev->dev;
2021 struct hp_wmi_info *info;
2022 struct device *hwdev;
2023 bool has_events;
2024 bool is_new;
2025 u8 icount;
2026 u8 pcount;
2027 u8 count;
2028 int err;
2029
2030 err = init_platform_events(dev, &pevents, &pcount);
2031 if (err)
2032 return err;
2033
2034 err = init_numeric_sensors(state, connected, &info,
2035 &icount, &count, &is_new);
2036 if (err)
2037 return err;
2038
2039 if (IS_ENABLED(CONFIG_DEBUG_FS))
2040 hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new);
2041
2042 if (!count)
2043 return 0; /* No connected sensors; debugfs only. */
2044
2045 has_events = find_event_attributes(state, pevents, pcount);
2046
2047 /* Survive failure to install WMI event handler. */
2048 if (has_events && !add_event_handler(state))
2049 has_events = false;
2050
2051 err = make_chip_info(state, has_events);
2052 if (err)
2053 return err;
2054
2055 hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
2056 state, &hp_wmi_chip_info,
2057 NULL);
2058 return PTR_ERR_OR_ZERO(hwdev);
2059 }
2060
hp_wmi_sensors_probe(struct wmi_device * wdev,const void * context)2061 static int hp_wmi_sensors_probe(struct wmi_device *wdev, const void *context)
2062 {
2063 struct device *dev = &wdev->dev;
2064 struct hp_wmi_sensors *state;
2065
2066 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
2067 if (!state)
2068 return -ENOMEM;
2069
2070 state->wdev = wdev;
2071
2072 mutex_init(&state->lock);
2073
2074 dev_set_drvdata(dev, state);
2075
2076 return hp_wmi_sensors_init(state);
2077 }
2078
2079 static const struct wmi_device_id hp_wmi_sensors_id_table[] = {
2080 { HP_WMI_NUMERIC_SENSOR_GUID, NULL },
2081 {},
2082 };
2083
2084 static struct wmi_driver hp_wmi_sensors_driver = {
2085 .driver = { .name = "hp-wmi-sensors" },
2086 .id_table = hp_wmi_sensors_id_table,
2087 .probe = hp_wmi_sensors_probe,
2088 };
2089 module_wmi_driver(hp_wmi_sensors_driver);
2090
2091 MODULE_AUTHOR("James Seo <james@equiv.tech>");
2092 MODULE_DESCRIPTION("HP WMI Sensors driver");
2093 MODULE_LICENSE("GPL");
2094