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

HID: hid-sensor-custom: Add custom sensor iio support

Currently custom sensors properties are not decoded and it is up to
user space to interpret.

Some manufacturers already standardized the meaning of some custom sensors.
They can be presented as a proper IIO sensor. We can identify these sensors
based on manufacturer and serial number property in the report.

This change is identifying hinge sensor when the manufacturer is "INTEL".
This creates a platform device so that a sensor driver can be loaded to
process these sensors.

Signed-off-by: Ye Xiang <xiang.ye@intel.com>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Link: https://lore.kernel.org/r/20201215054444.9324-2-xiang.ye@intel.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Ye Xiang and committed by
Jonathan Cameron
23931967 ce69361a

+157
+143
drivers/hid/hid-sensor-custom.c
··· 4 4 * Copyright (c) 2015, Intel Corporation. 5 5 */ 6 6 7 + #include <linux/ctype.h> 7 8 #include <linux/kernel.h> 8 9 #include <linux/module.h> 9 10 #include <linux/init.h> ··· 22 21 #define HID_CUSTOM_TOTAL_ATTRS (HID_CUSTOM_MAX_CORE_ATTRS + 1) 23 22 #define HID_CUSTOM_FIFO_SIZE 4096 24 23 #define HID_CUSTOM_MAX_FEATURE_BYTES 64 24 + #define HID_SENSOR_USAGE_LENGTH (4 + 1) 25 25 26 26 struct hid_sensor_custom_field { 27 27 int report_id; ··· 52 50 struct kfifo data_fifo; 53 51 unsigned long misc_opened; 54 52 wait_queue_head_t wait; 53 + struct platform_device *custom_pdev; 55 54 }; 56 55 57 56 /* Header for each sample to user space via dev interface */ ··· 749 746 750 747 } 751 748 749 + /* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ 750 + static const char *const known_sensor_luid[] = { "020B000000000000" }; 751 + 752 + static int get_luid_table_index(unsigned char *usage_str) 753 + { 754 + int i; 755 + 756 + for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { 757 + if (!strncmp(usage_str, known_sensor_luid[i], 758 + strlen(known_sensor_luid[i]))) 759 + return i; 760 + } 761 + 762 + return -ENODEV; 763 + } 764 + 765 + static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) 766 + { 767 + struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; 768 + struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; 769 + int report_size; 770 + int ret; 771 + static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; 772 + static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; 773 + int i; 774 + 775 + memset(w_buf, 0, sizeof(w_buf)); 776 + memset(buf, 0, sizeof(buf)); 777 + 778 + /* get manufacturer info */ 779 + ret = sensor_hub_input_get_attribute_info(hsdev, 780 + HID_FEATURE_REPORT, hsdev->usage, 781 + HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); 782 + if (ret < 0) 783 + return ret; 784 + 785 + report_size = 786 + sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, 787 + sensor_manufacturer.index, sizeof(w_buf), 788 + w_buf); 789 + if (report_size <= 0) { 790 + hid_err(hsdev->hdev, 791 + "Failed to get sensor manufacturer info %d\n", 792 + report_size); 793 + return -ENODEV; 794 + } 795 + 796 + /* convert from wide char to char */ 797 + for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) 798 + buf[i] = (char)w_buf[i]; 799 + 800 + /* ensure it's ISH sensor */ 801 + if (strncmp(buf, "INTEL", strlen("INTEL"))) 802 + return -ENODEV; 803 + 804 + memset(w_buf, 0, sizeof(w_buf)); 805 + memset(buf, 0, sizeof(buf)); 806 + 807 + /* get real usage id */ 808 + ret = sensor_hub_input_get_attribute_info(hsdev, 809 + HID_FEATURE_REPORT, hsdev->usage, 810 + HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); 811 + if (ret < 0) 812 + return ret; 813 + 814 + report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, 815 + sensor_luid_info.index, sizeof(w_buf), 816 + w_buf); 817 + if (report_size <= 0) { 818 + hid_err(hsdev->hdev, "Failed to get real usage info %d\n", 819 + report_size); 820 + return -ENODEV; 821 + } 822 + 823 + /* convert from wide char to char */ 824 + for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) 825 + buf[i] = (char)w_buf[i]; 826 + 827 + if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { 828 + hid_err(hsdev->hdev, 829 + "%s luid length not match %zu != (%zu + 5)\n", __func__, 830 + strlen(buf), strlen(known_sensor_luid[0])); 831 + return -ENODEV; 832 + } 833 + 834 + /* get table index with luid (not matching 'LUID: ' in luid) */ 835 + return get_luid_table_index(&buf[5]); 836 + } 837 + 838 + static struct platform_device * 839 + hid_sensor_register_platform_device(struct platform_device *pdev, 840 + struct hid_sensor_hub_device *hsdev, 841 + int index) 842 + { 843 + char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; 844 + struct platform_device *custom_pdev; 845 + const char *dev_name; 846 + char *c; 847 + 848 + /* copy real usage id */ 849 + memcpy(real_usage, known_sensor_luid[index], 4); 850 + 851 + /* usage id are all lowcase */ 852 + for (c = real_usage; *c != '\0'; c++) 853 + *c = tolower(*c); 854 + 855 + /* HID-SENSOR-INT-REAL_USAGE_ID */ 856 + dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); 857 + if (!dev_name) 858 + return ERR_PTR(-ENOMEM); 859 + 860 + custom_pdev = platform_device_register_data(pdev->dev.parent, dev_name, 861 + PLATFORM_DEVID_NONE, hsdev, 862 + sizeof(*hsdev)); 863 + kfree(dev_name); 864 + return custom_pdev; 865 + } 866 + 752 867 static int hid_sensor_custom_probe(struct platform_device *pdev) 753 868 { 754 869 struct hid_sensor_custom *sensor_inst; 755 870 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 756 871 int ret; 872 + int index; 757 873 758 874 sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), 759 875 GFP_KERNEL); ··· 886 764 sensor_inst->pdev = pdev; 887 765 mutex_init(&sensor_inst->mutex); 888 766 platform_set_drvdata(pdev, sensor_inst); 767 + 768 + index = get_known_custom_sensor_index(hsdev); 769 + if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { 770 + sensor_inst->custom_pdev = 771 + hid_sensor_register_platform_device(pdev, hsdev, index); 772 + 773 + ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); 774 + if (ret) { 775 + dev_err(&pdev->dev, 776 + "register_platform_device failed\n"); 777 + return ret; 778 + } 779 + 780 + return 0; 781 + } 782 + 889 783 ret = sensor_hub_register_callback(hsdev, hsdev->usage, 890 784 &sensor_inst->callbacks); 891 785 if (ret < 0) { ··· 939 801 { 940 802 struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev); 941 803 struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 804 + 805 + if (sensor_inst->custom_pdev) { 806 + platform_device_unregister(sensor_inst->custom_pdev); 807 + return 0; 808 + } 942 809 943 810 hid_sensor_custom_dev_if_remove(sensor_inst); 944 811 hid_sensor_custom_remove_attributes(sensor_inst);
+14
include/linux/hid-sensor-ids.h
··· 128 128 #define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND 0x15 129 129 130 130 /* Common selectors */ 131 + #define HID_USAGE_SENSOR_PROP_DESC 0x200300 132 + #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 133 + #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 134 + #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 131 135 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E 132 136 #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F 133 137 #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 ··· 161 157 /* Report State enumerations */ 162 158 #define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x200840 163 159 #define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x200841 160 + 161 + /* Custom Sensor (2000e1) */ 162 + #define HID_USAGE_SENSOR_HINGE 0x20020B 163 + #define HID_USAGE_SENSOR_DATA_FIELD_LOCATION 0x200400 164 + #define HID_USAGE_SENSOR_DATA_FIELE_TIME_SINCE_SYS_BOOT 0x20052B 165 + #define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_USAGE 0x200541 166 + #define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE_BASE 0x200543 167 + /* Custom Sensor data 28=>x>=0 */ 168 + #define HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE(x) \ 169 + (HID_USAGE_SENSOR_DATA_FIELD_CUSTOM_VALUE_BASE + (x)) 164 170 165 171 #endif