@@ -337,7 +337,8 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
337337 }
338338
339339 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 );
341342 status = AE_ERROR ;
342343 goto end ;
343344 }
@@ -773,6 +774,24 @@ static DEVICE_ATTR_RW(dc_brightness);
773774static DEVICE_ATTR_RW (current_brightness );
774775static DEVICE_ATTR_RW (cdpower );
775776
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+
776795static struct attribute * pcc_sysfs_entries [] = {
777796 & dev_attr_numbatt .attr ,
778797 & dev_attr_lcdtype .attr ,
@@ -787,8 +806,9 @@ static struct attribute *pcc_sysfs_entries[] = {
787806};
788807
789808static 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 ,
792812};
793813
794814
@@ -941,12 +961,15 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
941961 if (!pcc )
942962 return - EINVAL ;
943963
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 );
946968 acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , pcc -> sticky_key );
947969 acpi_pcc_write_sset (pcc , SINF_AC_CUR_BRIGHT , pcc -> ac_brightness );
948970 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 );
950973
951974 return 0 ;
952975}
@@ -963,11 +986,21 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
963986
964987 num_sifr = acpi_pcc_get_sqty (device );
965988
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 );
968995 return - ENODEV ;
969996 }
970997
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+
9711004 pcc = kzalloc (sizeof (struct pcc_acpi ), GFP_KERNEL );
9721005 if (!pcc ) {
9731006 pr_err ("Couldn't allocate mem for pcc" );
@@ -1020,11 +1053,14 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
10201053 acpi_pcc_write_sset (pcc , SINF_STICKY_KEY , 0 );
10211054 pcc -> sticky_key = 0 ;
10221055
1023- pcc -> eco_mode = pcc -> sinf [SINF_ECO_MODE ];
1024- pcc -> mute = pcc -> sinf [SINF_MUTE ];
10251056 pcc -> ac_brightness = pcc -> sinf [SINF_AC_CUR_BRIGHT ];
10261057 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 ];
10281064
10291065 /* add sysfs attributes */
10301066 result = sysfs_create_group (& device -> dev .kobj , & pcc_attr_group );
0 commit comments