brintos

brintos / linux-shallow public Read only

0
0
Text · 55.4 KiB · d6bdad2 Raw
2078 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * hwmon driver for HP (and some HP Compaq) business-class computers that4 * 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.pdf12 * [2] Hewlett-Packard Development Company, L.P.,13 *     "HP Retail Manageability", 2012. [Online].14 *     Available: http://h10032.www1.hp.com/ctg/Manual/c03291135.pdf15 * [3] Linux Hardware Project, A. Ponomarenko et al.,16 *     "linuxhw/ACPI - Collect ACPI table dumps", 2018. [Online].17 *     Available: https://github.com/linuxhw/ACPI18 * [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer",19 *     2017. [Online]. Available: https://github.com/pali/bmfdec20 * [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-items22 */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		128U55#define HP_WMI_MAX_PROPERTIES		32U56#define HP_WMI_MAX_INSTANCES		32U57 58enum 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 67enum hp_wmi_category {68	HP_WMI_CATEGORY_SENSOR			= 3,69};70 71enum 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 81enum 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 97enum 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 107enum 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 122static 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 137enum 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 147static 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 157enum 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 165static 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 173static 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 180static 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 instance191 *192 * Two variants of HPBIOS_BIOSNumericSensor are known. The first is specified193 * in [1] and appears to be much more widespread. The second was discovered by194 * decoding BMOF blobs [4], seems to be found only in some newer ZBook systems195 * [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 are198 * accessed by name. For us, supporting both variants gets ugly and hacky at199 * 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 */265struct 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 instance282 *283 * Instances of this object reveal the set of possible HPBIOS_BIOSEvent284 * 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 */314struct 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 instance326 *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 */353struct hp_wmi_event {354	const char *name;355	const char *description;356	u32 category;357};358 359/*360 * struct hp_wmi_info - sensor info361 * @nsensor: numeric sensor properties362 * @instance: its WMI instance number363 * @state: pointer to driver state364 * @has_alarm: whether sensor has an alarm flag365 * @alarm: alarm flag366 * @type: its hwmon sensor type367 * @cached_val: current sensor reading value, scaled for hwmon368 * @last_updated: when these readings were last updated369 */370struct 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 state384 * @wdev: pointer to the parent WMI device385 * @info_map: sensor info structs by hwmon type and channel number386 * @channel_count: count of hwmon channels by hwmon type387 * @has_intrusion: whether an intrusion sensor is present388 * @intrusion: intrusion flag389 * @lock: mutex to lock polling WMI and changes to driver state390 */391struct 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 401static 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 417static 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 */446static 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 */463static 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 instance481 * @guid: WMI object GUID482 * @instance: WMI object instance number483 *484 * Returns a new WMI object instance on success, or NULL on error.485 * Caller must kfree() the result.486 */487static 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 */500static 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 509static 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 != valid_type) {530			if (type == ACPI_TYPE_BUFFER &&531			    valid_type == ACPI_TYPE_STRING &&532			    is_raw_wmi_string(elements[prop].buffer.pointer,533					      elements[prop].buffer.length))534				continue;535			return -EINVAL;536		}537	}538 539	return 0;540}541 542static int extract_acpi_value(struct device *dev,543			      union acpi_object *element,544			      acpi_object_type type,545			      u32 *out_value, char **out_string)546{547	switch (type) {548	case ACPI_TYPE_INTEGER:549		*out_value = element->integer.value;550		break;551 552	case ACPI_TYPE_STRING:553		*out_string = element->type == ACPI_TYPE_BUFFER ?554			hp_wmi_wstrdup(dev, element->buffer.pointer) :555			hp_wmi_strdup(dev, strim(element->string.pointer));556		if (!*out_string)557			return -ENOMEM;558		break;559 560	default:561		return -EINVAL;562	}563 564	return 0;565}566 567/*568 * check_numeric_sensor_wobj - validate a HPBIOS_BIOSNumericSensor instance569 * @wobj: pointer to WMI object instance to check570 * @out_size: out pointer to count of possible states571 * @out_is_new: out pointer to whether this is a "new" variant object572 *573 * Returns 0 on success, or a negative error code on error.574 */575static int check_numeric_sensor_wobj(const union acpi_object *wobj,576				     u8 *out_size, bool *out_is_new)577{578	acpi_object_type type = wobj->type;579	int prop = HP_WMI_PROPERTY_NAME;580	acpi_object_type valid_type;581	union acpi_object *elements;582	u32 elem_count;583	int last_prop;584	bool is_new;585	u8 count;586	u32 j;587	u32 i;588 589	if (type != ACPI_TYPE_PACKAGE)590		return -EINVAL;591 592	/*593	 * elements is a variable-length array of ACPI objects, one for594	 * each property of the WMI object instance, except that the595	 * strings in PossibleStates[] are flattened into this array596	 * as if each individual string were a property by itself.597	 */598	elements = wobj->package.elements;599 600	elem_count = wobj->package.count;601	if (elem_count <= HP_WMI_PROPERTY_SIZE ||602	    elem_count > HP_WMI_MAX_PROPERTIES)603		return -EINVAL;604 605	type = elements[HP_WMI_PROPERTY_SIZE].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_STRING:613		is_new = false;614		last_prop = HP_WMI_PROPERTY_CURRENT_READING;615		break;616 617	default:618		return -EINVAL;619	}620 621	/*622	 * In general, the count of PossibleStates[] must be > 0.623	 * Also, the old variant lacks the Size property, so we may need to624	 * reduce the value of last_prop by 1 when doing arithmetic with it.625	 */626	if (elem_count < last_prop - !is_new + 1)627		return -EINVAL;628 629	count = elem_count - (last_prop - !is_new);630 631	for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) {632		type = elements[i].type;633		valid_type = hp_wmi_property_map[prop];634		if (type != valid_type)635			return -EINVAL;636 637		switch (prop) {638		case HP_WMI_PROPERTY_OPERATIONAL_STATUS:639			/* Old variant: CurrentState follows OperationalStatus. */640			if (!is_new)641				prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;642			break;643 644		case HP_WMI_PROPERTY_SIZE:645			/* New variant: Size == count of PossibleStates[]. */646			if (count != elements[i].integer.value)647				return -EINVAL;648			break;649 650		case HP_WMI_PROPERTY_POSSIBLE_STATES:651			/* PossibleStates[0] has already been type-checked. */652			for (j = 0; i + 1 < elem_count && j + 1 < count; j++) {653				type = elements[++i].type;654				if (type != valid_type)655					return -EINVAL;656			}657 658			/* Old variant: BaseUnits follows PossibleStates[]. */659			if (!is_new)660				prop = HP_WMI_PROPERTY_BASE_UNITS - 1;661			break;662 663		case HP_WMI_PROPERTY_CURRENT_STATE:664			/* Old variant: PossibleStates[] follows CurrentState. */665			if (!is_new)666				prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;667			break;668		}669	}670 671	if (prop != last_prop + 1)672		return -EINVAL;673 674	*out_size = count;675	*out_is_new = is_new;676 677	return 0;678}679 680static int681numeric_sensor_is_connected(const struct hp_wmi_numeric_sensor *nsensor)682{683	u32 operational_status = nsensor->operational_status;684 685	return operational_status != HP_WMI_STATUS_NO_CONTACT;686}687 688static int numeric_sensor_has_fault(const struct hp_wmi_numeric_sensor *nsensor)689{690	u32 operational_status = nsensor->operational_status;691 692	switch (operational_status) {693	case HP_WMI_STATUS_DEGRADED:694	case HP_WMI_STATUS_STRESSED:		/* e.g. Overload, overtemp. */695	case HP_WMI_STATUS_PREDICTIVE_FAILURE:	/* e.g. Fan removed. */696	case HP_WMI_STATUS_ERROR:697	case HP_WMI_STATUS_NON_RECOVERABLE_ERROR:698	case HP_WMI_STATUS_NO_CONTACT:699	case HP_WMI_STATUS_LOST_COMMUNICATION:700	case HP_WMI_STATUS_ABORTED:701	case HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR:702 703	/* Assume combination by addition; bitwise OR doesn't make sense. */704	case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_DEGRADED:705	case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_ERROR:706		return true;707	}708 709	return false;710}711 712/* scale_numeric_sensor - scale sensor reading for hwmon */713static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)714{715	u32 current_reading = nsensor->current_reading;716	s32 unit_modifier = nsensor->unit_modifier;717	u32 sensor_type = nsensor->sensor_type;718	u32 base_units = nsensor->base_units;719	s32 target_modifier;720	long val;721 722	/* Fan readings are in RPM units; others are in milliunits. */723	target_modifier = sensor_type == HP_WMI_TYPE_AIR_FLOW ? 0 : -3;724 725	val = current_reading;726 727	for (; unit_modifier < target_modifier; unit_modifier++)728		val = DIV_ROUND_CLOSEST(val, 10);729 730	for (; unit_modifier > target_modifier; unit_modifier--) {731		if (val > LONG_MAX / 10) {732			val = LONG_MAX;733			break;734		}735		val *= 10;736	}737 738	if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {739		switch (base_units) {740		case HP_WMI_UNITS_DEGREES_F:741			val -= MILLI * 32;742			val = val <= LONG_MAX / 5 ?743				      DIV_ROUND_CLOSEST(val * 5, 9) :744				      DIV_ROUND_CLOSEST(val, 9) * 5;745			break;746 747		case HP_WMI_UNITS_DEGREES_K:748			val = milli_kelvin_to_millicelsius(val);749			break;750		}751	}752 753	return val;754}755 756/*757 * classify_numeric_sensor - classify a numeric sensor758 * @nsensor: pointer to numeric sensor struct759 *760 * Returns an enum hp_wmi_type value on success,761 * or a negative value if the sensor type is unsupported.762 */763static int classify_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)764{765	u32 sensor_type = nsensor->sensor_type;766	u32 base_units = nsensor->base_units;767	const char *name = nsensor->name;768 769	switch (sensor_type) {770	case HP_WMI_TYPE_TEMPERATURE:771		/*772		 * Some systems have sensors named "X Thermal Index" in "Other"773		 * units. Tested CPU sensor examples were found to be in °C,774		 * albeit perhaps "differently" accurate; e.g. readings were775		 * reliably -6°C vs. coretemp on a HP Compaq Elite 8300, and776		 * +8°C on an EliteOne G1 800. But this is still within the777		 * realm of plausibility for cheaply implemented motherboard778		 * sensors, and chassis readings were about as expected.779		 */780		if ((base_units == HP_WMI_UNITS_OTHER &&781		     strstr(name, HP_WMI_PATTERN_TEMP_SENSOR)) ||782		    base_units == HP_WMI_UNITS_DEGREES_C ||783		    base_units == HP_WMI_UNITS_DEGREES_F ||784		    base_units == HP_WMI_UNITS_DEGREES_K)785			return HP_WMI_TYPE_TEMPERATURE;786		break;787 788	case HP_WMI_TYPE_VOLTAGE:789		if (base_units == HP_WMI_UNITS_VOLTS)790			return HP_WMI_TYPE_VOLTAGE;791		break;792 793	case HP_WMI_TYPE_CURRENT:794		if (base_units == HP_WMI_UNITS_AMPS)795			return HP_WMI_TYPE_CURRENT;796		break;797 798	case HP_WMI_TYPE_AIR_FLOW:799		/*800		 * Strangely, HP considers fan RPM sensor type to be801		 * "Air Flow" instead of the more intuitive "Tachometer".802		 */803		if (base_units == HP_WMI_UNITS_RPM)804			return HP_WMI_TYPE_AIR_FLOW;805		break;806	}807 808	return -EINVAL;809}810 811static int812populate_numeric_sensor_from_wobj(struct device *dev,813				  struct hp_wmi_numeric_sensor *nsensor,814				  union acpi_object *wobj, bool *out_is_new)815{816	int last_prop = HP_WMI_PROPERTY_RATE_UNITS;817	int prop = HP_WMI_PROPERTY_NAME;818	const char **possible_states;819	union acpi_object *element;820	acpi_object_type type;821	char *string;822	bool is_new;823	u32 value;824	u8 size;825	int err;826 827	err = check_numeric_sensor_wobj(wobj, &size, &is_new);828	if (err)829		return err;830 831	possible_states = devm_kcalloc(dev, size, sizeof(*possible_states),832				       GFP_KERNEL);833	if (!possible_states)834		return -ENOMEM;835 836	element = wobj->package.elements;837	nsensor->possible_states = possible_states;838	nsensor->size = size;839 840	if (!is_new)841		last_prop = HP_WMI_PROPERTY_CURRENT_READING;842 843	for (; prop <= last_prop; prop++) {844		type = hp_wmi_property_map[prop];845 846		err = extract_acpi_value(dev, element, type, &value, &string);847		if (err)848			return err;849 850		element++;851 852		switch (prop) {853		case HP_WMI_PROPERTY_NAME:854			nsensor->name = string;855			break;856 857		case HP_WMI_PROPERTY_DESCRIPTION:858			nsensor->description = string;859			break;860 861		case HP_WMI_PROPERTY_SENSOR_TYPE:862			if (value > HP_WMI_TYPE_AIR_FLOW)863				return -EINVAL;864 865			nsensor->sensor_type = value;866			break;867 868		case HP_WMI_PROPERTY_OTHER_SENSOR_TYPE:869			nsensor->other_sensor_type = string;870			break;871 872		case HP_WMI_PROPERTY_OPERATIONAL_STATUS:873			nsensor->operational_status = value;874 875			/* Old variant: CurrentState follows OperationalStatus. */876			if (!is_new)877				prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;878			break;879 880		case HP_WMI_PROPERTY_SIZE:881			break;			/* Already set. */882 883		case HP_WMI_PROPERTY_POSSIBLE_STATES:884			*possible_states++ = string;885			if (--size)886				prop--;887 888			/* Old variant: BaseUnits follows PossibleStates[]. */889			if (!is_new && !size)890				prop = HP_WMI_PROPERTY_BASE_UNITS - 1;891			break;892 893		case HP_WMI_PROPERTY_CURRENT_STATE:894			nsensor->current_state = string;895 896			/* Old variant: PossibleStates[] follows CurrentState. */897			if (!is_new)898				prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;899			break;900 901		case HP_WMI_PROPERTY_BASE_UNITS:902			nsensor->base_units = value;903			break;904 905		case HP_WMI_PROPERTY_UNIT_MODIFIER:906			/* UnitModifier is signed. */907			nsensor->unit_modifier = (s32)value;908			break;909 910		case HP_WMI_PROPERTY_CURRENT_READING:911			nsensor->current_reading = value;912			break;913 914		case HP_WMI_PROPERTY_RATE_UNITS:915			nsensor->rate_units = value;916			break;917 918		default:919			return -EINVAL;920		}921	}922 923	*out_is_new = is_new;924 925	return 0;926}927 928/* update_numeric_sensor_from_wobj - update fungible sensor properties */929static void930update_numeric_sensor_from_wobj(struct device *dev,931				struct hp_wmi_numeric_sensor *nsensor,932				const union acpi_object *wobj)933{934	const union acpi_object *elements;935	const union acpi_object *element;936	const char *new_string;937	char *trimmed;938	char *string;939	bool is_new;940	int offset;941	u8 size;942	int err;943 944	err = check_numeric_sensor_wobj(wobj, &size, &is_new);945	if (err)946		return;947 948	elements = wobj->package.elements;949 950	element = &elements[HP_WMI_PROPERTY_OPERATIONAL_STATUS];951	nsensor->operational_status = element->integer.value;952 953	/*954	 * In general, an index offset is needed after PossibleStates[0].955	 * On a new variant, CurrentState is after PossibleStates[]. This is956	 * not the case on an old variant, but we still need to offset the957	 * read because CurrentState is where Size would be on a new variant.958	 */959	offset = is_new ? size - 1 : -2;960 961	element = &elements[HP_WMI_PROPERTY_CURRENT_STATE + offset];962	string = element->type == ACPI_TYPE_BUFFER ?963		convert_raw_wmi_string(element->buffer.pointer) :964		element->string.pointer;965 966	if (string) {967		trimmed = strim(string);968		if (strcmp(trimmed, nsensor->current_state)) {969			new_string = hp_wmi_strdup(dev, trimmed);970			if (new_string) {971				devm_kfree(dev, nsensor->current_state);972				nsensor->current_state = new_string;973			}974		}975		if (element->type == ACPI_TYPE_BUFFER)976			kfree(string);977	}978 979	/* Old variant: -2 (not -1) because it lacks the Size property. */980	if (!is_new)981		offset = (int)size - 2;	/* size is > 0, i.e. may be 1. */982 983	element = &elements[HP_WMI_PROPERTY_UNIT_MODIFIER + offset];984	nsensor->unit_modifier = (s32)element->integer.value;985 986	element = &elements[HP_WMI_PROPERTY_CURRENT_READING + offset];987	nsensor->current_reading = element->integer.value;988}989 990/*991 * check_platform_events_wobj - validate a HPBIOS_PlatformEvents instance992 * @wobj: pointer to WMI object instance to check993 *994 * Returns 0 on success, or a negative error code on error.995 */996static int check_platform_events_wobj(const union acpi_object *wobj)997{998	return check_wobj(wobj, hp_wmi_platform_events_property_map,999			  HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS);1000}1001 1002static int1003populate_platform_events_from_wobj(struct device *dev,1004				   struct hp_wmi_platform_events *pevents,1005				   union acpi_object *wobj)1006{1007	int last_prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS;1008	int prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME;1009	union acpi_object *element;1010	acpi_object_type type;1011	char *string;1012	u32 value;1013	int err;1014 1015	err = check_platform_events_wobj(wobj);1016	if (err)1017		return err;1018 1019	element = wobj->package.elements;1020 1021	for (; prop <= last_prop; prop++, element++) {1022		type = hp_wmi_platform_events_property_map[prop];1023 1024		err = extract_acpi_value(dev, element, type, &value, &string);1025		if (err)1026			return err;1027 1028		switch (prop) {1029		case HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME:1030			pevents->name = string;1031			break;1032 1033		case HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION:1034			pevents->description = string;1035			break;1036 1037		case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE:1038			if (strcasecmp(HP_WMI_EVENT_NAMESPACE, string))1039				return -EINVAL;1040 1041			pevents->source_namespace = string;1042			break;1043 1044		case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS:1045			if (strcasecmp(HP_WMI_EVENT_CLASS, string))1046				return -EINVAL;1047 1048			pevents->source_class = string;1049			break;1050 1051		case HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY:1052			pevents->category = value;1053			break;1054 1055		case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY:1056			pevents->possible_severity = value;1057			break;1058 1059		case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS:1060			pevents->possible_status = value;1061			break;1062 1063		default:1064			return -EINVAL;1065		}1066	}1067 1068	return 0;1069}1070 1071/*1072 * check_event_wobj - validate a HPBIOS_BIOSEvent instance1073 * @wobj: pointer to WMI object instance to check1074 *1075 * Returns 0 on success, or a negative error code on error.1076 */1077static int check_event_wobj(const union acpi_object *wobj)1078{1079	return check_wobj(wobj, hp_wmi_event_property_map,1080			  HP_WMI_EVENT_PROPERTY_STATUS);1081}1082 1083static int populate_event_from_wobj(struct device *dev,1084				    struct hp_wmi_event *event,1085				    union acpi_object *wobj)1086{1087	int prop = HP_WMI_EVENT_PROPERTY_NAME;1088	union acpi_object *element;1089	acpi_object_type type;1090	char *string;1091	u32 value;1092	int err;1093 1094	err = check_event_wobj(wobj);1095	if (err)1096		return err;1097 1098	element = wobj->package.elements;1099 1100	for (; prop <= HP_WMI_EVENT_PROPERTY_CATEGORY; prop++, element++) {1101		type = hp_wmi_event_property_map[prop];1102 1103		err = extract_acpi_value(dev, element, type, &value, &string);1104		if (err)1105			return err;1106 1107		switch (prop) {1108		case HP_WMI_EVENT_PROPERTY_NAME:1109			event->name = string;1110			break;1111 1112		case HP_WMI_EVENT_PROPERTY_DESCRIPTION:1113			event->description = string;1114			break;1115 1116		case HP_WMI_EVENT_PROPERTY_CATEGORY:1117			event->category = value;1118			break;1119 1120		default:1121			return -EINVAL;1122		}1123	}1124 1125	return 0;1126}1127 1128/*1129 * classify_event - classify an event1130 * @name: event name1131 * @category: event category1132 *1133 * Classify instances of both HPBIOS_PlatformEvents and HPBIOS_BIOSEvent from1134 * property values. Recognition criteria are based on multiple ACPI dumps [3].1135 *1136 * Returns an enum hp_wmi_type value on success,1137 * or a negative value if the event type is unsupported.1138 */1139static int classify_event(const char *event_name, u32 category)1140{1141	if (category != HP_WMI_CATEGORY_SENSOR)1142		return -EINVAL;1143 1144	/* Fan events have Name "X Stall". */1145	if (strstr(event_name, HP_WMI_PATTERN_FAN_ALARM))1146		return HP_WMI_TYPE_AIR_FLOW;1147 1148	/* Intrusion events have Name "Hood Intrusion". */1149	if (!strcmp(event_name, HP_WMI_PATTERN_INTRUSION_ALARM))1150		return HP_WMI_TYPE_INTRUSION;1151 1152	/*1153	 * Temperature events have Name either "Thermal Caution" or1154	 * "Thermal Critical". Deal only with "Thermal Critical" events.1155	 *1156	 * "Thermal Caution" events have Status "Stressed", informing us that1157	 * the OperationalStatus of the related sensor has become "Stressed".1158	 * However, this is already a fault condition that will clear itself1159	 * when the sensor recovers, so we have no further interest in them.1160	 */1161	if (!strcmp(event_name, HP_WMI_PATTERN_TEMP_ALARM))1162		return HP_WMI_TYPE_TEMPERATURE;1163 1164	return -EINVAL;1165}1166 1167/*1168 * interpret_info - interpret sensor for hwmon1169 * @info: pointer to sensor info struct1170 *1171 * Should be called after the numeric sensor member has been updated.1172 */1173static void interpret_info(struct hp_wmi_info *info)1174{1175	const struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;1176 1177	info->cached_val = scale_numeric_sensor(nsensor);1178	info->last_updated = jiffies;1179}1180 1181/*1182 * hp_wmi_update_info - poll WMI to update sensor info1183 * @state: pointer to driver state1184 * @info: pointer to sensor info struct1185 *1186 * Returns 0 on success, or a negative error code on error.1187 */1188static int hp_wmi_update_info(struct hp_wmi_sensors *state,1189			      struct hp_wmi_info *info)1190{1191	struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;1192	struct device *dev = &state->wdev->dev;1193	const union acpi_object *wobj;1194	u8 instance = info->instance;1195	int ret = 0;1196 1197	if (time_after(jiffies, info->last_updated + HZ)) {1198		mutex_lock(&state->lock);1199 1200		wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, instance);1201		if (!wobj) {1202			ret = -EIO;1203			goto out_unlock;1204		}1205 1206		update_numeric_sensor_from_wobj(dev, nsensor, wobj);1207 1208		interpret_info(info);1209 1210		kfree(wobj);1211 1212out_unlock:1213		mutex_unlock(&state->lock);1214	}1215 1216	return ret;1217}1218 1219static int basic_string_show(struct seq_file *seqf, void *ignored)1220{1221	const char *str = seqf->private;1222 1223	seq_printf(seqf, "%s\n", str);1224 1225	return 0;1226}1227DEFINE_SHOW_ATTRIBUTE(basic_string);1228 1229static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop)1230{1231	struct hp_wmi_numeric_sensor *nsensor;1232	struct hp_wmi_sensors *state;1233	struct hp_wmi_info *info;1234	int err;1235 1236	info = seqf->private;1237	state = info->state;1238	nsensor = &info->nsensor;1239 1240	err = hp_wmi_update_info(state, info);1241	if (err)1242		return err;1243 1244	switch (prop) {1245	case HP_WMI_PROPERTY_OPERATIONAL_STATUS:1246		seq_printf(seqf, "%u\n", nsensor->operational_status);1247		break;1248 1249	case HP_WMI_PROPERTY_CURRENT_STATE:1250		seq_printf(seqf, "%s\n", nsensor->current_state);1251		break;1252 1253	case HP_WMI_PROPERTY_UNIT_MODIFIER:1254		seq_printf(seqf, "%d\n", nsensor->unit_modifier);1255		break;1256 1257	case HP_WMI_PROPERTY_CURRENT_READING:1258		seq_printf(seqf, "%u\n", nsensor->current_reading);1259		break;1260 1261	default:1262		return -EOPNOTSUPP;1263	}1264 1265	return 0;1266}1267 1268static int operational_status_show(struct seq_file *seqf, void *ignored)1269{1270	return fungible_show(seqf, HP_WMI_PROPERTY_OPERATIONAL_STATUS);1271}1272DEFINE_SHOW_ATTRIBUTE(operational_status);1273 1274static int current_state_show(struct seq_file *seqf, void *ignored)1275{1276	return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_STATE);1277}1278DEFINE_SHOW_ATTRIBUTE(current_state);1279 1280static int possible_states_show(struct seq_file *seqf, void *ignored)1281{1282	struct hp_wmi_numeric_sensor *nsensor = seqf->private;1283	u8 i;1284 1285	for (i = 0; i < nsensor->size; i++)1286		seq_printf(seqf, "%s%s", i ? "," : "",1287			   nsensor->possible_states[i]);1288 1289	seq_puts(seqf, "\n");1290 1291	return 0;1292}1293DEFINE_SHOW_ATTRIBUTE(possible_states);1294 1295static int unit_modifier_show(struct seq_file *seqf, void *ignored)1296{1297	return fungible_show(seqf, HP_WMI_PROPERTY_UNIT_MODIFIER);1298}1299DEFINE_SHOW_ATTRIBUTE(unit_modifier);1300 1301static int current_reading_show(struct seq_file *seqf, void *ignored)1302{1303	return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_READING);1304}1305DEFINE_SHOW_ATTRIBUTE(current_reading);1306 1307/* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */1308static void hp_wmi_devm_debugfs_remove(void *res)1309{1310	debugfs_remove_recursive(res);1311}1312 1313/* hp_wmi_debugfs_init - create and populate debugfs directory tree */1314static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info,1315				struct hp_wmi_platform_events *pevents,1316				u8 icount, u8 pcount, bool is_new)1317{1318	struct hp_wmi_numeric_sensor *nsensor;1319	char buf[HP_WMI_MAX_STR_SIZE];1320	struct dentry *debugfs;1321	struct dentry *entries;1322	struct dentry *dir;1323	int err;1324	u8 i;1325 1326	/* dev_name() gives a not-very-friendly GUID for WMI devices. */1327	scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id);1328 1329	debugfs = debugfs_create_dir(buf, NULL);1330	if (IS_ERR(debugfs))1331		return;1332 1333	err = devm_add_action_or_reset(dev, hp_wmi_devm_debugfs_remove,1334				       debugfs);1335	if (err)1336		return;1337 1338	entries = debugfs_create_dir("sensor", debugfs);1339 1340	for (i = 0; i < icount; i++, info++) {1341		nsensor = &info->nsensor;1342 1343		scnprintf(buf, sizeof(buf), "%u", i);1344		dir = debugfs_create_dir(buf, entries);1345 1346		debugfs_create_file("name", 0444, dir,1347				    (void *)nsensor->name,1348				    &basic_string_fops);1349 1350		debugfs_create_file("description", 0444, dir,1351				    (void *)nsensor->description,1352				    &basic_string_fops);1353 1354		debugfs_create_u32("sensor_type", 0444, dir,1355				   &nsensor->sensor_type);1356 1357		debugfs_create_file("other_sensor_type", 0444, dir,1358				    (void *)nsensor->other_sensor_type,1359				    &basic_string_fops);1360 1361		debugfs_create_file("operational_status", 0444, dir,1362				    info, &operational_status_fops);1363 1364		debugfs_create_file("possible_states", 0444, dir,1365				    nsensor, &possible_states_fops);1366 1367		debugfs_create_file("current_state", 0444, dir,1368				    info, &current_state_fops);1369 1370		debugfs_create_u32("base_units", 0444, dir,1371				   &nsensor->base_units);1372 1373		debugfs_create_file("unit_modifier", 0444, dir,1374				    info, &unit_modifier_fops);1375 1376		debugfs_create_file("current_reading", 0444, dir,1377				    info, &current_reading_fops);1378 1379		if (is_new)1380			debugfs_create_u32("rate_units", 0444, dir,1381					   &nsensor->rate_units);1382	}1383 1384	if (!pcount)1385		return;1386 1387	entries = debugfs_create_dir("platform_events", debugfs);1388 1389	for (i = 0; i < pcount; i++, pevents++) {1390		scnprintf(buf, sizeof(buf), "%u", i);1391		dir = debugfs_create_dir(buf, entries);1392 1393		debugfs_create_file("name", 0444, dir,1394				    (void *)pevents->name,1395				    &basic_string_fops);1396 1397		debugfs_create_file("description", 0444, dir,1398				    (void *)pevents->description,1399				    &basic_string_fops);1400 1401		debugfs_create_file("source_namespace", 0444, dir,1402				    (void *)pevents->source_namespace,1403				    &basic_string_fops);1404 1405		debugfs_create_file("source_class", 0444, dir,1406				    (void *)pevents->source_class,1407				    &basic_string_fops);1408 1409		debugfs_create_u32("category", 0444, dir,1410				   &pevents->category);1411 1412		debugfs_create_u32("possible_severity", 0444, dir,1413				   &pevents->possible_severity);1414 1415		debugfs_create_u32("possible_status", 0444, dir,1416				   &pevents->possible_status);1417	}1418}1419 1420static umode_t hp_wmi_hwmon_is_visible(const void *drvdata,1421				       enum hwmon_sensor_types type,1422				       u32 attr, int channel)1423{1424	const struct hp_wmi_sensors *state = drvdata;1425	const struct hp_wmi_info *info;1426 1427	if (type == hwmon_intrusion)1428		return state->has_intrusion ? 0644 : 0;1429 1430	if (!state->info_map[type] || !state->info_map[type][channel])1431		return 0;1432 1433	info = state->info_map[type][channel];1434 1435	if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||1436	    (type == hwmon_fan  && attr == hwmon_fan_alarm))1437		return info->has_alarm ? 0444 : 0;1438 1439	return 0444;1440}1441 1442static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,1443			     u32 attr, int channel, long *out_val)1444{1445	struct hp_wmi_sensors *state = dev_get_drvdata(dev);1446	const struct hp_wmi_numeric_sensor *nsensor;1447	struct hp_wmi_info *info;1448	int err;1449 1450	if (type == hwmon_intrusion) {1451		*out_val = state->intrusion ? 1 : 0;1452 1453		return 0;1454	}1455 1456	info = state->info_map[type][channel];1457 1458	if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||1459	    (type == hwmon_fan  && attr == hwmon_fan_alarm)) {1460		*out_val = info->alarm ? 1 : 0;1461		info->alarm = false;1462 1463		return 0;1464	}1465 1466	nsensor = &info->nsensor;1467 1468	err = hp_wmi_update_info(state, info);1469	if (err)1470		return err;1471 1472	if ((type == hwmon_temp && attr == hwmon_temp_fault) ||1473	    (type == hwmon_fan  && attr == hwmon_fan_fault))1474		*out_val = numeric_sensor_has_fault(nsensor);1475	else1476		*out_val = info->cached_val;1477 1478	return 0;1479}1480 1481static int hp_wmi_hwmon_read_string(struct device *dev,1482				    enum hwmon_sensor_types type, u32 attr,1483				    int channel, const char **out_str)1484{1485	const struct hp_wmi_sensors *state = dev_get_drvdata(dev);1486	const struct hp_wmi_info *info;1487 1488	info = state->info_map[type][channel];1489	*out_str = info->nsensor.name;1490 1491	return 0;1492}1493 1494static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,1495			      u32 attr, int channel, long val)1496{1497	struct hp_wmi_sensors *state = dev_get_drvdata(dev);1498 1499	if (val)1500		return -EINVAL;1501 1502	mutex_lock(&state->lock);1503 1504	state->intrusion = false;1505 1506	mutex_unlock(&state->lock);1507 1508	return 0;1509}1510 1511static const struct hwmon_ops hp_wmi_hwmon_ops = {1512	.is_visible  = hp_wmi_hwmon_is_visible,1513	.read	     = hp_wmi_hwmon_read,1514	.read_string = hp_wmi_hwmon_read_string,1515	.write	     = hp_wmi_hwmon_write,1516};1517 1518static struct hwmon_chip_info hp_wmi_chip_info = {1519	.ops         = &hp_wmi_hwmon_ops,1520	.info        = NULL,1521};1522 1523static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,1524					   const char *event_description)1525{1526	struct hp_wmi_info **ptr_info = state->info_map[hwmon_fan];1527	u8 fan_count = state->channel_count[hwmon_fan];1528	struct hp_wmi_info *info;1529	const char *name;1530	u8 i;1531 1532	/* Fan event has Description "X Speed". Sensor has Name "X[ Speed]". */1533 1534	for (i = 0; i < fan_count; i++, ptr_info++) {1535		info = *ptr_info;1536		name = info->nsensor.name;1537 1538		if (strstr(event_description, name))1539			return info;1540	}1541 1542	return NULL;1543}1544 1545static u8 match_temp_events(struct hp_wmi_sensors *state,1546			    const char *event_description,1547			    struct hp_wmi_info *temp_info[])1548{1549	struct hp_wmi_info **ptr_info = state->info_map[hwmon_temp];1550	u8 temp_count = state->channel_count[hwmon_temp];1551	struct hp_wmi_info *info;1552	const char *name;1553	u8 count = 0;1554	bool is_cpu;1555	bool is_sys;1556	u8 i;1557 1558	/* Description is either "CPU Thermal Index" or "Chassis Thermal Index". */1559 1560	is_cpu = !strcmp(event_description, HP_WMI_PATTERN_CPU_TEMP);1561	is_sys = !strcmp(event_description, HP_WMI_PATTERN_SYS_TEMP);1562	if (!is_cpu && !is_sys)1563		return 0;1564 1565	/*1566	 * CPU event: Match one sensor with Name either "CPU Thermal Index" or1567	 * "CPU Temperature", or multiple with Name(s) "CPU[#] Temperature".1568	 *1569	 * Chassis event: Match one sensor with Name either1570	 * "Chassis Thermal Index" or "System Ambient Temperature".1571	 */1572 1573	for (i = 0; i < temp_count; i++, ptr_info++) {1574		info = *ptr_info;1575		name = info->nsensor.name;1576 1577		if ((is_cpu && (!strcmp(name, HP_WMI_PATTERN_CPU_TEMP) ||1578				!strcmp(name, HP_WMI_PATTERN_CPU_TEMP2))) ||1579		    (is_sys && (!strcmp(name, HP_WMI_PATTERN_SYS_TEMP) ||1580				!strcmp(name, HP_WMI_PATTERN_SYS_TEMP2)))) {1581			temp_info[0] = info;1582			return 1;1583		}1584 1585		if (is_cpu && (strstr(name, HP_WMI_PATTERN_CPU) &&1586			       strstr(name, HP_WMI_PATTERN_TEMP)))1587			temp_info[count++] = info;1588	}1589 1590	return count;1591}1592 1593/* hp_wmi_devm_debugfs_remove - devm callback for WMI event handler removal */1594static void hp_wmi_devm_notify_remove(void *ignored)1595{1596	wmi_remove_notify_handler(HP_WMI_EVENT_GUID);1597}1598 1599/* hp_wmi_notify - WMI event notification handler */1600static void hp_wmi_notify(union acpi_object *wobj, void *context)1601{1602	struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};1603	struct hp_wmi_sensors *state = context;1604	struct device *dev = &state->wdev->dev;1605	struct hp_wmi_event event = {};1606	struct hp_wmi_info *fan_info;1607	acpi_status err;1608	int event_type;1609	u8 count;1610 1611	/*1612	 * The following warning may occur in the kernel log:1613	 *1614	 *   ACPI Warning: \_SB.WMID._WED: Return type mismatch -1615	 *     found Package, expected Integer/String/Buffer1616	 *1617	 * After using [4] to decode BMOF blobs found in [3], careless copying1618	 * of BIOS code seems the most likely explanation for this warning.1619	 * HP_WMI_EVENT_GUID refers to \\.\root\WMI\HPBIOS_BIOSEvent on1620	 * business-class systems, but it refers to \\.\root\WMI\hpqBEvnt on1621	 * non-business-class systems. Per the existing hp-wmi driver, it1622	 * looks like an instance of hpqBEvnt delivered as event data may1623	 * indeed take the form of a raw ACPI_BUFFER on non-business-class1624	 * systems ("may" because ASL shows some BIOSes do strange things).1625	 *1626	 * In any case, we can ignore this warning, because we always validate1627	 * the event data to ensure it is an ACPI_PACKAGE containing a1628	 * HPBIOS_BIOSEvent instance.1629	 */1630 1631	if (!wobj)1632		return;1633 1634	mutex_lock(&state->lock);1635 1636	err = populate_event_from_wobj(dev, &event, wobj);1637	if (err) {1638		dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type);1639		goto out_free;1640	}1641 1642	event_type = classify_event(event.name, event.category);1643	switch (event_type) {1644	case HP_WMI_TYPE_AIR_FLOW:1645		fan_info = match_fan_event(state, event.description);1646		if (fan_info)1647			fan_info->alarm = true;1648		break;1649 1650	case HP_WMI_TYPE_INTRUSION:1651		state->intrusion = true;1652		break;1653 1654	case HP_WMI_TYPE_TEMPERATURE:1655		count = match_temp_events(state, event.description, temp_info);1656		while (count)1657			temp_info[--count]->alarm = true;1658		break;1659 1660	default:1661		break;1662	}1663 1664out_free:1665	devm_kfree(dev, event.name);1666	devm_kfree(dev, event.description);1667 1668	mutex_unlock(&state->lock);1669}1670 1671static int init_platform_events(struct device *dev,1672				struct hp_wmi_platform_events **out_pevents,1673				u8 *out_pcount)1674{1675	struct hp_wmi_platform_events *pevents_arr;1676	struct hp_wmi_platform_events *pevents;1677	union acpi_object *wobj;1678	u8 count;1679	int err;1680	u8 i;1681 1682	count = hp_wmi_wobj_instance_count(HP_WMI_PLATFORM_EVENTS_GUID);1683	if (!count) {1684		*out_pcount = 0;1685 1686		dev_dbg(dev, "No platform events\n");1687 1688		return 0;1689	}1690 1691	pevents_arr = devm_kcalloc(dev, count, sizeof(*pevents), GFP_KERNEL);1692	if (!pevents_arr)1693		return -ENOMEM;1694 1695	for (i = 0, pevents = pevents_arr; i < count; i++, pevents++) {1696		wobj = hp_wmi_get_wobj(HP_WMI_PLATFORM_EVENTS_GUID, i);1697		if (!wobj)1698			return -EIO;1699 1700		err = populate_platform_events_from_wobj(dev, pevents, wobj);1701 1702		kfree(wobj);1703 1704		if (err)1705			return err;1706	}1707 1708	*out_pevents = pevents_arr;1709	*out_pcount = count;1710 1711	dev_dbg(dev, "Found %u platform events\n", count);1712 1713	return 0;1714}1715 1716static int init_numeric_sensors(struct hp_wmi_sensors *state,1717				struct hp_wmi_info *connected[],1718				struct hp_wmi_info **out_info,1719				u8 *out_icount, u8 *out_count,1720				bool *out_is_new)1721{1722	struct hp_wmi_info ***info_map = state->info_map;1723	u8 *channel_count = state->channel_count;1724	struct device *dev = &state->wdev->dev;1725	struct hp_wmi_numeric_sensor *nsensor;1726	u8 channel_index[hwmon_max] = {};1727	enum hwmon_sensor_types type;1728	struct hp_wmi_info *info_arr;1729	struct hp_wmi_info *info;1730	union acpi_object *wobj;1731	u8 count = 0;1732	bool is_new;1733	u8 icount;1734	int wtype;1735	int err;1736	u8 c;1737	u8 i;1738 1739	icount = hp_wmi_wobj_instance_count(HP_WMI_NUMERIC_SENSOR_GUID);1740	if (!icount)1741		return -ENODATA;1742 1743	info_arr = devm_kcalloc(dev, icount, sizeof(*info), GFP_KERNEL);1744	if (!info_arr)1745		return -ENOMEM;1746 1747	for (i = 0, info = info_arr; i < icount; i++, info++) {1748		wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, i);1749		if (!wobj)1750			return -EIO;1751 1752		info->instance = i;1753		info->state = state;1754		nsensor = &info->nsensor;1755 1756		err = populate_numeric_sensor_from_wobj(dev, nsensor, wobj,1757							&is_new);1758 1759		kfree(wobj);1760 1761		if (err)1762			return err;1763 1764		if (!numeric_sensor_is_connected(nsensor))1765			continue;1766 1767		wtype = classify_numeric_sensor(nsensor);1768		if (wtype < 0)1769			continue;1770 1771		type = hp_wmi_hwmon_type_map[wtype];1772 1773		channel_count[type]++;1774 1775		info->type = type;1776 1777		interpret_info(info);1778 1779		connected[count++] = info;1780	}1781 1782	dev_dbg(dev, "Found %u sensors (%u connected)\n", i, count);1783 1784	for (i = 0; i < count; i++) {1785		info = connected[i];1786		type = info->type;1787		c = channel_index[type]++;1788 1789		if (!info_map[type]) {1790			info_map[type] = devm_kcalloc(dev, channel_count[type],1791						      sizeof(*info_map),1792						      GFP_KERNEL);1793			if (!info_map[type])1794				return -ENOMEM;1795		}1796 1797		info_map[type][c] = info;1798	}1799 1800	*out_info = info_arr;1801	*out_icount = icount;1802	*out_count = count;1803	*out_is_new = is_new;1804 1805	return 0;1806}1807 1808static bool find_event_attributes(struct hp_wmi_sensors *state,1809				  struct hp_wmi_platform_events *pevents,1810				  u8 pevents_count)1811{1812	/*1813	 * The existence of this HPBIOS_PlatformEvents instance:1814	 *1815	 *   {1816	 *     Name = "Rear Chassis Fan0 Stall";1817	 *     Description = "Rear Chassis Fan0 Speed";1818	 *     Category = 3;           // "Sensor"1819	 *     PossibleSeverity = 25;  // "Critical Failure"1820	 *     PossibleStatus = 5;     // "Predictive Failure"1821	 *     [...]1822	 *   }1823	 *1824	 * means that this HPBIOS_BIOSEvent instance may occur:1825	 *1826	 *   {1827	 *     Name = "Rear Chassis Fan0 Stall";1828	 *     Description = "Rear Chassis Fan0 Speed";1829	 *     Category = 3;           // "Sensor"1830	 *     Severity = 25;          // "Critical Failure"1831	 *     Status = 5;             // "Predictive Failure"1832	 *   }1833	 *1834	 * After the event occurs (e.g. because the fan was unplugged),1835	 * polling the related HPBIOS_BIOSNumericSensor instance gives:1836	 *1837	 *   {1838	 *      Name = "Rear Chassis Fan0";1839	 *      Description = "Reports rear chassis fan0 speed";1840	 *      OperationalStatus = 5; // "Predictive Failure", was 3 ("OK")1841	 *      CurrentReading = 0;1842	 *      [...]1843	 *   }1844	 *1845	 * In this example, the hwmon fan channel for "Rear Chassis Fan0"1846	 * should support the alarm flag and have it be set if the related1847	 * HPBIOS_BIOSEvent instance occurs.1848	 *1849	 * In addition to fan events, temperature (CPU/chassis) and intrusion1850	 * events are relevant to hwmon [2]. Note that much information in [2]1851	 * is unreliable; it is referenced in addition to ACPI dumps [3] merely1852	 * to support the conclusion that sensor and event names/descriptions1853	 * are systematic enough to allow this driver to match them.1854	 *1855	 * Complications and limitations:1856	 *1857	 * - Strings are freeform and may vary, cf. sensor Name "CPU0 Fan"1858	 *   on a Z420 vs. "CPU Fan Speed" on an EliteOne 800 G1.1859	 * - Leading/trailing whitespace is a rare but real possibility [3].1860	 * - The HPBIOS_PlatformEvents object may not exist or its instances1861	 *   may show that the system only has e.g. BIOS setting-related1862	 *   events (cf. the ProBook 4540s and ProBook 470 G0 [3]).1863	 */1864 1865	struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};1866	const char *event_description;1867	struct hp_wmi_info *fan_info;1868	bool has_events = false;1869	const char *event_name;1870	u32 event_category;1871	int event_type;1872	u8 count;1873	u8 i;1874 1875	for (i = 0; i < pevents_count; i++, pevents++) {1876		event_name = pevents->name;1877		event_description = pevents->description;1878		event_category = pevents->category;1879 1880		event_type = classify_event(event_name, event_category);1881		switch (event_type) {1882		case HP_WMI_TYPE_AIR_FLOW:1883			fan_info = match_fan_event(state, event_description);1884			if (!fan_info)1885				break;1886 1887			fan_info->has_alarm = true;1888			has_events = true;1889			break;1890 1891		case HP_WMI_TYPE_INTRUSION:1892			state->has_intrusion = true;1893			has_events = true;1894			break;1895 1896		case HP_WMI_TYPE_TEMPERATURE:1897			count = match_temp_events(state, event_description,1898						  temp_info);1899			if (!count)1900				break;1901 1902			while (count)1903				temp_info[--count]->has_alarm = true;1904			has_events = true;1905			break;1906 1907		default:1908			break;1909		}1910	}1911 1912	return has_events;1913}1914 1915static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)1916{1917	const struct hwmon_channel_info **ptr_channel_info;1918	struct hp_wmi_info ***info_map = state->info_map;1919	u8 *channel_count = state->channel_count;1920	struct hwmon_channel_info *channel_info;1921	struct device *dev = &state->wdev->dev;1922	enum hwmon_sensor_types type;1923	u8 type_count = 0;1924	u32 *config;1925	u32 attr;1926	u8 count;1927	u8 i;1928 1929	if (channel_count[hwmon_temp])1930		channel_count[hwmon_chip] = 1;1931 1932	if (has_events && state->has_intrusion)1933		channel_count[hwmon_intrusion] = 1;1934 1935	for (type = hwmon_chip; type < hwmon_max; type++)1936		if (channel_count[type])1937			type_count++;1938 1939	channel_info = devm_kcalloc(dev, type_count,1940				    sizeof(*channel_info), GFP_KERNEL);1941	if (!channel_info)1942		return -ENOMEM;1943 1944	ptr_channel_info = devm_kcalloc(dev, type_count + 1,1945					sizeof(*ptr_channel_info), GFP_KERNEL);1946	if (!ptr_channel_info)1947		return -ENOMEM;1948 1949	hp_wmi_chip_info.info = ptr_channel_info;1950 1951	for (type = hwmon_chip; type < hwmon_max; type++) {1952		count = channel_count[type];1953		if (!count)1954			continue;1955 1956		config = devm_kcalloc(dev, count + 1,1957				      sizeof(*config), GFP_KERNEL);1958		if (!config)1959			return -ENOMEM;1960 1961		attr = hp_wmi_hwmon_attributes[type];1962		channel_info->type = type;1963		channel_info->config = config;1964		memset32(config, attr, count);1965 1966		*ptr_channel_info++ = channel_info++;1967 1968		if (!has_events || (type != hwmon_temp && type != hwmon_fan))1969			continue;1970 1971		attr = type == hwmon_temp ? HWMON_T_ALARM : HWMON_F_ALARM;1972 1973		for (i = 0; i < count; i++)1974			if (info_map[type][i]->has_alarm)1975				config[i] |= attr;1976	}1977 1978	return 0;1979}1980 1981static bool add_event_handler(struct hp_wmi_sensors *state)1982{1983	struct device *dev = &state->wdev->dev;1984	int err;1985 1986	err = wmi_install_notify_handler(HP_WMI_EVENT_GUID,1987					 hp_wmi_notify, state);1988	if (err) {1989		dev_info(dev, "Failed to subscribe to WMI event\n");1990		return false;1991	}1992 1993	err = devm_add_action_or_reset(dev, hp_wmi_devm_notify_remove, NULL);1994	if (err)1995		return false;1996 1997	return true;1998}1999 2000static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)2001{2002	struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES];2003	struct hp_wmi_platform_events *pevents = NULL;2004	struct device *dev = &state->wdev->dev;2005	struct hp_wmi_info *info;2006	struct device *hwdev;2007	bool has_events;2008	bool is_new;2009	u8 icount;2010	u8 pcount;2011	u8 count;2012	int err;2013 2014	err = init_platform_events(dev, &pevents, &pcount);2015	if (err)2016		return err;2017 2018	err = init_numeric_sensors(state, connected, &info,2019				   &icount, &count, &is_new);2020	if (err)2021		return err;2022 2023	if (IS_ENABLED(CONFIG_DEBUG_FS))2024		hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new);2025 2026	if (!count)2027		return 0;	/* No connected sensors; debugfs only. */2028 2029	has_events = find_event_attributes(state, pevents, pcount);2030 2031	/* Survive failure to install WMI event handler. */2032	if (has_events && !add_event_handler(state))2033		has_events = false;2034 2035	err = make_chip_info(state, has_events);2036	if (err)2037		return err;2038 2039	hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",2040						     state, &hp_wmi_chip_info,2041						     NULL);2042	return PTR_ERR_OR_ZERO(hwdev);2043}2044 2045static int hp_wmi_sensors_probe(struct wmi_device *wdev, const void *context)2046{2047	struct device *dev = &wdev->dev;2048	struct hp_wmi_sensors *state;2049 2050	state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);2051	if (!state)2052		return -ENOMEM;2053 2054	state->wdev = wdev;2055 2056	mutex_init(&state->lock);2057 2058	dev_set_drvdata(dev, state);2059 2060	return hp_wmi_sensors_init(state);2061}2062 2063static const struct wmi_device_id hp_wmi_sensors_id_table[] = {2064	{ HP_WMI_NUMERIC_SENSOR_GUID, NULL },2065	{},2066};2067 2068static struct wmi_driver hp_wmi_sensors_driver = {2069	.driver   = { .name = "hp-wmi-sensors" },2070	.id_table = hp_wmi_sensors_id_table,2071	.probe    = hp_wmi_sensors_probe,2072};2073module_wmi_driver(hp_wmi_sensors_driver);2074 2075MODULE_AUTHOR("James Seo <james@equiv.tech>");2076MODULE_DESCRIPTION("HP WMI Sensors driver");2077MODULE_LICENSE("GPL");2078