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>
@@ -750,114 +751,209 @@ static void hid_sensor_custom_dev_if_remove(struct hid_sensor_custom
750
751
751
752
}
752
753
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
+ };
755
766
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
+ };
759
810
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 ++ ;
764
819
}
765
820
766
- return - ENODEV ;
821
+ return ( count == -1 ) || * prop == ( u16 ) * match ;
767
822
}
768
823
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 )
770
827
{
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 };
774
829
int ret ;
775
- static u16 w_buf [HID_CUSTOM_MAX_FEATURE_BYTES ];
776
- static char buf [HID_CUSTOM_MAX_FEATURE_BYTES ];
777
- int i ;
778
830
779
- memset (w_buf , 0 , sizeof (w_buf ));
780
- memset (buf , 0 , sizeof (buf ));
831
+ memset (prop , 0 , prop_size );
781
832
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 );
786
836
if (ret < 0 )
787
837
return ret ;
788
838
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 ;
798
845
}
799
846
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
+ }
803
849
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 } };
807
856
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;
810
861
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 );
815
888
if (ret < 0 )
816
889
return ret ;
817
890
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
+ */
826
895
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 ) ;
830
899
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 );
837
903
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 ;
840
936
}
841
937
842
938
static struct platform_device *
843
939
hid_sensor_register_platform_device (struct platform_device * pdev ,
844
940
struct hid_sensor_hub_device * hsdev ,
845
- int index )
941
+ const struct hid_sensor_custom_match * match )
846
942
{
847
- char real_usage [HID_SENSOR_USAGE_LENGTH ] = { 0 } ;
943
+ char real_usage [HID_SENSOR_USAGE_LENGTH ];
848
944
struct platform_device * custom_pdev ;
849
945
const char * dev_name ;
850
946
char * c ;
851
947
852
- /* copy real usage id */
853
- memcpy (real_usage , known_sensor_luid [index ], 4 );
948
+ memcpy (real_usage , match -> luid , 4 );
854
949
855
950
/* usage id are all lowcase */
856
951
for (c = real_usage ; * c != '\0' ; c ++ )
857
952
* c = tolower (* c );
858
953
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 );
861
957
if (!dev_name )
862
958
return ERR_PTR (- ENOMEM );
863
959
@@ -873,7 +969,7 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
873
969
struct hid_sensor_custom * sensor_inst ;
874
970
struct hid_sensor_hub_device * hsdev = pdev -> dev .platform_data ;
875
971
int ret ;
876
- int index ;
972
+ const struct hid_sensor_custom_match * match ;
877
973
878
974
sensor_inst = devm_kzalloc (& pdev -> dev , sizeof (* sensor_inst ),
879
975
GFP_KERNEL );
@@ -888,10 +984,10 @@ static int hid_sensor_custom_probe(struct platform_device *pdev)
888
984
mutex_init (& sensor_inst -> mutex );
889
985
platform_set_drvdata (pdev , sensor_inst );
890
986
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 ) {
893
989
sensor_inst -> custom_pdev =
894
- hid_sensor_register_platform_device (pdev , hsdev , index );
990
+ hid_sensor_register_platform_device (pdev , hsdev , match );
895
991
896
992
ret = PTR_ERR_OR_ZERO (sensor_inst -> custom_pdev );
897
993
if (ret ) {
0 commit comments