Lines Matching +full:milli +full:- +full:ohms
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * hwmon driver for HP (and some HP Compaq) business-class computers that
9 * [1] Hewlett-Packard Development Company, L.P.,
12 * [2] Hewlett-Packard Development Company, L.P.,
16 * "linuxhw/ACPI - Collect ACPI table dumps", 2018. [Online].
18 * [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer",
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-w…
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"
190 * struct hp_wmi_numeric_sensor - a HPBIOS_BIOSNumericSensor instance
217 * "Non-Recoverable Error","Starting","Stopping","Stopped",
239 * "Pounds","Foot-Pounds","Ounce-Inches","Gauss","Gilberts",
240 * "Henries","Farads","Ohms","Siemens","Moles","Becquerels",
281 * struct hp_wmi_platform_events - a HPBIOS_PlatformEvents instance
300 * "Major Failure","Critical Failure","Non-recoverable Error",
307 * "Non-Recoverable Error","Starting","Stopping","Stopped",
325 * struct hp_wmi_event - a HPBIOS_BIOSEvent instance
340 * "Non-recoverable Error"}]
346 * "Non-Recoverable Error","Starting","Stopping","Stopped",
360 * struct hp_wmi_info - sensor info
383 * struct hp_wmi_sensors - driver state
406 /* WMI strings are length-prefixed UTF-16 [5]. */ in is_raw_wmi_string()
410 length -= sizeof(*ptr); in is_raw_wmi_string()
427 /* Count UTF-16 code points. Exclude trailing null padding. */ in convert_raw_wmi_string()
430 cps--; in convert_raw_wmi_string()
432 /* Each code point becomes up to 3 UTF-8 characters. */ in convert_raw_wmi_string()
433 len = min(cps * 3, HP_WMI_MAX_STR_SIZE - 1); in convert_raw_wmi_string()
445 /* hp_wmi_strdup - devm_kstrdup, but length-limited */
451 len = strnlen(src, HP_WMI_MAX_STR_SIZE - 1); in hp_wmi_strdup()
462 /* hp_wmi_wstrdup - hp_wmi_strdup, but for a raw WMI string */
480 * hp_wmi_get_wobj - poll WMI for a WMI object instance
499 /* hp_wmi_wobj_instance_count - find count of WMI object instances */
512 acpi_object_type type = wobj->type; in check_wobj()
519 return -EINVAL; in check_wobj()
521 elem_count = wobj->package.count; in check_wobj()
523 return -EINVAL; in check_wobj()
525 elements = wobj->package.elements; in check_wobj()
535 return -EINVAL; in check_wobj()
549 *out_value = element->integer.value; in extract_acpi_value()
553 *out_string = element->type == ACPI_TYPE_BUFFER ? in extract_acpi_value()
554 hp_wmi_wstrdup(dev, element->buffer.pointer) : in extract_acpi_value()
555 hp_wmi_strdup(dev, strim(element->string.pointer)); in extract_acpi_value()
557 return -ENOMEM; in extract_acpi_value()
561 return -EINVAL; in extract_acpi_value()
568 * check_numeric_sensor_wobj - validate a HPBIOS_BIOSNumericSensor instance
578 acpi_object_type type = wobj->type; in check_numeric_sensor_wobj()
590 return -EINVAL; in check_numeric_sensor_wobj()
593 * elements is a variable-length array of ACPI objects, one for in check_numeric_sensor_wobj()
598 elements = wobj->package.elements; in check_numeric_sensor_wobj()
600 elem_count = wobj->package.count; in check_numeric_sensor_wobj()
603 return -EINVAL; in check_numeric_sensor_wobj()
618 return -EINVAL; in check_numeric_sensor_wobj()
626 if (elem_count < last_prop - !is_new + 1) in check_numeric_sensor_wobj()
627 return -EINVAL; in check_numeric_sensor_wobj()
629 count = elem_count - (last_prop - !is_new); in check_numeric_sensor_wobj()
635 return -EINVAL; in check_numeric_sensor_wobj()
641 prop = HP_WMI_PROPERTY_CURRENT_STATE - 1; in check_numeric_sensor_wobj()
647 return -EINVAL; in check_numeric_sensor_wobj()
651 /* PossibleStates[0] has already been type-checked. */ in check_numeric_sensor_wobj()
655 return -EINVAL; in check_numeric_sensor_wobj()
660 prop = HP_WMI_PROPERTY_BASE_UNITS - 1; in check_numeric_sensor_wobj()
666 prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1; in check_numeric_sensor_wobj()
672 return -EINVAL; in check_numeric_sensor_wobj()
683 u32 operational_status = nsensor->operational_status; in numeric_sensor_is_connected()
690 u32 operational_status = nsensor->operational_status; in numeric_sensor_has_fault()
712 /* scale_numeric_sensor - scale sensor reading for hwmon */
715 u32 current_reading = nsensor->current_reading; in scale_numeric_sensor()
716 s32 unit_modifier = nsensor->unit_modifier; in scale_numeric_sensor()
717 u32 sensor_type = nsensor->sensor_type; in scale_numeric_sensor()
718 u32 base_units = nsensor->base_units; in scale_numeric_sensor()
723 target_modifier = sensor_type == HP_WMI_TYPE_AIR_FLOW ? 0 : -3; in scale_numeric_sensor()
730 for (; unit_modifier > target_modifier; unit_modifier--) { in scale_numeric_sensor()
741 val -= MILLI * 32; in scale_numeric_sensor()
757 * classify_numeric_sensor - classify a numeric sensor
765 u32 sensor_type = nsensor->sensor_type; in classify_numeric_sensor()
766 u32 base_units = nsensor->base_units; in classify_numeric_sensor()
767 const char *name = nsensor->name; in classify_numeric_sensor()
775 * reliably -6°C vs. coretemp on a HP Compaq Elite 8300, and in classify_numeric_sensor()
808 return -EINVAL; in classify_numeric_sensor()
834 return -ENOMEM; in populate_numeric_sensor_from_wobj()
836 element = wobj->package.elements; in populate_numeric_sensor_from_wobj()
837 nsensor->possible_states = possible_states; in populate_numeric_sensor_from_wobj()
838 nsensor->size = size; in populate_numeric_sensor_from_wobj()
854 nsensor->name = string; in populate_numeric_sensor_from_wobj()
858 nsensor->description = string; in populate_numeric_sensor_from_wobj()
863 return -EINVAL; in populate_numeric_sensor_from_wobj()
865 nsensor->sensor_type = value; in populate_numeric_sensor_from_wobj()
869 nsensor->other_sensor_type = string; in populate_numeric_sensor_from_wobj()
873 nsensor->operational_status = value; in populate_numeric_sensor_from_wobj()
877 prop = HP_WMI_PROPERTY_CURRENT_STATE - 1; in populate_numeric_sensor_from_wobj()
885 if (--size) in populate_numeric_sensor_from_wobj()
886 prop--; in populate_numeric_sensor_from_wobj()
890 prop = HP_WMI_PROPERTY_BASE_UNITS - 1; in populate_numeric_sensor_from_wobj()
894 nsensor->current_state = string; in populate_numeric_sensor_from_wobj()
898 prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1; in populate_numeric_sensor_from_wobj()
902 nsensor->base_units = value; in populate_numeric_sensor_from_wobj()
907 nsensor->unit_modifier = (s32)value; in populate_numeric_sensor_from_wobj()
911 nsensor->current_reading = value; in populate_numeric_sensor_from_wobj()
915 nsensor->rate_units = value; in populate_numeric_sensor_from_wobj()
919 return -EINVAL; in populate_numeric_sensor_from_wobj()
928 /* update_numeric_sensor_from_wobj - update fungible sensor properties */
948 elements = wobj->package.elements; in update_numeric_sensor_from_wobj()
951 nsensor->operational_status = element->integer.value; in update_numeric_sensor_from_wobj()
959 offset = is_new ? size - 1 : -2; in update_numeric_sensor_from_wobj()
962 string = element->type == ACPI_TYPE_BUFFER ? in update_numeric_sensor_from_wobj()
963 convert_raw_wmi_string(element->buffer.pointer) : in update_numeric_sensor_from_wobj()
964 element->string.pointer; in update_numeric_sensor_from_wobj()
968 if (strcmp(trimmed, nsensor->current_state)) { in update_numeric_sensor_from_wobj()
971 devm_kfree(dev, nsensor->current_state); in update_numeric_sensor_from_wobj()
972 nsensor->current_state = new_string; in update_numeric_sensor_from_wobj()
975 if (element->type == ACPI_TYPE_BUFFER) in update_numeric_sensor_from_wobj()
979 /* Old variant: -2 (not -1) because it lacks the Size property. */ in update_numeric_sensor_from_wobj()
981 offset = (int)size - 2; /* size is > 0, i.e. may be 1. */ in update_numeric_sensor_from_wobj()
984 nsensor->unit_modifier = (s32)element->integer.value; in update_numeric_sensor_from_wobj()
987 nsensor->current_reading = element->integer.value; in update_numeric_sensor_from_wobj()
991 * check_platform_events_wobj - validate a HPBIOS_PlatformEvents instance
1019 element = wobj->package.elements; in populate_platform_events_from_wobj()
1030 pevents->name = string; in populate_platform_events_from_wobj()
1034 pevents->description = string; in populate_platform_events_from_wobj()
1039 return -EINVAL; in populate_platform_events_from_wobj()
1041 pevents->source_namespace = string; in populate_platform_events_from_wobj()
1046 return -EINVAL; in populate_platform_events_from_wobj()
1048 pevents->source_class = string; in populate_platform_events_from_wobj()
1052 pevents->category = value; in populate_platform_events_from_wobj()
1056 pevents->possible_severity = value; in populate_platform_events_from_wobj()
1060 pevents->possible_status = value; in populate_platform_events_from_wobj()
1064 return -EINVAL; in populate_platform_events_from_wobj()
1072 * check_event_wobj - validate a HPBIOS_BIOSEvent instance
1098 element = wobj->package.elements; in populate_event_from_wobj()
1109 event->name = string; in populate_event_from_wobj()
1113 event->description = string; in populate_event_from_wobj()
1117 event->category = value; in populate_event_from_wobj()
1121 return -EINVAL; in populate_event_from_wobj()
1129 * classify_event - classify an event
1142 return -EINVAL; in classify_event()
1164 return -EINVAL; in classify_event()
1168 * interpret_info - interpret sensor for hwmon
1175 const struct hp_wmi_numeric_sensor *nsensor = &info->nsensor; in interpret_info()
1177 info->cached_val = scale_numeric_sensor(nsensor); in interpret_info()
1178 info->last_updated = jiffies; in interpret_info()
1182 * hp_wmi_update_info - poll WMI to update sensor info
1191 struct hp_wmi_numeric_sensor *nsensor = &info->nsensor; in hp_wmi_update_info()
1192 struct device *dev = &state->wdev->dev; in hp_wmi_update_info()
1194 u8 instance = info->instance; in hp_wmi_update_info()
1197 if (time_after(jiffies, info->last_updated + HZ)) { in hp_wmi_update_info()
1198 mutex_lock(&state->lock); in hp_wmi_update_info()
1202 ret = -EIO; in hp_wmi_update_info()
1213 mutex_unlock(&state->lock); in hp_wmi_update_info()
1221 const char *str = seqf->private; in basic_string_show()
1236 info = seqf->private; in fungible_show()
1237 state = info->state; in fungible_show()
1238 nsensor = &info->nsensor; in fungible_show()
1246 seq_printf(seqf, "%u\n", nsensor->operational_status); in fungible_show()
1250 seq_printf(seqf, "%s\n", nsensor->current_state); in fungible_show()
1254 seq_printf(seqf, "%d\n", nsensor->unit_modifier); in fungible_show()
1258 seq_printf(seqf, "%u\n", nsensor->current_reading); in fungible_show()
1262 return -EOPNOTSUPP; in fungible_show()
1282 struct hp_wmi_numeric_sensor *nsensor = seqf->private; in possible_states_show()
1285 for (i = 0; i < nsensor->size; i++) in possible_states_show()
1287 nsensor->possible_states[i]); in possible_states_show()
1307 /* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */
1313 /* hp_wmi_debugfs_init - create and populate debugfs directory tree */
1326 /* dev_name() gives a not-very-friendly GUID for WMI devices. */ in hp_wmi_debugfs_init()
1327 scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id); in hp_wmi_debugfs_init()
1341 nsensor = &info->nsensor; in hp_wmi_debugfs_init()
1347 (void *)nsensor->name, in hp_wmi_debugfs_init()
1351 (void *)nsensor->description, in hp_wmi_debugfs_init()
1355 &nsensor->sensor_type); in hp_wmi_debugfs_init()
1358 (void *)nsensor->other_sensor_type, in hp_wmi_debugfs_init()
1371 &nsensor->base_units); in hp_wmi_debugfs_init()
1381 &nsensor->rate_units); in hp_wmi_debugfs_init()
1394 (void *)pevents->name, in hp_wmi_debugfs_init()
1398 (void *)pevents->description, in hp_wmi_debugfs_init()
1402 (void *)pevents->source_namespace, in hp_wmi_debugfs_init()
1406 (void *)pevents->source_class, in hp_wmi_debugfs_init()
1410 &pevents->category); in hp_wmi_debugfs_init()
1413 &pevents->possible_severity); in hp_wmi_debugfs_init()
1416 &pevents->possible_status); in hp_wmi_debugfs_init()
1428 return state->has_intrusion ? 0644 : 0; in hp_wmi_hwmon_is_visible()
1430 if (!state->info_map[type] || !state->info_map[type][channel]) in hp_wmi_hwmon_is_visible()
1433 info = state->info_map[type][channel]; in hp_wmi_hwmon_is_visible()
1437 return info->has_alarm ? 0444 : 0; in hp_wmi_hwmon_is_visible()
1451 *out_val = state->intrusion ? 1 : 0; in hp_wmi_hwmon_read()
1456 info = state->info_map[type][channel]; in hp_wmi_hwmon_read()
1460 *out_val = info->alarm ? 1 : 0; in hp_wmi_hwmon_read()
1461 info->alarm = false; in hp_wmi_hwmon_read()
1466 nsensor = &info->nsensor; in hp_wmi_hwmon_read()
1476 *out_val = info->cached_val; in hp_wmi_hwmon_read()
1488 info = state->info_map[type][channel]; in hp_wmi_hwmon_read_string()
1489 *out_str = info->nsensor.name; in hp_wmi_hwmon_read_string()
1500 return -EINVAL; in hp_wmi_hwmon_write()
1502 mutex_lock(&state->lock); in hp_wmi_hwmon_write()
1504 state->intrusion = false; in hp_wmi_hwmon_write()
1506 mutex_unlock(&state->lock); in hp_wmi_hwmon_write()
1526 struct hp_wmi_info **ptr_info = state->info_map[hwmon_fan]; in match_fan_event()
1527 u8 fan_count = state->channel_count[hwmon_fan]; in match_fan_event()
1536 name = info->nsensor.name; in match_fan_event()
1549 struct hp_wmi_info **ptr_info = state->info_map[hwmon_temp]; in match_temp_events()
1550 u8 temp_count = state->channel_count[hwmon_temp]; in match_temp_events()
1575 name = info->nsensor.name; in match_temp_events()
1593 /* hp_wmi_devm_debugfs_remove - devm callback for WMI event handler removal */
1599 /* hp_wmi_notify - WMI event notification handler */
1605 struct device *dev = &state->wdev->dev; in hp_wmi_notify()
1616 * ACPI Warning: \_SB.WMID._WED: Return type mismatch - in hp_wmi_notify()
1622 * business-class systems, but it refers to \\.\root\WMI\hpqBEvnt on in hp_wmi_notify()
1623 * non-business-class systems. Per the existing hp-wmi driver, it in hp_wmi_notify()
1625 * indeed take the form of a raw ACPI_BUFFER on non-business-class in hp_wmi_notify()
1633 mutex_lock(&state->lock); in hp_wmi_notify()
1645 dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type); in hp_wmi_notify()
1654 fan_info->alarm = true; in hp_wmi_notify()
1658 state->intrusion = true; in hp_wmi_notify()
1664 temp_info[--count]->alarm = true; in hp_wmi_notify()
1678 mutex_unlock(&state->lock); in hp_wmi_notify()
1703 return -ENOMEM; in init_platform_events()
1708 return -EIO; in init_platform_events()
1732 struct hp_wmi_info ***info_map = state->info_map; in init_numeric_sensors()
1733 u8 *channel_count = state->channel_count; in init_numeric_sensors()
1734 struct device *dev = &state->wdev->dev; in init_numeric_sensors()
1751 return -ENODATA; in init_numeric_sensors()
1755 return -ENOMEM; in init_numeric_sensors()
1760 return -EIO; in init_numeric_sensors()
1762 info->instance = i; in init_numeric_sensors()
1763 info->state = state; in init_numeric_sensors()
1764 nsensor = &info->nsensor; in init_numeric_sensors()
1785 info->type = type; in init_numeric_sensors()
1796 type = info->type; in init_numeric_sensors()
1804 return -ENOMEM; in init_numeric_sensors()
1867 * - Strings are freeform and may vary, cf. sensor Name "CPU0 Fan" in find_event_attributes()
1869 * - Leading/trailing whitespace is a rare but real possibility [3]. in find_event_attributes()
1870 * - The HPBIOS_PlatformEvents object may not exist or its instances in find_event_attributes()
1871 * may show that the system only has e.g. BIOS setting-related in find_event_attributes()
1886 event_name = pevents->name; in find_event_attributes()
1887 event_description = pevents->description; in find_event_attributes()
1888 event_category = pevents->category; in find_event_attributes()
1897 fan_info->has_alarm = true; in find_event_attributes()
1902 state->has_intrusion = true; in find_event_attributes()
1913 temp_info[--count]->has_alarm = true; in find_event_attributes()
1928 struct hp_wmi_info ***info_map = state->info_map; in make_chip_info()
1929 u8 *channel_count = state->channel_count; in make_chip_info()
1931 struct device *dev = &state->wdev->dev; in make_chip_info()
1942 if (has_events && state->has_intrusion) in make_chip_info()
1952 return -ENOMEM; in make_chip_info()
1957 return -ENOMEM; in make_chip_info()
1969 return -ENOMEM; in make_chip_info()
1972 channel_info->type = type; in make_chip_info()
1973 channel_info->config = config; in make_chip_info()
1984 if (info_map[type][i]->has_alarm) in make_chip_info()
1993 struct device *dev = &state->wdev->dev; in add_event_handler()
2014 struct device *dev = &state->wdev->dev; in hp_wmi_sensors_init()
2057 struct device *dev = &wdev->dev; in hp_wmi_sensors_probe()
2062 return -ENOMEM; in hp_wmi_sensors_probe()
2064 state->wdev = wdev; in hp_wmi_sensors_probe()
2066 mutex_init(&state->lock); in hp_wmi_sensors_probe()
2079 .driver = { .name = "hp-wmi-sensors" },