Loading drivers/hid/hid-sensor-custom.c +169 −73 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ */ #include <linux/ctype.h> #include <linux/dmi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> Loading Loading @@ -750,114 +751,209 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom } /* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ static const char *const known_sensor_luid[] = { "020B000000000000" }; /* * Match a known custom sensor. * tag and luid is mandatory. */ struct hid_sensor_custom_match { const char *tag; const char *luid; const char *model; const char *manufacturer; bool check_dmi; struct dmi_system_id dmi; }; static int get_luid_table_index(unsigned char *usage_str) { int i; /* * Custom sensor properties used for matching. */ struct hid_sensor_custom_properties { u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES]; u16 model[HID_CUSTOM_MAX_FEATURE_BYTES]; u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES]; }; for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { if (!strncmp(usage_str, known_sensor_luid[i], strlen(known_sensor_luid[i]))) return i; static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = { /* * Intel Integrated Sensor Hub (ISH) */ { /* Intel ISH hinge */ .tag = "INT", .luid = "020B000000000000", .manufacturer = "INTEL", }, /* * Lenovo Intelligent Sensing Solution (LISS) */ { /* ambient light */ .tag = "LISS", .luid = "0041010200000082", .model = "STK3X3X Sensor", .manufacturer = "Vendor 258", .check_dmi = true, .dmi.matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), } }, { /* human presence */ .tag = "LISS", .luid = "0226000171AC0081", .model = "VL53L1_HOD Sensor", .manufacturer = "ST_MICRO", .check_dmi = true, .dmi.matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), } }, {} }; static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match, size_t count) { while (count-- && *prop && *match) { if (*prop != (u16) *match) return false; prop++; match++; } return -ENODEV; return (count == -1) || *prop == (u16)*match; } static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev, u32 prop_usage_id, size_t prop_size, u16 *prop) { struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; int report_size; struct hid_sensor_hub_attribute_info prop_attr = { 0 }; int ret; static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; int i; memset(w_buf, 0, sizeof(w_buf)); memset(buf, 0, sizeof(buf)); memset(prop, 0, prop_size); /* get manufacturer info */ ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, prop_usage_id, &prop_attr); if (ret < 0) return ret; report_size = sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, sensor_manufacturer.index, sizeof(w_buf), w_buf); if (report_size <= 0) { hid_err(hsdev->hdev, "Failed to get sensor manufacturer info %d\n", report_size); return -ENODEV; ret = sensor_hub_get_feature(hsdev, prop_attr.report_id, prop_attr.index, prop_size, prop); if (ret < 0) { hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n", prop_usage_id, ret); return ret; } /* convert from wide char to char */ for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) buf[i] = (char)w_buf[i]; return 0; } /* ensure it's ISH sensor */ if (strncmp(buf, "INTEL", strlen("INTEL"))) return -ENODEV; static bool hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev, const struct hid_sensor_custom_match *match, const struct hid_sensor_custom_properties *prop) { struct dmi_system_id dmi[] = { match->dmi, { 0 } }; if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) || !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid, HID_CUSTOM_MAX_FEATURE_BYTES - 5)) return false; if (match->model && !hid_sensor_custom_prop_match_str(prop->model, match->model, HID_CUSTOM_MAX_FEATURE_BYTES)) return false; if (match->manufacturer && !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer, HID_CUSTOM_MAX_FEATURE_BYTES)) return false; if (match->check_dmi && !dmi_check_system(dmi)) return false; return true; } memset(w_buf, 0, sizeof(w_buf)); memset(buf, 0, sizeof(buf)); static int hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev, struct hid_sensor_custom_properties *prop) { int ret; /* get real usage id */ ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); ret = hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_SERIAL_NUM, HID_CUSTOM_MAX_FEATURE_BYTES, prop->serial_num); if (ret < 0) return ret; report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, sensor_luid_info.index, sizeof(w_buf), w_buf); if (report_size <= 0) { hid_err(hsdev->hdev, "Failed to get real usage info %d\n", report_size); return -ENODEV; } /* * Ignore errors on the following model and manufacturer properties. * Because these are optional, it is not an error if they are missing. */ /* convert from wide char to char */ for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) buf[i] = (char)w_buf[i]; hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL, HID_CUSTOM_MAX_FEATURE_BYTES, prop->model); if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { hid_err(hsdev->hdev, "%s luid length not match %zu != (%zu + 5)\n", __func__, strlen(buf), strlen(known_sensor_luid[0])); return -ENODEV; hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER, HID_CUSTOM_MAX_FEATURE_BYTES, prop->manufacturer); return 0; } /* get table index with luid (not matching 'LUID: ' in luid) */ return get_luid_table_index(&buf[5]); static int hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev, const struct hid_sensor_custom_match **known) { int ret; const struct hid_sensor_custom_match *match = hid_sensor_custom_known_table; struct hid_sensor_custom_properties *prop; prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL); if (!prop) return -ENOMEM; ret = hid_sensor_custom_properties_get(hsdev, prop); if (ret < 0) goto out; while (match->tag) { if (hid_sensor_custom_do_match(hsdev, match, prop)) { *known = match; ret = 0; goto out; } match++; } ret = -ENODATA; out: kfree(prop); return ret; } static struct platform_device * hid_sensor_register_platform_device(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, int index) const struct hid_sensor_custom_match *match) { char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; char real_usage[HID_SENSOR_USAGE_LENGTH]; struct platform_device *custom_pdev; const char *dev_name; char *c; /* copy real usage id */ memcpy(real_usage, known_sensor_luid[index], 4); memcpy(real_usage, match->luid, 4); /* usage id are all lowcase */ for (c = real_usage; *c != '\0'; c++) *c = tolower(*c); /* HID-SENSOR-INT-REAL_USAGE_ID */ dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); /* HID-SENSOR-TAG-REAL_USAGE_ID */ dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s", match->tag, real_usage); if (!dev_name) return ERR_PTR(-ENOMEM); Loading @@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) struct hid_sensor_custom *sensor_inst; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; int ret; int index; const struct hid_sensor_custom_match *match; sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), GFP_KERNEL); Loading @@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) mutex_init(&sensor_inst->mutex); platform_set_drvdata(pdev, sensor_inst); index = get_known_custom_sensor_index(hsdev); if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { ret = hid_sensor_custom_get_known(hsdev, &match); if (!ret) { sensor_inst->custom_pdev = hid_sensor_register_platform_device(pdev, hsdev, index); hid_sensor_register_platform_device(pdev, hsdev, match); ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); if (ret) { Loading drivers/iio/light/hid-sensor-als.c +14 −13 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ static int als_read_raw(struct iio_dev *indio_dev, long mask) { struct als_state *als_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev; int report_id = -1; u32 address; int ret_type; Loading @@ -110,11 +111,8 @@ static int als_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&als_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( als_state->common_attributes.hsdev, HID_USAGE_SENSOR_ALS, address, report_id, SENSOR_HUB_SYNC, min < 0); hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&als_state->common_attributes, false); } else { Loading Loading @@ -259,9 +257,7 @@ static int als_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, st->als_illum.report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_ALS, &st->als_illum, st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum, &st->scale_pre_decml, &st->scale_post_decml); return ret; Loading @@ -285,7 +281,8 @@ static int hid_als_probe(struct platform_device *pdev) als_state->common_attributes.hsdev = hsdev; als_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &als_state->common_attributes, als_sensitivity_addresses, ARRAY_SIZE(als_sensitivity_addresses)); Loading @@ -303,7 +300,8 @@ static int hid_als_probe(struct platform_device *pdev) ret = als_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, HID_USAGE_SENSOR_ALS, als_state); hsdev->usage, als_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; Loading Loading @@ -333,8 +331,7 @@ static int hid_als_probe(struct platform_device *pdev) als_state->callbacks.send_event = als_proc_event; als_state->callbacks.capture_sample = als_capture_sample; als_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS, &als_state->callbacks); ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); goto error_iio_unreg; Loading @@ -356,7 +353,7 @@ static int hid_als_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); Loading @@ -368,6 +365,10 @@ static const struct platform_device_id hid_als_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200041", }, { /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0041", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_als_ids); Loading drivers/iio/light/hid-sensor-prox.c +23 −14 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; int report_id = -1; u32 address; int ret_type; Loading @@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, report_id = prox_state->prox_attr.report_id; min = prox_state->prox_attr.logical_minimum; address = HID_USAGE_SENSOR_HUMAN_PRESENCE; hsdev = prox_state->common_attributes.hsdev; break; default: report_id = -1; Loading @@ -84,11 +86,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&prox_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( prox_state->common_attributes.hsdev, HID_USAGE_SENSOR_PROX, address, report_id, SENSOR_HUB_SYNC, min < 0); hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&prox_state->common_attributes, false); } else { Loading Loading @@ -191,12 +190,18 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_HUMAN_PRESENCE: switch (raw_len) { case 1: prox_state->human_presence = *(u8 *)raw_data; return 0; case 4: prox_state->human_presence = *(u32 *)raw_data; ret = 0; break; return 0; default: break; } break; } return ret; } Loading Loading @@ -244,7 +249,7 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->common_attributes.hsdev = hsdev; prox_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &prox_state->common_attributes, prox_sensitivity_addresses, ARRAY_SIZE(prox_sensitivity_addresses)); Loading @@ -262,7 +267,7 @@ static int hid_prox_probe(struct platform_device *pdev) ret = prox_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, HID_USAGE_SENSOR_PROX, prox_state); hsdev->usage, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; Loading Loading @@ -291,7 +296,7 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->callbacks.send_event = prox_proc_event; prox_state->callbacks.capture_sample = prox_capture_sample; prox_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX, ret = sensor_hub_register_callback(hsdev, hsdev->usage, &prox_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); Loading @@ -314,7 +319,7 @@ static int hid_prox_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX); sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); Loading @@ -326,6 +331,10 @@ static const struct platform_device_id hid_prox_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200011", }, { /* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0226", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_prox_ids); Loading include/linux/hid-sensor-ids.h +1 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 #define HID_USAGE_SENSOR_PROP_MODEL 0x200306 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 Loading Loading
drivers/hid/hid-sensor-custom.c +169 −73 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ */ #include <linux/ctype.h> #include <linux/dmi.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> Loading Loading @@ -750,114 +751,209 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom } /* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */ static const char *const known_sensor_luid[] = { "020B000000000000" }; /* * Match a known custom sensor. * tag and luid is mandatory. */ struct hid_sensor_custom_match { const char *tag; const char *luid; const char *model; const char *manufacturer; bool check_dmi; struct dmi_system_id dmi; }; static int get_luid_table_index(unsigned char *usage_str) { int i; /* * Custom sensor properties used for matching. */ struct hid_sensor_custom_properties { u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES]; u16 model[HID_CUSTOM_MAX_FEATURE_BYTES]; u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES]; }; for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) { if (!strncmp(usage_str, known_sensor_luid[i], strlen(known_sensor_luid[i]))) return i; static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = { /* * Intel Integrated Sensor Hub (ISH) */ { /* Intel ISH hinge */ .tag = "INT", .luid = "020B000000000000", .manufacturer = "INTEL", }, /* * Lenovo Intelligent Sensing Solution (LISS) */ { /* ambient light */ .tag = "LISS", .luid = "0041010200000082", .model = "STK3X3X Sensor", .manufacturer = "Vendor 258", .check_dmi = true, .dmi.matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), } }, { /* human presence */ .tag = "LISS", .luid = "0226000171AC0081", .model = "VL53L1_HOD Sensor", .manufacturer = "ST_MICRO", .check_dmi = true, .dmi.matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), } }, {} }; static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match, size_t count) { while (count-- && *prop && *match) { if (*prop != (u16) *match) return false; prop++; match++; } return -ENODEV; return (count == -1) || *prop == (u16)*match; } static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev) static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev, u32 prop_usage_id, size_t prop_size, u16 *prop) { struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 }; struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 }; int report_size; struct hid_sensor_hub_attribute_info prop_attr = { 0 }; int ret; static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES]; static char buf[HID_CUSTOM_MAX_FEATURE_BYTES]; int i; memset(w_buf, 0, sizeof(w_buf)); memset(buf, 0, sizeof(buf)); memset(prop, 0, prop_size); /* get manufacturer info */ ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer); ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, prop_usage_id, &prop_attr); if (ret < 0) return ret; report_size = sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id, sensor_manufacturer.index, sizeof(w_buf), w_buf); if (report_size <= 0) { hid_err(hsdev->hdev, "Failed to get sensor manufacturer info %d\n", report_size); return -ENODEV; ret = sensor_hub_get_feature(hsdev, prop_attr.report_id, prop_attr.index, prop_size, prop); if (ret < 0) { hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n", prop_usage_id, ret); return ret; } /* convert from wide char to char */ for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) buf[i] = (char)w_buf[i]; return 0; } /* ensure it's ISH sensor */ if (strncmp(buf, "INTEL", strlen("INTEL"))) return -ENODEV; static bool hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev, const struct hid_sensor_custom_match *match, const struct hid_sensor_custom_properties *prop) { struct dmi_system_id dmi[] = { match->dmi, { 0 } }; if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) || !hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid, HID_CUSTOM_MAX_FEATURE_BYTES - 5)) return false; if (match->model && !hid_sensor_custom_prop_match_str(prop->model, match->model, HID_CUSTOM_MAX_FEATURE_BYTES)) return false; if (match->manufacturer && !hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer, HID_CUSTOM_MAX_FEATURE_BYTES)) return false; if (match->check_dmi && !dmi_check_system(dmi)) return false; return true; } memset(w_buf, 0, sizeof(w_buf)); memset(buf, 0, sizeof(buf)); static int hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev, struct hid_sensor_custom_properties *prop) { int ret; /* get real usage id */ ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, hsdev->usage, HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info); ret = hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_SERIAL_NUM, HID_CUSTOM_MAX_FEATURE_BYTES, prop->serial_num); if (ret < 0) return ret; report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id, sensor_luid_info.index, sizeof(w_buf), w_buf); if (report_size <= 0) { hid_err(hsdev->hdev, "Failed to get real usage info %d\n", report_size); return -ENODEV; } /* * Ignore errors on the following model and manufacturer properties. * Because these are optional, it is not an error if they are missing. */ /* convert from wide char to char */ for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++) buf[i] = (char)w_buf[i]; hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL, HID_CUSTOM_MAX_FEATURE_BYTES, prop->model); if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) { hid_err(hsdev->hdev, "%s luid length not match %zu != (%zu + 5)\n", __func__, strlen(buf), strlen(known_sensor_luid[0])); return -ENODEV; hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER, HID_CUSTOM_MAX_FEATURE_BYTES, prop->manufacturer); return 0; } /* get table index with luid (not matching 'LUID: ' in luid) */ return get_luid_table_index(&buf[5]); static int hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev, const struct hid_sensor_custom_match **known) { int ret; const struct hid_sensor_custom_match *match = hid_sensor_custom_known_table; struct hid_sensor_custom_properties *prop; prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL); if (!prop) return -ENOMEM; ret = hid_sensor_custom_properties_get(hsdev, prop); if (ret < 0) goto out; while (match->tag) { if (hid_sensor_custom_do_match(hsdev, match, prop)) { *known = match; ret = 0; goto out; } match++; } ret = -ENODATA; out: kfree(prop); return ret; } static struct platform_device * hid_sensor_register_platform_device(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, int index) const struct hid_sensor_custom_match *match) { char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 }; char real_usage[HID_SENSOR_USAGE_LENGTH]; struct platform_device *custom_pdev; const char *dev_name; char *c; /* copy real usage id */ memcpy(real_usage, known_sensor_luid[index], 4); memcpy(real_usage, match->luid, 4); /* usage id are all lowcase */ for (c = real_usage; *c != '\0'; c++) *c = tolower(*c); /* HID-SENSOR-INT-REAL_USAGE_ID */ dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage); /* HID-SENSOR-TAG-REAL_USAGE_ID */ dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s", match->tag, real_usage); if (!dev_name) return ERR_PTR(-ENOMEM); Loading @@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) struct hid_sensor_custom *sensor_inst; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; int ret; int index; const struct hid_sensor_custom_match *match; sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst), GFP_KERNEL); Loading @@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev) mutex_init(&sensor_inst->mutex); platform_set_drvdata(pdev, sensor_inst); index = get_known_custom_sensor_index(hsdev); if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) { ret = hid_sensor_custom_get_known(hsdev, &match); if (!ret) { sensor_inst->custom_pdev = hid_sensor_register_platform_device(pdev, hsdev, index); hid_sensor_register_platform_device(pdev, hsdev, match); ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev); if (ret) { Loading
drivers/iio/light/hid-sensor-als.c +14 −13 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ static int als_read_raw(struct iio_dev *indio_dev, long mask) { struct als_state *als_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev; int report_id = -1; u32 address; int ret_type; Loading @@ -110,11 +111,8 @@ static int als_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&als_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( als_state->common_attributes.hsdev, HID_USAGE_SENSOR_ALS, address, report_id, SENSOR_HUB_SYNC, min < 0); hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&als_state->common_attributes, false); } else { Loading Loading @@ -259,9 +257,7 @@ static int als_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, st->als_illum.report_id); st->scale_precision = hid_sensor_format_scale( HID_USAGE_SENSOR_ALS, &st->als_illum, st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum, &st->scale_pre_decml, &st->scale_post_decml); return ret; Loading @@ -285,7 +281,8 @@ static int hid_als_probe(struct platform_device *pdev) als_state->common_attributes.hsdev = hsdev; als_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &als_state->common_attributes, als_sensitivity_addresses, ARRAY_SIZE(als_sensitivity_addresses)); Loading @@ -303,7 +300,8 @@ static int hid_als_probe(struct platform_device *pdev) ret = als_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, HID_USAGE_SENSOR_ALS, als_state); hsdev->usage, als_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; Loading Loading @@ -333,8 +331,7 @@ static int hid_als_probe(struct platform_device *pdev) als_state->callbacks.send_event = als_proc_event; als_state->callbacks.capture_sample = als_capture_sample; als_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS, &als_state->callbacks); ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); goto error_iio_unreg; Loading @@ -356,7 +353,7 @@ static int hid_als_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct als_state *als_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes); Loading @@ -368,6 +365,10 @@ static const struct platform_device_id hid_als_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200041", }, { /* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0041", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_als_ids); Loading
drivers/iio/light/hid-sensor-prox.c +23 −14 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, long mask) { struct prox_state *prox_state = iio_priv(indio_dev); struct hid_sensor_hub_device *hsdev; int report_id = -1; u32 address; int ret_type; Loading @@ -75,6 +76,7 @@ static int prox_read_raw(struct iio_dev *indio_dev, report_id = prox_state->prox_attr.report_id; min = prox_state->prox_attr.logical_minimum; address = HID_USAGE_SENSOR_HUMAN_PRESENCE; hsdev = prox_state->common_attributes.hsdev; break; default: report_id = -1; Loading @@ -84,11 +86,8 @@ static int prox_read_raw(struct iio_dev *indio_dev, hid_sensor_power_state(&prox_state->common_attributes, true); *val = sensor_hub_input_attr_get_raw_value( prox_state->common_attributes.hsdev, HID_USAGE_SENSOR_PROX, address, report_id, SENSOR_HUB_SYNC, min < 0); hsdev, hsdev->usage, address, report_id, SENSOR_HUB_SYNC, min < 0); hid_sensor_power_state(&prox_state->common_attributes, false); } else { Loading Loading @@ -191,12 +190,18 @@ static int prox_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_HUMAN_PRESENCE: switch (raw_len) { case 1: prox_state->human_presence = *(u8 *)raw_data; return 0; case 4: prox_state->human_presence = *(u32 *)raw_data; ret = 0; break; return 0; default: break; } break; } return ret; } Loading Loading @@ -244,7 +249,7 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->common_attributes.hsdev = hsdev; prox_state->common_attributes.pdev = pdev; ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX, ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &prox_state->common_attributes, prox_sensitivity_addresses, ARRAY_SIZE(prox_sensitivity_addresses)); Loading @@ -262,7 +267,7 @@ static int hid_prox_probe(struct platform_device *pdev) ret = prox_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, HID_USAGE_SENSOR_PROX, prox_state); hsdev->usage, prox_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; Loading Loading @@ -291,7 +296,7 @@ static int hid_prox_probe(struct platform_device *pdev) prox_state->callbacks.send_event = prox_proc_event; prox_state->callbacks.capture_sample = prox_capture_sample; prox_state->callbacks.pdev = pdev; ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX, ret = sensor_hub_register_callback(hsdev, hsdev->usage, &prox_state->callbacks); if (ret < 0) { dev_err(&pdev->dev, "callback reg failed\n"); Loading @@ -314,7 +319,7 @@ static int hid_prox_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct prox_state *prox_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX); sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(indio_dev, &prox_state->common_attributes); Loading @@ -326,6 +331,10 @@ static const struct platform_device_id hid_prox_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-200011", }, { /* Format: HID-SENSOR-tag-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-LISS-0226", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_prox_ids); Loading
include/linux/hid-sensor-ids.h +1 −0 Original line number Diff line number Diff line Loading @@ -132,6 +132,7 @@ #define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301 #define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307 #define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305 #define HID_USAGE_SENSOR_PROP_MODEL 0x200306 #define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E #define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F #define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 Loading