Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: hid-sensor-custom: Allow more custom iio sensors

The known LUID table for established/known custom HID sensors was
limited to sensors with "INTEL" as manufacturer. But some vendors such
as Lenovo also include fairly standard iio sensors (e.g. ambient light)
in their custom sensors.

Expand the known custom sensors table by a tag used for the platform
device name and match sensors based on the LUID as well as optionally
on model and manufacturer properties.

Signed-off-by: Philipp Jungkamp <p.jungkamp@gmx.net>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Philipp Jungkamp and committed by
Jiri Kosina
98c062e8 2043f9a3

+141 -74
+140 -74
drivers/hid/hid-sensor-custom.c
··· 5 5 */ 6 6 7 7 #include <linux/ctype.h> 8 + #include <linux/dmi.h> 8 9 #include <linux/kernel.h> 9 10 #include <linux/module.h> 10 11 #include <linux/init.h> ··· 751 750 752 751 } 753 752 754 - /* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ 755 - static const char *const known_sensor_luid[] = { "020B000000000000" }; 753 + /* 754 + * Match a known custom sensor. 755 + * tag and luid is mandatory. 756 + */ 757 + struct hid_sensor_custom_match { 758 + const char *tag; 759 + const char *luid; 760 + const char *model; 761 + const char *manufacturer; 762 + bool check_dmi; 763 + struct dmi_system_id dmi; 764 + }; 756 765 757 - static int get_luid_table_index(unsigned char *usage_str) 766 + /* 767 + * Custom sensor properties used for matching. 768 + */ 769 + struct hid_sensor_custom_properties { 770 + u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES]; 771 + u16 model[HID_CUSTOM_MAX_FEATURE_BYTES]; 772 + u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES]; 773 + }; 774 + 775 + static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = { 776 + /* 777 + * Intel Integrated Sensor Hub (ISH) 778 + */ 779 + { /* Intel ISH hinge */ 780 + .tag = "INT", 781 + .luid = "020B000000000000", 782 + .manufacturer = "INTEL", 783 + }, 784 + {} 785 + }; 786 + 787 + static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match, 788 + size_t count) 758 789 { 759 - int i; 760 - 761 - for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { 762 - if (!strncmp(usage_str, known_sensor_luid[i], 763 - strlen(known_sensor_luid[i]))) 764 - return i; 790 + while (count-- && *prop && *match) { 791 + if (*prop != (u16) *match) 792 + return false; 793 + prop++; 794 + match++; 765 795 } 766 796 767 - return -ENODEV; 797 + return (count == -1) || *prop == (u16)*match; 768 798 } 769 799 770 - static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) 800 + static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev, 801 + u32 prop_usage_id, size_t prop_size, 802 + u16 *prop) 771 803 { 772 - struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; 773 - struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; 774 - int report_size; 804 + struct hid_sensor_hub_attribute_info prop_attr = { 0 }; 775 805 int ret; 776 - static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; 777 - static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; 778 - int i; 779 806 780 - memset(w_buf, 0, sizeof(w_buf)); 781 - memset(buf, 0, sizeof(buf)); 807 + memset(prop, 0, prop_size); 782 808 783 - /* get manufacturer info */ 784 - ret = sensor_hub_input_get_attribute_info(hsdev, 785 - HID_FEATURE_REPORT, hsdev->usage, 786 - HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); 809 + ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, 810 + hsdev->usage, prop_usage_id, 811 + &prop_attr); 787 812 if (ret < 0) 788 813 return ret; 789 814 790 - report_size = 791 - sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, 792 - sensor_manufacturer.index, sizeof(w_buf), 793 - w_buf); 794 - if (report_size <= 0) { 795 - hid_err(hsdev->hdev, 796 - "Failed to get sensor manufacturer info %d\n", 797 - report_size); 798 - return -ENODEV; 815 + ret = sensor_hub_get_feature(hsdev, prop_attr.report_id, 816 + prop_attr.index, prop_size, prop); 817 + if (ret < 0) { 818 + hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n", 819 + prop_usage_id, ret); 820 + return ret; 799 821 } 800 822 801 - /* convert from wide char to char */ 802 - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) 803 - buf[i] = (char)w_buf[i]; 823 + return 0; 824 + } 804 825 805 - /* ensure it's ISH sensor */ 806 - if (strncmp(buf, "INTEL", strlen("INTEL"))) 807 - return -ENODEV; 826 + static bool 827 + hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev, 828 + const struct hid_sensor_custom_match *match, 829 + const struct hid_sensor_custom_properties *prop) 830 + { 831 + struct dmi_system_id dmi[] = { match->dmi, { 0 } }; 808 832 809 - memset(w_buf, 0, sizeof(w_buf)); 810 - memset(buf, 0, sizeof(buf)); 833 + if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) || 834 + !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid, 835 + HID_CUSTOM_MAX_FEATURE_BYTES - 5)) 836 + return false; 811 837 812 - /* get real usage id */ 813 - ret = sensor_hub_input_get_attribute_info(hsdev, 814 - HID_FEATURE_REPORT, hsdev->usage, 815 - HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); 838 + if (match->model && 839 + !hid_sensor_custom_prop_match_str(prop->model, match->model, 840 + HID_CUSTOM_MAX_FEATURE_BYTES)) 841 + return false; 842 + 843 + if (match->manufacturer && 844 + !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer, 845 + HID_CUSTOM_MAX_FEATURE_BYTES)) 846 + return false; 847 + 848 + if (match->check_dmi && !dmi_check_system(dmi)) 849 + return false; 850 + 851 + return true; 852 + } 853 + 854 + static int 855 + hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev, 856 + struct hid_sensor_custom_properties *prop) 857 + { 858 + int ret; 859 + 860 + ret = hid_sensor_custom_get_prop(hsdev, 861 + HID_USAGE_SENSOR_PROP_SERIAL_NUM, 862 + HID_CUSTOM_MAX_FEATURE_BYTES, 863 + prop->serial_num); 816 864 if (ret < 0) 817 865 return ret; 818 866 819 - report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, 820 - sensor_luid_info.index, sizeof(w_buf), 821 - w_buf); 822 - if (report_size <= 0) { 823 - hid_err(hsdev->hdev, "Failed to get real usage info %d\n", 824 - report_size); 825 - return -ENODEV; 867 + /* 868 + * Ignore errors on the following model and manufacturer properties. 869 + * Because these are optional, it is not an error if they are missing. 870 + */ 871 + 872 + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL, 873 + HID_CUSTOM_MAX_FEATURE_BYTES, 874 + prop->model); 875 + 876 + hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER, 877 + HID_CUSTOM_MAX_FEATURE_BYTES, 878 + prop->manufacturer); 879 + 880 + return 0; 881 + } 882 + 883 + static int 884 + hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev, 885 + const struct hid_sensor_custom_match **known) 886 + { 887 + int ret; 888 + const struct hid_sensor_custom_match *match = 889 + hid_sensor_custom_known_table; 890 + struct hid_sensor_custom_properties prop; 891 + 892 + ret = hid_sensor_custom_properties_get(hsdev, &prop); 893 + if (ret < 0) 894 + return ret; 895 + 896 + while (match->tag) { 897 + if (hid_sensor_custom_do_match(hsdev, match, &prop)) { 898 + *known = match; 899 + return 0; 900 + } 901 + match++; 826 902 } 827 903 828 - /* convert from wide char to char */ 829 - for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) 830 - buf[i] = (char)w_buf[i]; 831 - 832 - if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { 833 - hid_err(hsdev->hdev, 834 - "%s luid length not match %zu != (%zu + 5)\n", __func__, 835 - strlen(buf), strlen(known_sensor_luid[0])); 836 - return -ENODEV; 837 - } 838 - 839 - /* get table index with luid (not matching 'LUID: ' in luid) */ 840 - return get_luid_table_index(&buf[5]); 904 + return -ENODATA; 841 905 } 842 906 843 907 static struct platform_device * 844 908 hid_sensor_register_platform_device(struct platform_device *pdev, 845 909 struct hid_sensor_hub_device *hsdev, 846 - int index) 910 + const struct hid_sensor_custom_match *match) 847 911 { 848 - char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; 912 + char real_usage[HID_SENSOR_USAGE_LENGTH]; 849 913 struct platform_device *custom_pdev; 850 914 const char *dev_name; 851 915 char *c; 852 916 853 - /* copy real usage id */ 854 - memcpy(real_usage, known_sensor_luid[index], 4); 917 + memcpy(real_usage, match->luid, 4); 855 918 856 919 /* usage id are all lowcase */ 857 920 for (c = real_usage; *c != '\0'; c++) 858 921 *c = tolower(*c); 859 922 860 - /* HID-SENSOR-INT-REAL_USAGE_ID */ 861 - dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); 923 + /* HID-SENSOR-TAG-REAL_USAGE_ID */ 924 + dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s", 925 + match->tag, real_usage); 862 926 if (!dev_name) 863 927 return ERR_PTR(-ENOMEM); 864 928 ··· 939 873 struct hid_sensor_custom *sensor_inst; 940 874 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 941 875 int ret; 942 - int index; 876 + const struct hid_sensor_custom_match *match; 943 877 944 878 sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), 945 879 GFP_KERNEL); ··· 954 888 mutex_init(&sensor_inst->mutex); 955 889 platform_set_drvdata(pdev, sensor_inst); 956 890 957 - index = get_known_custom_sensor_index(hsdev); 958 - if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { 891 + ret = hid_sensor_custom_get_known(hsdev, &match); 892 + if (!ret) { 959 893 sensor_inst->custom_pdev = 960 - hid_sensor_register_platform_device(pdev, hsdev, index); 894 + hid_sensor_register_platform_device(pdev, hsdev, match); 961 895 962 896 ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); 963 897 if (ret) {
+1
include/linux/hid-sensor-ids.h
··· 132 132 #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 133 133 #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 134 134 #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 135 + #define HID_USAGE_SENSOR_PROP_MODEL 0x200306 135 136 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E 136 137 #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F 137 138 #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310