HID: fix unit exponent parsing
[cascardo/linux.git] / drivers / hid / hid-input.c
index d917c0d..007a943 100644 (file)
@@ -192,7 +192,6 @@ static int hidinput_setkeycode(struct input_dev *dev,
        return -EINVAL;
 }
 
-
 /**
  * hidinput_calc_abs_res - calculate an absolute axis resolution
  * @field: the HID report field to calculate resolution for
@@ -208,7 +207,7 @@ static int hidinput_setkeycode(struct input_dev *dev,
  * Only exponent 1 length units are processed. Centimeters and inches are
  * converted to millimeters. Degrees are converted to radians.
  */
-static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
+__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
 {
        __s32 unit_exponent = field->unit_exponent;
        __s32 logical_extents = field->logical_maximum -
@@ -229,17 +228,29 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
        case ABS_X:
        case ABS_Y:
        case ABS_Z:
-               if (field->unit == 0x11) {              /* If centimeters */
+       case ABS_MT_POSITION_X:
+       case ABS_MT_POSITION_Y:
+       case ABS_MT_TOOL_X:
+       case ABS_MT_TOOL_Y:
+       case ABS_MT_TOUCH_MAJOR:
+       case ABS_MT_TOUCH_MINOR:
+               if (field->unit & 0xffffff00)           /* Not a length */
+                       return 0;
+               unit_exponent += hid_snto32(field->unit >> 4, 4) - 1;
+               switch (field->unit & 0xf) {
+               case 0x1:                               /* If centimeters */
                        /* Convert to millimeters */
                        unit_exponent += 1;
-               } else if (field->unit == 0x13) {       /* If inches */
+                       break;
+               case 0x3:                               /* If inches */
                        /* Convert to millimeters */
                        prev = physical_extents;
                        physical_extents *= 254;
                        if (physical_extents < prev)
                                return 0;
                        unit_exponent -= 1;
-               } else {
+                       break;
+               default:
                        return 0;
                }
                break;
@@ -281,8 +292,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
        }
 
        /* Calculate resolution */
-       return logical_extents / physical_extents;
+       return DIV_ROUND_CLOSEST(logical_extents, physical_extents);
 }
+EXPORT_SYMBOL_GPL(hidinput_calc_abs_res);
 
 #ifdef CONFIG_HID_BATTERY_STRENGTH
 static enum power_supply_property hidinput_battery_props[] = {