8787#define FAN_ID_FMT "F%dID" /* r-o char[16] */
8888
8989#define TEMP_SENSOR_TYPE "sp78"
90+ #define FLOAT_TYPE "flt "
9091
9192/* List of keys used to read/write fan speeds */
9293static const char * const fan_speed_fmt [] = {
@@ -96,6 +97,7 @@ static const char *const fan_speed_fmt[] = {
9697 "F%dSf" , /* safe speed - not all models */
9798 "F%dTg" , /* target speed (manual: rw) */
9899};
100+ #define FAN_MANUAL_FMT "F%dMd"
99101
100102#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
101103#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
@@ -734,6 +736,42 @@ static int applesmc_read_s16(struct applesmc_device *smc,
734736 return 0 ;
735737}
736738
739+ /**
740+ * applesmc_float_to_u32 - Retrieve the integral part of a float.
741+ * This is needed because Apple made fans use float values in the T2.
742+ * The fractional point is not significantly useful though, and the integral
743+ * part can be easily extracted.
744+ */
745+ static inline u32 applesmc_float_to_u32 (u32 d )
746+ {
747+ u8 sign = (u8 ) ((d >> 31 ) & 1 );
748+ s32 exp = (s32 ) ((d >> 23 ) & 0xff ) - 0x7f ;
749+ u32 fr = d & ((1u << 23 ) - 1 );
750+
751+ if (sign || exp < 0 )
752+ return 0 ;
753+
754+ return (u32 ) ((1u << exp ) + (fr >> (23 - exp )));
755+ }
756+
757+ /**
758+ * applesmc_u32_to_float - Convert an u32 into a float.
759+ * See applesmc_float_to_u32 for a rationale.
760+ */
761+ static inline u32 applesmc_u32_to_float (u32 d )
762+ {
763+ u32 dc = d , bc = 0 , exp ;
764+
765+ if (!d )
766+ return 0 ;
767+
768+ while (dc >>= 1 )
769+ ++ bc ;
770+ exp = 0x7f + bc ;
771+
772+ return (u32 ) ((exp << 23 ) |
773+ ((d << (23 - (exp - 0x7f ))) & ((1u << 23 ) - 1 )));
774+ }
737775/*
738776 * applesmc_device_init - initialize the accelerometer. Can sleep.
739777 */
@@ -1241,6 +1279,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
12411279 struct device_attribute * attr , char * sysfsbuf )
12421280{
12431281 struct applesmc_device * smc = dev_get_drvdata (dev );
1282+ const struct applesmc_entry * entry ;
12441283 int ret ;
12451284 unsigned int speed = 0 ;
12461285 char newkey [5 ];
@@ -1249,11 +1288,21 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
12491288 scnprintf (newkey , sizeof (newkey ), fan_speed_fmt [to_option (attr )],
12501289 to_index (attr ));
12511290
1252- ret = applesmc_read_key (smc , newkey , buffer , 2 );
1291+ entry = applesmc_get_entry_by_key (smc , newkey );
1292+ if (IS_ERR (entry ))
1293+ return PTR_ERR (entry );
1294+
1295+ if (!strcmp (entry -> type , FLOAT_TYPE )) {
1296+ ret = applesmc_read_entry (smc , entry , (u8 * ) & speed , 4 );
1297+ speed = applesmc_float_to_u32 (speed );
1298+ } else {
1299+ ret = applesmc_read_entry (smc , entry , buffer , 2 );
1300+ speed = ((buffer [0 ] << 8 | buffer [1 ]) >> 2 );
1301+ }
1302+
12531303 if (ret )
12541304 return ret ;
12551305
1256- speed = ((buffer [0 ] << 8 | buffer [1 ]) >> 2 );
12571306 return sysfs_emit (sysfsbuf , "%u\n" , speed );
12581307}
12591308
@@ -1262,6 +1311,7 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
12621311 const char * sysfsbuf , size_t count )
12631312{
12641313 struct applesmc_device * smc = dev_get_drvdata (dev );
1314+ const struct applesmc_entry * entry ;
12651315 int ret ;
12661316 unsigned long speed ;
12671317 char newkey [5 ];
@@ -1273,9 +1323,18 @@ static ssize_t applesmc_store_fan_speed(struct device *dev,
12731323 scnprintf (newkey , sizeof (newkey ), fan_speed_fmt [to_option (attr )],
12741324 to_index (attr ));
12751325
1276- buffer [0 ] = (speed >> 6 ) & 0xff ;
1277- buffer [1 ] = (speed << 2 ) & 0xff ;
1278- ret = applesmc_write_key (smc , newkey , buffer , 2 );
1326+ entry = applesmc_get_entry_by_key (smc , newkey );
1327+ if (IS_ERR (entry ))
1328+ return PTR_ERR (entry );
1329+
1330+ if (!strcmp (entry -> type , FLOAT_TYPE )) {
1331+ speed = applesmc_u32_to_float (speed );
1332+ ret = applesmc_write_entry (smc , entry , (u8 * ) & speed , 4 );
1333+ } else {
1334+ buffer [0 ] = (speed >> 6 ) & 0xff ;
1335+ buffer [1 ] = (speed << 2 ) & 0xff ;
1336+ ret = applesmc_write_key (smc , newkey , buffer , 2 );
1337+ }
12791338
12801339 if (ret )
12811340 return ret ;
@@ -1290,12 +1349,26 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
12901349 int ret ;
12911350 u16 manual = 0 ;
12921351 u8 buffer [2 ];
1352+ char newkey [5 ];
1353+ bool has_newkey = false;
1354+
1355+ scnprintf (newkey , sizeof (newkey ), FAN_MANUAL_FMT , to_index (attr ));
1356+
1357+ ret = applesmc_has_key (smc , newkey , & has_newkey );
1358+ if (ret )
1359+ return ret ;
1360+
1361+ if (has_newkey ) {
1362+ ret = applesmc_read_key (smc , newkey , buffer , 1 );
1363+ manual = buffer [0 ];
1364+ } else {
1365+ ret = applesmc_read_key (smc , FANS_MANUAL , buffer , 2 );
1366+ manual = ((buffer [0 ] << 8 | buffer [1 ]) >> to_index (attr )) & 0x01 ;
1367+ }
12931368
1294- ret = applesmc_read_key (smc , FANS_MANUAL , buffer , 2 );
12951369 if (ret )
12961370 return ret ;
12971371
1298- manual = ((buffer [0 ] << 8 | buffer [1 ]) >> to_index (attr )) & 0x01 ;
12991372 return sysfs_emit (sysfsbuf , "%d\n" , manual );
13001373}
13011374
@@ -1306,27 +1379,39 @@ static ssize_t applesmc_store_fan_manual(struct device *dev,
13061379 struct applesmc_device * smc = dev_get_drvdata (dev );
13071380 int ret ;
13081381 u8 buffer [2 ];
1382+ char newkey [5 ];
1383+ bool has_newkey = false;
13091384 unsigned long input ;
13101385 u16 val ;
13111386
13121387 if (kstrtoul (sysfsbuf , 10 , & input ) < 0 )
13131388 return - EINVAL ;
13141389
1315- ret = applesmc_read_key (smc , FANS_MANUAL , buffer , 2 );
1390+ scnprintf (newkey , sizeof (newkey ), FAN_MANUAL_FMT , to_index (attr ));
1391+
1392+ ret = applesmc_has_key (smc , newkey , & has_newkey );
13161393 if (ret )
1317- goto out ;
1394+ return ret ;
13181395
1319- val = (buffer [0 ] << 8 | buffer [1 ]);
1396+ if (has_newkey ) {
1397+ buffer [0 ] = input & 1 ;
1398+ ret = applesmc_write_key (smc , newkey , buffer , 1 );
1399+ } else {
1400+ ret = applesmc_read_key (smc , FANS_MANUAL , buffer , 2 );
1401+ val = (buffer [0 ] << 8 | buffer [1 ]);
1402+ if (ret )
1403+ goto out ;
13201404
1321- if (input )
1322- val = val | (0x01 << to_index (attr ));
1323- else
1324- val = val & ~(0x01 << to_index (attr ));
1405+ if (input )
1406+ val = val | (0x01 << to_index (attr ));
1407+ else
1408+ val = val & ~(0x01 << to_index (attr ));
13251409
1326- buffer [0 ] = (val >> 8 ) & 0xFF ;
1327- buffer [1 ] = val & 0xFF ;
1410+ buffer [0 ] = (val >> 8 ) & 0xFF ;
1411+ buffer [1 ] = val & 0xFF ;
13281412
1329- ret = applesmc_write_key (smc , FANS_MANUAL , buffer , 2 );
1413+ ret = applesmc_write_key (smc , FANS_MANUAL , buffer , 2 );
1414+ }
13301415
13311416out :
13321417 if (ret )
0 commit comments