Skip to content

Commit 2818ccb

Browse files
committed
Merge branch 'for-6.3/hid-sensor' into for-linus
Allow more custom IIO sensors through HID (Philipp Jungkamp)
2 parents 1f3a957 + f1f7365 commit 2818ccb

File tree

4 files changed

+207
-100
lines changed

4 files changed

+207
-100
lines changed

drivers/hid/hid-sensor-custom.c

Lines changed: 169 additions & 73 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,209 @@ 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+
};
775+
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+
* Lenovo Intelligent Sensing Solution (LISS)
787+
*/
788+
{ /* ambient light */
789+
.tag = "LISS",
790+
.luid = "0041010200000082",
791+
.model = "STK3X3X Sensor",
792+
.manufacturer = "Vendor 258",
793+
.check_dmi = true,
794+
.dmi.matches = {
795+
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
796+
}
797+
},
798+
{ /* human presence */
799+
.tag = "LISS",
800+
.luid = "0226000171AC0081",
801+
.model = "VL53L1_HOD Sensor",
802+
.manufacturer = "ST_MICRO",
803+
.check_dmi = true,
804+
.dmi.matches = {
805+
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
806+
}
807+
},
808+
{}
809+
};
759810

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;
811+
static bool hid_sensor_custom_prop_match_str(const u16 *prop, const char *match,
812+
size_t count)
813+
{
814+
while (count-- && *prop && *match) {
815+
if (*prop != (u16) *match)
816+
return false;
817+
prop++;
818+
match++;
764819
}
765820

766-
return -ENODEV;
821+
return (count == -1) || *prop == (u16)*match;
767822
}
768823

769-
static int get_known_custom_sensor_index(struct hid_sensor_hub_device *hsdev)
824+
static int hid_sensor_custom_get_prop(struct hid_sensor_hub_device *hsdev,
825+
u32 prop_usage_id, size_t prop_size,
826+
u16 *prop)
770827
{
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;
828+
struct hid_sensor_hub_attribute_info prop_attr = { 0 };
774829
int ret;
775-
static u16 w_buf[HID_CUSTOM_MAX_FEATURE_BYTES];
776-
static char buf[HID_CUSTOM_MAX_FEATURE_BYTES];
777-
int i;
778830

779-
memset(w_buf, 0, sizeof(w_buf));
780-
memset(buf, 0, sizeof(buf));
831+
memset(prop, 0, prop_size);
781832

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);
833+
ret = sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
834+
hsdev->usage, prop_usage_id,
835+
&prop_attr);
786836
if (ret < 0)
787837
return ret;
788838

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;
839+
ret = sensor_hub_get_feature(hsdev, prop_attr.report_id,
840+
prop_attr.index, prop_size, prop);
841+
if (ret < 0) {
842+
hid_err(hsdev->hdev, "Failed to get sensor property %08x %d\n",
843+
prop_usage_id, ret);
844+
return ret;
798845
}
799846

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];
847+
return 0;
848+
}
803849

804-
/* ensure it's ISH sensor */
805-
if (strncmp(buf, "INTEL", strlen("INTEL")))
806-
return -ENODEV;
850+
static bool
851+
hid_sensor_custom_do_match(struct hid_sensor_hub_device *hsdev,
852+
const struct hid_sensor_custom_match *match,
853+
const struct hid_sensor_custom_properties *prop)
854+
{
855+
struct dmi_system_id dmi[] = { match->dmi, { 0 } };
807856

808-
memset(w_buf, 0, sizeof(w_buf));
809-
memset(buf, 0, sizeof(buf));
857+
if (!hid_sensor_custom_prop_match_str(prop->serial_num, "LUID:", 5) ||
858+
!hid_sensor_custom_prop_match_str(prop->serial_num + 5, match->luid,
859+
HID_CUSTOM_MAX_FEATURE_BYTES - 5))
860+
return false;
810861

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);
862+
if (match->model &&
863+
!hid_sensor_custom_prop_match_str(prop->model, match->model,
864+
HID_CUSTOM_MAX_FEATURE_BYTES))
865+
return false;
866+
867+
if (match->manufacturer &&
868+
!hid_sensor_custom_prop_match_str(prop->manufacturer, match->manufacturer,
869+
HID_CUSTOM_MAX_FEATURE_BYTES))
870+
return false;
871+
872+
if (match->check_dmi && !dmi_check_system(dmi))
873+
return false;
874+
875+
return true;
876+
}
877+
878+
static int
879+
hid_sensor_custom_properties_get(struct hid_sensor_hub_device *hsdev,
880+
struct hid_sensor_custom_properties *prop)
881+
{
882+
int ret;
883+
884+
ret = hid_sensor_custom_get_prop(hsdev,
885+
HID_USAGE_SENSOR_PROP_SERIAL_NUM,
886+
HID_CUSTOM_MAX_FEATURE_BYTES,
887+
prop->serial_num);
815888
if (ret < 0)
816889
return ret;
817890

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-
}
891+
/*
892+
* Ignore errors on the following model and manufacturer properties.
893+
* Because these are optional, it is not an error if they are missing.
894+
*/
826895

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];
896+
hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MODEL,
897+
HID_CUSTOM_MAX_FEATURE_BYTES,
898+
prop->model);
830899

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;
836-
}
900+
hid_sensor_custom_get_prop(hsdev, HID_USAGE_SENSOR_PROP_MANUFACTURER,
901+
HID_CUSTOM_MAX_FEATURE_BYTES,
902+
prop->manufacturer);
837903

838-
/* get table index with luid (not matching 'LUID: ' in luid) */
839-
return get_luid_table_index(&buf[5]);
904+
return 0;
905+
}
906+
907+
static int
908+
hid_sensor_custom_get_known(struct hid_sensor_hub_device *hsdev,
909+
const struct hid_sensor_custom_match **known)
910+
{
911+
int ret;
912+
const struct hid_sensor_custom_match *match =
913+
hid_sensor_custom_known_table;
914+
struct hid_sensor_custom_properties *prop;
915+
916+
prop = kmalloc(sizeof(struct hid_sensor_custom_properties), GFP_KERNEL);
917+
if (!prop)
918+
return -ENOMEM;
919+
920+
ret = hid_sensor_custom_properties_get(hsdev, prop);
921+
if (ret < 0)
922+
goto out;
923+
924+
while (match->tag) {
925+
if (hid_sensor_custom_do_match(hsdev, match, prop)) {
926+
*known = match;
927+
ret = 0;
928+
goto out;
929+
}
930+
match++;
931+
}
932+
ret = -ENODATA;
933+
out:
934+
kfree(prop);
935+
return ret;
840936
}
841937

842938
static struct platform_device *
843939
hid_sensor_register_platform_device(struct platform_device *pdev,
844940
struct hid_sensor_hub_device *hsdev,
845-
int index)
941+
const struct hid_sensor_custom_match *match)
846942
{
847-
char real_usage[HID_SENSOR_USAGE_LENGTH] = { 0 };
943+
char real_usage[HID_SENSOR_USAGE_LENGTH];
848944
struct platform_device *custom_pdev;
849945
const char *dev_name;
850946
char *c;
851947

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

855950
/* usage id are all lowcase */
856951
for (c = real_usage; *c != '\0'; c++)
857952
*c = tolower(*c);
858953

859-
/* HID-SENSOR-INT-REAL_USAGE_ID */
860-
dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-INT-%s", real_usage);
954+
/* HID-SENSOR-TAG-REAL_USAGE_ID */
955+
dev_name = kasprintf(GFP_KERNEL, "HID-SENSOR-%s-%s",
956+
match->tag, real_usage);
861957
if (!dev_name)
862958
return ERR_PTR(-ENOMEM);
863959

@@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
873969
struct hid_sensor_custom *sensor_inst;
874970
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
875971
int ret;
876-
int index;
972+
const struct hid_sensor_custom_match *match;
877973

878974
sensor_inst = devm_kzalloc(&pdev->dev, sizeof(*sensor_inst),
879975
GFP_KERNEL);
@@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
888984
mutex_init(&sensor_inst->mutex);
889985
platform_set_drvdata(pdev, sensor_inst);
890986

891-
index = get_known_custom_sensor_index(hsdev);
892-
if (index >= 0 && index < ARRAY_SIZE(known_sensor_luid)) {
987+
ret = hid_sensor_custom_get_known(hsdev, &match);
988+
if (!ret) {
893989
sensor_inst->custom_pdev =
894-
hid_sensor_register_platform_device(pdev, hsdev, index);
990+
hid_sensor_register_platform_device(pdev, hsdev, match);
895991

896992
ret = PTR_ERR_OR_ZERO(sensor_inst->custom_pdev);
897993
if (ret) {

drivers/iio/light/hid-sensor-als.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static int als_read_raw(struct iio_dev *indio_dev,
8686
long mask)
8787
{
8888
struct als_state *als_state = iio_priv(indio_dev);
89+
struct hid_sensor_hub_device *hsdev = als_state->common_attributes.hsdev;
8990
int report_id = -1;
9091
u32 address;
9192
int ret_type;
@@ -110,11 +111,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
110111
hid_sensor_power_state(&als_state->common_attributes,
111112
true);
112113
*val = sensor_hub_input_attr_get_raw_value(
113-
als_state->common_attributes.hsdev,
114-
HID_USAGE_SENSOR_ALS, address,
115-
report_id,
116-
SENSOR_HUB_SYNC,
117-
min < 0);
114+
hsdev, hsdev->usage, address, report_id,
115+
SENSOR_HUB_SYNC, min < 0);
118116
hid_sensor_power_state(&als_state->common_attributes,
119117
false);
120118
} else {
@@ -259,9 +257,7 @@ static int als_parse_report(struct platform_device *pdev,
259257
dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index,
260258
st->als_illum.report_id);
261259

262-
st->scale_precision = hid_sensor_format_scale(
263-
HID_USAGE_SENSOR_ALS,
264-
&st->als_illum,
260+
st->scale_precision = hid_sensor_format_scale(usage_id, &st->als_illum,
265261
&st->scale_pre_decml, &st->scale_post_decml);
266262

267263
return ret;
@@ -285,7 +281,8 @@ static int hid_als_probe(struct platform_device *pdev)
285281
als_state->common_attributes.hsdev = hsdev;
286282
als_state->common_attributes.pdev = pdev;
287283

288-
ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS,
284+
ret = hid_sensor_parse_common_attributes(hsdev,
285+
hsdev->usage,
289286
&als_state->common_attributes,
290287
als_sensitivity_addresses,
291288
ARRAY_SIZE(als_sensitivity_addresses));
@@ -303,7 +300,8 @@ static int hid_als_probe(struct platform_device *pdev)
303300

304301
ret = als_parse_report(pdev, hsdev,
305302
(struct iio_chan_spec *)indio_dev->channels,
306-
HID_USAGE_SENSOR_ALS, als_state);
303+
hsdev->usage,
304+
als_state);
307305
if (ret) {
308306
dev_err(&pdev->dev, "failed to setup attributes\n");
309307
return ret;
@@ -333,8 +331,7 @@ static int hid_als_probe(struct platform_device *pdev)
333331
als_state->callbacks.send_event = als_proc_event;
334332
als_state->callbacks.capture_sample = als_capture_sample;
335333
als_state->callbacks.pdev = pdev;
336-
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS,
337-
&als_state->callbacks);
334+
ret = sensor_hub_register_callback(hsdev, hsdev->usage, &als_state->callbacks);
338335
if (ret < 0) {
339336
dev_err(&pdev->dev, "callback reg failed\n");
340337
goto error_iio_unreg;
@@ -356,7 +353,7 @@ static int hid_als_remove(struct platform_device *pdev)
356353
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
357354
struct als_state *als_state = iio_priv(indio_dev);
358355

359-
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS);
356+
sensor_hub_remove_callback(hsdev, hsdev->usage);
360357
iio_device_unregister(indio_dev);
361358
hid_sensor_remove_trigger(indio_dev, &als_state->common_attributes);
362359

@@ -368,6 +365,10 @@ static const struct platform_device_id hid_als_ids[] = {
368365
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
369366
.name = "HID-SENSOR-200041",
370367
},
368+
{
369+
/* Format: HID-SENSOR-custom_sensor_tag-usage_id_in_hex_lowercase */
370+
.name = "HID-SENSOR-LISS-0041",
371+
},
371372
{ /* sentinel */ }
372373
};
373374
MODULE_DEVICE_TABLE(platform, hid_als_ids);

0 commit comments

Comments
 (0)