@@ -337,7 +337,8 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
337
337
}
338
338
339
339
if (pcc -> num_sifr < hkey -> package .count ) {
340
- pr_err ("SQTY reports bad SINF length\n" );
340
+ pr_err ("SQTY reports bad SINF length SQTY: %lu SINF-pkg-count: %u\n" ,
341
+ pcc -> num_sifr , hkey -> package .count );
341
342
status = AE_ERROR ;
342
343
goto end ;
343
344
}
@@ -773,6 +774,24 @@ static DEVICE_ATTR_RW(dc_brightness);
773
774
static DEVICE_ATTR_RW (current_brightness );
774
775
static DEVICE_ATTR_RW (cdpower );
775
776
777
+ static umode_t pcc_sysfs_is_visible (struct kobject * kobj , struct attribute * attr , int idx )
778
+ {
779
+ struct device * dev = kobj_to_dev (kobj );
780
+ struct acpi_device * acpi = to_acpi_device (dev );
781
+ struct pcc_acpi * pcc = acpi_driver_data (acpi );
782
+
783
+ if (attr == & dev_attr_mute .attr )
784
+ return (pcc -> num_sifr > SINF_MUTE ) ? attr -> mode : 0 ;
785
+
786
+ if (attr == & dev_attr_eco_mode .attr )
787
+ return (pcc -> num_sifr > SINF_ECO_MODE ) ? attr -> mode : 0 ;
788
+
789
+ if (attr == & dev_attr_current_brightness .attr )
790
+ return (pcc -> num_sifr > SINF_CUR_BRIGHT ) ? attr -> mode : 0 ;
791
+
792
+ return attr -> mode ;
793
+ }
794
+
776
795
static struct attribute * pcc_sysfs_entries [] = {
777
796
& dev_attr_numbatt .attr ,
778
797
& dev_attr_lcdtype .attr ,
@@ -787,8 +806,9 @@ static struct attribute *pcc_sysfs_entries[] = {
787
806
};
788
807
789
808
static const struct attribute_group pcc_attr_group = {
790
- .name = NULL , /* put in device directory */
791
- .attrs = pcc_sysfs_entries ,
809
+ .name = NULL , /* put in device directory */
810
+ .attrs = pcc_sysfs_entries ,
811
+ .is_visible = pcc_sysfs_is_visible ,
792
812
};
793
813
794
814
@@ -941,12 +961,15 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
941
961
if (!pcc )
942
962
return - EINVAL ;
943
963
944
- acpi_pcc_write_sset (pcc , SINF_MUTE , pcc -> mute );
945
- acpi_pcc_write_sset (pcc , SINF_ECO_MODE , pcc -> eco_mode );
964
+ if (pcc -> num_sifr > SINF_MUTE )
965
+ acpi_pcc_write_sset (pcc , SINF_MUTE , pcc -> mute );
966
+ if (pcc -> num_sifr > SINF_ECO_MODE )
967
+ acpi_pcc_write_sset (pcc , SINF_ECO_MODE , pcc -> eco_mode );
946
968
acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , pcc -> sticky_key );
947
969
acpi_pcc_write_sset (pcc , SINF_AC_CUR_BRIGHT , pcc -> ac_brightness );
948
970
acpi_pcc_write_sset (pcc , SINF_DC_CUR_BRIGHT , pcc -> dc_brightness );
949
- acpi_pcc_write_sset (pcc , SINF_CUR_BRIGHT , pcc -> current_brightness );
971
+ if (pcc -> num_sifr > SINF_CUR_BRIGHT )
972
+ acpi_pcc_write_sset (pcc , SINF_CUR_BRIGHT , pcc -> current_brightness );
950
973
951
974
return 0 ;
952
975
}
@@ -963,11 +986,21 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
963
986
964
987
num_sifr = acpi_pcc_get_sqty (device );
965
988
966
- if (num_sifr < 0 || num_sifr > 255 ) {
967
- pr_err ("num_sifr out of range" );
989
+ /*
990
+ * pcc->sinf is expected to at least have the AC+DC brightness entries.
991
+ * Accesses to higher SINF entries are checked against num_sifr.
992
+ */
993
+ if (num_sifr <= SINF_DC_CUR_BRIGHT || num_sifr > 255 ) {
994
+ pr_err ("num_sifr %d out of range %d - 255\n" , num_sifr , SINF_DC_CUR_BRIGHT + 1 );
968
995
return - ENODEV ;
969
996
}
970
997
998
+ /*
999
+ * Some DSDT-s have an off-by-one bug where the SINF package count is
1000
+ * one higher than the SQTY reported value, allocate 1 entry extra.
1001
+ */
1002
+ num_sifr ++ ;
1003
+
971
1004
pcc = kzalloc (sizeof (struct pcc_acpi ), GFP_KERNEL );
972
1005
if (!pcc ) {
973
1006
pr_err ("Couldn't allocate mem for pcc" );
@@ -1020,11 +1053,14 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
1020
1053
acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , 0 );
1021
1054
pcc -> sticky_key = 0 ;
1022
1055
1023
- pcc -> eco_mode = pcc -> sinf [SINF_ECO_MODE ];
1024
- pcc -> mute = pcc -> sinf [SINF_MUTE ];
1025
1056
pcc -> ac_brightness = pcc -> sinf [SINF_AC_CUR_BRIGHT ];
1026
1057
pcc -> dc_brightness = pcc -> sinf [SINF_DC_CUR_BRIGHT ];
1027
- pcc -> current_brightness = pcc -> sinf [SINF_CUR_BRIGHT ];
1058
+ if (pcc -> num_sifr > SINF_MUTE )
1059
+ pcc -> mute = pcc -> sinf [SINF_MUTE ];
1060
+ if (pcc -> num_sifr > SINF_ECO_MODE )
1061
+ pcc -> eco_mode = pcc -> sinf [SINF_ECO_MODE ];
1062
+ if (pcc -> num_sifr > SINF_CUR_BRIGHT )
1063
+ pcc -> current_brightness = pcc -> sinf [SINF_CUR_BRIGHT ];
1028
1064
1029
1065
/* add sysfs attributes */
1030
1066
result = sysfs_create_group (& device -> dev .kobj , & pcc_attr_group );
0 commit comments