|
@@ -171,6 +171,76 @@ static void wacom_close(struct input_dev *dev)
|
|
|
usb_autopm_put_interface(wacom->intf);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 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.
|
|
@@ -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;
|