|
@@ -567,8 +567,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
|
|
|
keys = data[9] & 0x07;
|
|
|
}
|
|
|
} else {
|
|
|
- buttons = ((data[6] & 0x10) << 10) |
|
|
|
- ((data[5] & 0x10) << 9) |
|
|
|
+ buttons = ((data[6] & 0x10) << 5) |
|
|
|
+ ((data[5] & 0x10) << 4) |
|
|
|
((data[6] & 0x0F) << 4) |
|
|
|
(data[5] & 0x0F);
|
|
|
}
|
|
@@ -1227,11 +1227,17 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
|
|
|
continue;
|
|
|
|
|
|
if (range) {
|
|
|
+ /* Fix rotation alignment: userspace expects zero at left */
|
|
|
+ int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
|
|
|
+ rotation += 1800/4;
|
|
|
+ if (rotation > 899)
|
|
|
+ rotation -= 1800;
|
|
|
+
|
|
|
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
|
|
|
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
|
|
|
- input_report_abs(pen_input, ABS_TILT_X, frame[7]);
|
|
|
- input_report_abs(pen_input, ABS_TILT_Y, frame[8]);
|
|
|
- input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9]));
|
|
|
+ input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]);
|
|
|
+ input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]);
|
|
|
+ input_report_abs(pen_input, ABS_Z, rotation);
|
|
|
input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
|
|
|
}
|
|
|
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
|
|
@@ -1319,12 +1325,19 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
|
|
|
unsigned char *data = wacom->data;
|
|
|
|
|
|
int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
|
|
|
- int ring = data[285];
|
|
|
- int prox = buttons | (ring & 0x80);
|
|
|
+ int ring = data[285] & 0x7F;
|
|
|
+ bool ringstatus = data[285] & 0x80;
|
|
|
+ bool prox = buttons || ringstatus;
|
|
|
+
|
|
|
+ /* Fix touchring data: userspace expects 0 at left and increasing clockwise */
|
|
|
+ ring = 71 - ring;
|
|
|
+ ring += 3*72/16;
|
|
|
+ if (ring > 71)
|
|
|
+ ring -= 72;
|
|
|
|
|
|
wacom_report_numbered_buttons(pad_input, 9, buttons);
|
|
|
|
|
|
- input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0);
|
|
|
+ input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
|
|
|
|
|
|
input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
|
|
|
input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
|
|
@@ -1616,6 +1629,20 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage,
|
|
|
+ int value, int num, int denom)
|
|
|
+{
|
|
|
+ struct input_absinfo *abs = &input->absinfo[usage->code];
|
|
|
+ int range = (abs->maximum - abs->minimum + 1);
|
|
|
+
|
|
|
+ value += num*range/denom;
|
|
|
+ if (value > abs->maximum)
|
|
|
+ value -= range;
|
|
|
+ else if (value < abs->minimum)
|
|
|
+ value += range;
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
int wacom_equivalent_usage(int usage)
|
|
|
{
|
|
|
if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
|
|
@@ -1898,6 +1925,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
|
|
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
|
|
|
int i;
|
|
|
bool is_touch_on = value;
|
|
|
+ bool do_report = false;
|
|
|
|
|
|
/*
|
|
|
* Avoid reporting this event and setting inrange_state if this usage
|
|
@@ -1912,6 +1940,29 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
|
|
}
|
|
|
|
|
|
switch (equivalent_usage) {
|
|
|
+ case WACOM_HID_WD_TOUCHRING:
|
|
|
+ /*
|
|
|
+ * Userspace expects touchrings to increase in value with
|
|
|
+ * clockwise gestures and have their zero point at the
|
|
|
+ * tablet's left. HID events "should" be clockwise-
|
|
|
+ * increasing and zero at top, though the MobileStudio
|
|
|
+ * Pro and 2nd-gen Intuos Pro don't do this...
|
|
|
+ */
|
|
|
+ if (hdev->vendor == 0x56a &&
|
|
|
+ (hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
|
|
|
+ hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
|
|
|
+ value = (field->logical_maximum - value);
|
|
|
+
|
|
|
+ if (hdev->product == 0x357 || hdev->product == 0x358)
|
|
|
+ value = wacom_offset_rotation(input, usage, value, 3, 16);
|
|
|
+ else if (hdev->product == 0x34d || hdev->product == 0x34e)
|
|
|
+ value = wacom_offset_rotation(input, usage, value, 1, 2);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ value = wacom_offset_rotation(input, usage, value, 1, 4);
|
|
|
+ }
|
|
|
+ do_report = true;
|
|
|
+ break;
|
|
|
case WACOM_HID_WD_TOUCHRINGSTATUS:
|
|
|
if (!value)
|
|
|
input_event(input, usage->type, usage->code, 0);
|
|
@@ -1945,10 +1996,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
|
|
|
value, i);
|
|
|
/* fall through*/
|
|
|
default:
|
|
|
+ do_report = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (do_report) {
|
|
|
input_event(input, usage->type, usage->code, value);
|
|
|
if (value)
|
|
|
wacom_wac->hid_data.pad_input_event_flag = true;
|
|
|
- break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2086,22 +2141,34 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
|
|
|
wacom_wac->hid_data.tipswitch |= value;
|
|
|
return;
|
|
|
case HID_DG_TOOLSERIALNUMBER:
|
|
|
- wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
|
|
|
- wacom_wac->serial[0] |= (__u32)value;
|
|
|
+ if (value) {
|
|
|
+ wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
|
|
|
+ wacom_wac->serial[0] |= (__u32)value;
|
|
|
+ }
|
|
|
return;
|
|
|
+ case HID_DG_TWIST:
|
|
|
+ /*
|
|
|
+ * Userspace expects pen twist to have its zero point when
|
|
|
+ * the buttons/finger is on the tablet's left. HID values
|
|
|
+ * are zero when buttons are toward the top.
|
|
|
+ */
|
|
|
+ value = wacom_offset_rotation(input, usage, value, 1, 4);
|
|
|
+ break;
|
|
|
case WACOM_HID_WD_SENSE:
|
|
|
wacom_wac->hid_data.sense_state = value;
|
|
|
return;
|
|
|
case WACOM_HID_WD_SERIALHI:
|
|
|
- wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
|
|
|
- wacom_wac->serial[0] |= ((__u64)value) << 32;
|
|
|
- /*
|
|
|
- * Non-USI EMR devices may contain additional tool type
|
|
|
- * information here. See WACOM_HID_WD_TOOLTYPE case for
|
|
|
- * more details.
|
|
|
- */
|
|
|
- if (value >> 20 == 1) {
|
|
|
- wacom_wac->id[0] |= value & 0xFFFFF;
|
|
|
+ if (value) {
|
|
|
+ wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
|
|
|
+ wacom_wac->serial[0] |= ((__u64)value) << 32;
|
|
|
+ /*
|
|
|
+ * Non-USI EMR devices may contain additional tool type
|
|
|
+ * information here. See WACOM_HID_WD_TOOLTYPE case for
|
|
|
+ * more details.
|
|
|
+ */
|
|
|
+ if (value >> 20 == 1) {
|
|
|
+ wacom_wac->id[0] |= value & 0xFFFFF;
|
|
|
+ }
|
|
|
}
|
|
|
return;
|
|
|
case WACOM_HID_WD_TOOLTYPE:
|
|
@@ -2205,7 +2272,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
|
|
input_report_key(input, wacom_wac->tool[0], prox);
|
|
|
if (wacom_wac->serial[0]) {
|
|
|
input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
|
|
|
- input_report_abs(input, ABS_MISC, id);
|
|
|
+ input_report_abs(input, ABS_MISC, prox ? id : 0);
|
|
|
}
|
|
|
|
|
|
wacom_wac->hid_data.tipswitch = false;
|
|
@@ -2216,6 +2283,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
|
|
|
if (!prox) {
|
|
|
wacom_wac->tool[0] = 0;
|
|
|
wacom_wac->id[0] = 0;
|
|
|
+ wacom_wac->serial[0] = 0;
|
|
|
}
|
|
|
}
|
|
|
|