HID: wacom: generic: Add support for sensor offsets
authorJason Gerecke <killertofu@gmail.com>
Thu, 20 Oct 2016 01:03:50 +0000 (18:03 -0700)
committerJiri Kosina <jkosina@suse.cz>
Thu, 20 Oct 2016 07:54:00 +0000 (09:54 +0200)
Many of Wacom's display tablets include an "outbound" area where pen
digitizing is possible but outside of the display area. To accommodate
such sensors in the HID_GENERIC codepath, we add support for the
necessary vendor-defined HID feature usages and adjust the min/max
values of the X and Y axes accordingly, similar to what is done in
the non-generic codepath.

Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
drivers/hid/wacom_wac.h

index b2e2471bbef6b6c5d6db71cb897972980f6d34c7..b9779bcbd1403f00114f9565c543df79583baa38 100644 (file)
@@ -122,6 +122,7 @@ static void wacom_feature_mapping(struct hid_device *hdev,
        struct hid_data *hid_data = &wacom->wacom_wac.hid_data;
        u8 *data;
        int ret;
+       int n;
 
        switch (usage->hid) {
        case HID_DG_CONTACTMAX:
@@ -180,6 +181,27 @@ static void wacom_feature_mapping(struct hid_device *hdev,
                        wacom->wacom_wac.mode_value = 0;
                }
                break;
+       case WACOM_HID_WD_OFFSETLEFT:
+       case WACOM_HID_WD_OFFSETTOP:
+       case WACOM_HID_WD_OFFSETRIGHT:
+       case WACOM_HID_WD_OFFSETBOTTOM:
+               /* read manually */
+               n = hid_report_len(field->report);
+               data = hid_alloc_report_buf(field->report, GFP_KERNEL);
+               if (!data)
+                       break;
+               data[0] = field->report->id;
+               ret = wacom_get_report(hdev, HID_FEATURE_REPORT,
+                                       data, n, WAC_CMD_RETRIES);
+               if (ret == n) {
+                       ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT,
+                                                  data, n, 0);
+               } else {
+                       hid_warn(hdev, "%s: could not retrieve sensor offsets\n",
+                                __func__);
+               }
+               kfree(data);
+               break;
        }
 }
 
@@ -718,11 +740,6 @@ static int wacom_add_shared_data(struct hid_device *hdev)
                return retval;
        }
 
-       if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
-               wacom_wac->shared->touch = hdev;
-       else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
-               wacom_wac->shared->pen = hdev;
-
 out:
        mutex_unlock(&wacom_udev_list_lock);
        return retval;
@@ -2019,6 +2036,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
        if (error)
                goto fail;
 
+       error = wacom_add_shared_data(hdev);
+       if (error)
+               goto fail;
+
        /*
         * Bamboo Pad has a generic hid handling for the Pen, and we switch it
         * into debug mode for the touch part.
@@ -2059,9 +2080,10 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
 
        wacom_update_name(wacom, wireless ? " (WL)" : "");
 
-       error = wacom_add_shared_data(hdev);
-       if (error)
-               goto fail;
+       if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
+               wacom_wac->shared->touch = hdev;
+       else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
+               wacom_wac->shared->pen = hdev;
 
        if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
             (features->quirks & WACOM_QUIRK_BATTERY)) {
index 5046071f2e9e5adcac22118ff447443ad7979e21..3bb6dd6e4eea9d55affb9f691a9e844aaab7a489 100644 (file)
@@ -1468,6 +1468,9 @@ static int wacom_equivalent_usage(int usage)
 static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
                struct hid_field *field, __u8 type, __u16 code, int fuzz)
 {
+       struct wacom *wacom = input_get_drvdata(input);
+       struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+       struct wacom_features *features = &wacom_wac->features;
        int fmin = field->logical_minimum;
        int fmax = field->logical_maximum;
        unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
@@ -1477,6 +1480,15 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
                resolution_code = ABS_RZ;
        }
 
+       if (equivalent_usage == HID_GD_X) {
+               fmin += features->offset_left;
+               fmax -= features->offset_right;
+       }
+       if (equivalent_usage == HID_GD_Y) {
+               fmin += features->offset_top;
+               fmax -= features->offset_bottom;
+       }
+
        usage->type = type;
        usage->code = code;
 
@@ -1629,6 +1641,34 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field,
                 */
                wacom_wac->id[0] |= value;
                return 0;
+       case WACOM_HID_WD_OFFSETLEFT:
+               if (features->offset_left && value != features->offset_left)
+                       hid_warn(hdev, "%s: overriding exising left offset "
+                                "%d -> %d\n", __func__, value,
+                                features->offset_left);
+               features->offset_left = value;
+               return 0;
+       case WACOM_HID_WD_OFFSETRIGHT:
+               if (features->offset_right && value != features->offset_right)
+                       hid_warn(hdev, "%s: overriding exising right offset "
+                                "%d -> %d\n", __func__, value,
+                                features->offset_right);
+               features->offset_right = value;
+               return 0;
+       case WACOM_HID_WD_OFFSETTOP:
+               if (features->offset_top && value != features->offset_top)
+                       hid_warn(hdev, "%s: overriding exising top offset "
+                                "%d -> %d\n", __func__, value,
+                                features->offset_top);
+               features->offset_top = value;
+               return 0;
+       case WACOM_HID_WD_OFFSETBOTTOM:
+               if (features->offset_bottom && value != features->offset_bottom)
+                       hid_warn(hdev, "%s: overriding exising bottom offset "
+                                "%d -> %d\n", __func__, value,
+                                features->offset_bottom);
+               features->offset_bottom = value;
+               return 0;
        }
 
        /* send pen events only when touch is up or forced out
index 5c5c6891b8326d1fb782f6bd776db2ce6424e48f..b4c3c6425b85cb1ceed948d70b511e3e800ed333 100644 (file)
 #define WACOM_HID_WD_TOOLTYPE           (WACOM_HID_UP_WACOMDIGITIZER | 0x77)
 #define WACOM_HID_WD_DISTANCE           (WACOM_HID_UP_WACOMDIGITIZER | 0x0132)
 #define WACOM_HID_WD_FINGERWHEEL        (WACOM_HID_UP_WACOMDIGITIZER | 0x0d03)
+#define WACOM_HID_WD_OFFSETLEFT         (WACOM_HID_UP_WACOMDIGITIZER | 0x0d30)
+#define WACOM_HID_WD_OFFSETTOP          (WACOM_HID_UP_WACOMDIGITIZER | 0x0d31)
+#define WACOM_HID_WD_OFFSETRIGHT        (WACOM_HID_UP_WACOMDIGITIZER | 0x0d32)
+#define WACOM_HID_WD_OFFSETBOTTOM       (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
 #define WACOM_HID_WD_DATAMODE           (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
 #define WACOM_HID_UP_G9                 0xff090000
 #define WACOM_HID_G9_PEN                (WACOM_HID_UP_G9 | 0x02)