summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/tablet/wacom_sys.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 0d3219f2974..b44bba2a60c 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -172,6 +172,76 @@ static void wacom_close(struct input_dev *dev)
}
/*
+ * Calculate the resolution of the X or Y axis, given appropriate HID data.
+ * This function is little more than hidinput_calc_abs_res stripped down.
+ */
+static int wacom_calc_hid_res(int logical_extents, int physical_extents,
+ unsigned char unit, unsigned char exponent)
+{
+ int prev, unit_exponent;
+
+ /* Check if the extents are sane */
+ if (logical_extents <= 0 || physical_extents <= 0)
+ return 0;
+
+ /* Get signed value of nybble-sized twos-compliment exponent */
+ unit_exponent = exponent;
+ if (unit_exponent > 7)
+ unit_exponent -= 16;
+
+ /* Convert physical_extents to millimeters */
+ if (unit == 0x11) { /* If centimeters */
+ unit_exponent += 1;
+ } else if (unit == 0x13) { /* If inches */
+ prev = physical_extents;
+ physical_extents *= 254;
+ if (physical_extents < prev)
+ return 0;
+ unit_exponent -= 1;
+ } else {
+ return 0;
+ }
+
+ /* Apply negative unit exponent */
+ for (; unit_exponent < 0; unit_exponent++) {
+ prev = logical_extents;
+ logical_extents *= 10;
+ if (logical_extents < prev)
+ return 0;
+ }
+ /* Apply positive unit exponent */
+ for (; unit_exponent > 0; unit_exponent--) {
+ prev = physical_extents;
+ physical_extents *= 10;
+ if (physical_extents < prev)
+ return 0;
+ }
+
+ /* Calculate resolution */
+ return logical_extents / physical_extents;
+}
+
+/*
+ * The physical dimension specified by the HID descriptor is likely not in
+ * the "100th of a mm" units expected by wacom_calculate_touch_res. This
+ * function adjusts the value of [xy]_phy based on the unit and exponent
+ * provided by the HID descriptor. If an error occurs durring conversion
+ * (e.g. from the unit being left unspecified) [xy]_phy is not modified.
+ */
+static void wacom_fix_phy_from_hid(struct wacom_features *features)
+{
+ int xres = wacom_calc_hid_res(features->x_max, features->x_phy,
+ features->unit, features->unitExpo);
+ int yres = wacom_calc_hid_res(features->y_max, features->y_phy,
+ features->unit, features->unitExpo);
+
+ if (xres > 0 && yres > 0) {
+ features->x_phy = (100 * features->x_max) / xres;
+ features->y_phy = (100 * features->y_max) / yres;
+ }
+}
+
+/*
* Static values for max X/Y and resolution of Pen interface is stored in
* features. This mean physical size of active area can be computed.
* This is useful to do when Pen and Touch have same active area of tablet.
@@ -531,6 +601,7 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
error = wacom_parse_hid(intf, hid_desc, features);
if (error)
goto out;
+ wacom_fix_phy_from_hid(features);
out:
return error;