Skip to content

Commit 98c062e

Browse files
pjungkampJiri Kosina
authored andcommitted
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 <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]> Acked-by: Srinivas Pandruvada <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 2043f9a commit 98c062e

File tree

2 files changed

+139
-72
lines changed

2 files changed

+139
-72
lines changed

drivers/hid/hid-sensor-custom.c

Lines changed: 138 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <linux/ctype.h>
8+
#include <linux/dmi.h>
89
#include <linux/kernel.h>
910
#include <linux/module.h>
1011
#include <linux/init.h>
@@ -750,114 +751,179 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
750751

751752
}
752753

753-
/* luid defined in FW (e.g. ISH). Maybe used to identify sensor. */
754-
static const char *const known_sensor_luid[] = { "020B000000000000" };
754+
/*
755+
* Match a known custom sensor.
756+
* tag and luid is mandatory.
757+
*/
758+
struct hid_sensor_custom_match {
759+
const char *tag;
760+
const char *luid;
761+
const char *model;
762+
const char *manufacturer;
763+
bool check_dmi;
764+
struct dmi_system_id dmi;
765+
};
755766

756-
static int get_luid_table_index(unsigned char *usage_str)
757-
{
758-
int i;
767+
/*
768+
* Custom sensor properties used for matching.
769+
*/
770+
struct hid_sensor_custom_properties {
771+
u16 serial_num[HID_CUSTOM_MAX_FEATURE_BYTES];
772+
u16 model[HID_CUSTOM_MAX_FEATURE_BYTES];
773+
u16 manufacturer[HID_CUSTOM_MAX_FEATURE_BYTES];
774+
};
759775

760-
for (i = 0; i < ARRAY_SIZE(known_sensor_luid); i++) {
761-
if (!strncmp(usage_str, known_sensor_luid[i],
762-
strlen(known_sensor_luid[i])))
763-
return i;
776+
static const struct hid_sensor_custom_match hid_sensor_custom_known_table[] = {
777+
/*
778+
* Intel Integrated Sensor Hub (ISH)
779+
*/
780+
{ /* Intel ISH hinge */
781+
.tag = "INT",
782+
.luid = "020B000000000000",
783+
.manufacturer = "INTEL",
784+
},
785+
{}
786+
};
787+
788+
static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match,
789+
size_t count)
790+
{
791+
while (count-- && *prop && *match) {
792+
if (*prop != (u16) *match)
793+
return false;
794+
prop++;
795+
match++;
764796
}
765797

766-
return -ENODEV;
798+
return (count == -1) || *prop == (u16)*match;
767799
}
768800

769-
static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev)
801+
static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev,
802+
u32 prop_usage_id, size_t prop_size,
803+
u16 *prop)
770804
{
771-
struct hid_sensor_hub_attribute_info sensor_manufacturer = { 0 };
772-
struct hid_sensor_hub_attribute_info sensor_luid_info = { 0 };
773-
int report_size;
805+
struct hid_sensor_hub_attribute_info prop_attr = { 0 };
774806
int ret;
775-
static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES];
776-
static char buf[HID_CUSTOM_MAX_FEATURE_BYTES];
777-
int i;
778807

779-
memset(w_buf, 0, sizeof(w_buf));
780-
memset(buf, 0, sizeof(buf));
808+
memset(prop, 0, prop_size);
781809

782-
/* get manufacturer info */
783-
ret = sensor_hub_input_get_attribute_info(hsdev,
784-
HID_FEATURE_REPORT, hsdev->usage,
785-
HID_USAGE_SENSOR_PROP_MANUFACTURER, &sensor_manufacturer);
810+
ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
811+
hsdev->usage, prop_usage_id,
812+
&prop_attr);
786813
if (ret < 0)
787814
return ret;
788815

789-
report_size =
790-
sensor_hub_get_feature(hsdev, sensor_manufacturer.report_id,
791-
sensor_manufacturer.index, sizeof(w_buf),
792-
w_buf);
793-
if (report_size <= 0) {
794-
hid_err(hsdev->hdev,
795-
"Failed to get sensor manufacturer info %d\n",
796-
report_size);
797-
return -ENODEV;
816+
ret = sensor_hub_get_feature(hsdev, prop_attr.report_id,
817+
prop_attr.index, prop_size, prop);
818+
if (ret < 0) {
819+
hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n",
820+
prop_usage_id, ret);
821+
return ret;
798822
}
799823

800-
/* convert from wide char to char */
801-
for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
802-
buf[i] = (char)w_buf[i];
824+
return 0;
825+
}
826+
827+
static bool
828+
hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev,
829+
const struct hid_sensor_custom_match *match,
830+
const struct hid_sensor_custom_properties *prop)
831+
{
832+
struct dmi_system_id dmi[] = { match->dmi, { 0 } };
833+
834+
if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) ||
835+
!hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid,
836+
HID_CUSTOM_MAX_FEATURE_BYTES - 5))
837+
return false;
838+
839+
if (match->model &&
840+
!hid_sensor_custom_prop_match_str(prop->model, match->model,
841+
HID_CUSTOM_MAX_FEATURE_BYTES))
842+
return false;
843+
844+
if (match->manufacturer &&
845+
!hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer,
846+
HID_CUSTOM_MAX_FEATURE_BYTES))
847+
return false;
803848

804-
/* ensure it's ISH sensor */
805-
if (strncmp(buf, "INTEL", strlen("INTEL")))
806-
return -ENODEV;
849+
if (match->check_dmi && !dmi_check_system(dmi))
850+
return false;
807851

808-
memset(w_buf, 0, sizeof(w_buf));
809-
memset(buf, 0, sizeof(buf));
852+
return true;
853+
}
810854

811-
/* get real usage id */
812-
ret = sensor_hub_input_get_attribute_info(hsdev,
813-
HID_FEATURE_REPORT, hsdev->usage,
814-
HID_USAGE_SENSOR_PROP_SERIAL_NUM, &sensor_luid_info);
855+
static int
856+
hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev,
857+
struct hid_sensor_custom_properties *prop)
858+
{
859+
int ret;
860+
861+
ret = hid_sensor_custom_get_prop(hsdev,
862+
HID_USAGE_SENSOR_PROP_SERIAL_NUM,
863+
HID_CUSTOM_MAX_FEATURE_BYTES,
864+
prop->serial_num);
815865
if (ret < 0)
816866
return ret;
817867

818-
report_size = sensor_hub_get_feature(hsdev, sensor_luid_info.report_id,
819-
sensor_luid_info.index, sizeof(w_buf),
820-
w_buf);
821-
if (report_size <= 0) {
822-
hid_err(hsdev->hdev, "Failed to get real usage info %d\n",
823-
report_size);
824-
return -ENODEV;
825-
}
868+
/*
869+
* Ignore errors on the following model and manufacturer properties.
870+
* Because these are optional, it is not an error if they are missing.
871+
*/
872+
873+
hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL,
874+
HID_CUSTOM_MAX_FEATURE_BYTES,
875+
prop->model);
826876

827-
/* convert from wide char to char */
828-
for (i = 0; i < ARRAY_SIZE(buf) - 1 && w_buf[i]; i++)
829-
buf[i] = (char)w_buf[i];
877+
hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER,
878+
HID_CUSTOM_MAX_FEATURE_BYTES,
879+
prop->manufacturer);
830880

831-
if (strlen(buf) != strlen(known_sensor_luid[0]) + 5) {
832-
hid_err(hsdev->hdev,
833-
"%s luid length not match %zu != (%zu + 5)\n", __func__,
834-
strlen(buf), strlen(known_sensor_luid[0]));
835-
return -ENODEV;
881+
return 0;
882+
}
883+
884+
static int
885+
hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev,
886+
const struct hid_sensor_custom_match **known)
887+
{
888+
int ret;
889+
const struct hid_sensor_custom_match *match =
890+
hid_sensor_custom_known_table;
891+
struct hid_sensor_custom_properties prop;
892+
893+
ret = hid_sensor_custom_properties_get(hsdev, &prop);
894+
if (ret < 0)
895+
return ret;
896+
897+
while (match->tag) {
898+
if (hid_sensor_custom_do_match(hsdev, match, &prop)) {
899+
*known = match;
900+
return 0;
901+
}
902+
match++;
836903
}
837904

838-
/* get table index with luid (not matching 'LUID: ' in luid) */
839-
return get_luid_table_index(&buf[5]);
905+
return -ENODATA;
840906
}
841907

842908
static struct platform_device *
843909
hid_sensor_register_platform_device(struct platform_device *pdev,
844910
struct hid_sensor_hub_device *hsdev,
845-
int index)
911+
const struct hid_sensor_custom_match *match)
846912
{
847-
char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 };
913+
char real_usage[HID_SENSOR_USAGE_LENGTH];
848914
struct platform_device *custom_pdev;
849915
const char *dev_name;
850916
char *c;
851917

852-
/* copy real usage id */
853-
memcpy(real_usage, known_sensor_luid[index], 4);
918+
memcpy(real_usage, match->luid, 4);
854919

855920
/* usage id are all lowcase */
856921
for (c = real_usage; *c != '\0'; c++)
857922
*c = tolower(*c);
858923

859-
/* HID-SENSOR-INT-REAL_USAGE_ID */
860-
dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage);
924+
/* HID-SENSOR-TAG-REAL_USAGE_ID */
925+
dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s",
926+
match->tag, real_usage);
861927
if (!dev_name)
862928
return ERR_PTR(-ENOMEM);
863929

@@ -873,7 +939,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
873939
struct hid_sensor_custom *sensor_inst;
874940
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
875941
int ret;
876-
int index;
942+
const struct hid_sensor_custom_match *match;
877943

878944
sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
879945
GFP_KERNEL);
@@ -888,10 +954,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
888954
mutex_init(&sensor_inst->mutex);
889955
platform_set_drvdata(pdev, sensor_inst);
890956

891-
index = get_known_custom_sensor_index(hsdev);
892-
if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) {
957+
ret = hid_sensor_custom_get_known(hsdev, &match);
958+
if (!ret) {
893959
sensor_inst->custom_pdev =
894-
hid_sensor_register_platform_device(pdev, hsdev, index);
960+
hid_sensor_register_platform_device(pdev, hsdev, match);
895961

896962
ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev);
897963
if (ret) {

include/linux/hid-sensor-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@
132132
#define HID_USAGE_SENSOR_PROP_FRIENDLY_NAME 0x200301
133133
#define HID_USAGE_SENSOR_PROP_SERIAL_NUM 0x200307
134134
#define HID_USAGE_SENSOR_PROP_MANUFACTURER 0x200305
135+
#define HID_USAGE_SENSOR_PROP_MODEL 0x200306
135136
#define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E
136137
#define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F
137138
#define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310

0 commit comments

Comments
 (0)