w1: w1_therm: Fix conversion result for negative temperatures
authorIvan Zaentsev <ivan.zaentsev@wirenboard.ru>
Thu, 21 Jan 2021 09:30:21 +0000 (12:30 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Jan 2021 13:59:16 +0000 (14:59 +0100)
DS18B20 device driver returns an incorrect value for negative temperatures
due to a missing sign-extension in w1_DS18B20_convert_temp().

Fix by using s16 temperature value when converting to int.

Fixes: 9ace0b4dab1c (w1: w1_therm: Add support for GXCAS GX20MH01 device.)
Cc: stable <stable@vger.kernel.org>
Reported-by: Paweł Marciniak <sunwire@gmail.com>
Signed-off-by: Ivan Zaentsev <ivan.zaentsev@wirenboard.ru>
Link: https://lore.kernel.org/r/20210121093021.224764-1-ivan.zaentsev@wirenboard.ru
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/w1/slaves/w1_therm.c

index 3712b1e..976eea2 100644 (file)
@@ -667,28 +667,24 @@ static inline int w1_DS18B20_get_resolution(struct w1_slave *sl)
  */
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
-       int t;
-       u32 bv;
+       u16 bv;
+       s16 t;
+
+       /* Signed 16-bit value to unsigned, cpu order */
+       bv = le16_to_cpup((__le16 *)rom);
 
        /* Config register bit R2 = 1 - GX20MH01 in 13 or 14 bit resolution mode */
        if (rom[4] & 0x80) {
-               /* Signed 16-bit value to unsigned, cpu order */
-               bv = le16_to_cpup((__le16 *)rom);
-
                /* Insert two temperature bits from config register */
                /* Avoid arithmetic shift of signed value */
                bv = (bv << 2) | (rom[4] & 3);
-
-               t = (int) sign_extend32(bv, 17); /* Degrees, lowest bit is 2^-6 */
-               return (t*1000)/64;  /* Millidegrees */
+               t = (s16) bv;   /* Degrees, lowest bit is 2^-6 */
+               return (int)t * 1000 / 64;      /* Sign-extend to int; millidegrees */
        }
-
-       t = (int)le16_to_cpup((__le16 *)rom);
-       return t*1000/16;
+       t = (s16)bv;    /* Degrees, lowest bit is 2^-4 */
+       return (int)t * 1000 / 16;      /* Sign-extend to int; millidegrees */
 }
 
-
-
 /**
  * w1_DS18S20_convert_temp() - temperature computation for DS18S20
  * @rom: data read from device RAM (8 data bytes + 1 CRC byte)