From 3152301ff28872255461484b3dc831e2bf0f28db Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 30 Jul 2024 08:51:56 -0700 Subject: HID: wacom: Improve warning for tablets falling back to default resolution When we encounter a usage mapped to ABS_X or ABS_Y which has a calculated resolution of 0, we want to warn the user of this before setting a default value. The previous language used the word "usage" but then printed out the value of a "code" instead. We can improve this. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 1f4564982b95..b753b2f111fb 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1904,8 +1904,8 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage, if ((code == ABS_X || code == ABS_Y) && !resolution) { resolution = WACOM_INTUOS_RES; hid_warn(input, - "Wacom usage (%d) missing resolution \n", - code); + "Using default resolution for axis type 0x%x code 0x%x\n", + type, code); } input_abs_set_res(input, code, resolution); break; -- cgit v1.2.3 From 7525a0bd928e3a5d6dcea6a38cc5ce88f45d27a9 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 30 Jul 2024 08:51:57 -0700 Subject: HID: wacom: Support touchrings with relative motion If a touchring is configured to send relative events (e.g. +1 or -1 every time some bit of rotational distance is covered), we should similarly send relative events up to userspace. Previous non-HID tablets used REL_WHEEL to send this kind of information, so we opt to use this same axis since userspace (xf86-input-wacom and libinput) already expects this kind of behavior from the Wacom kernel driver. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index b753b2f111fb..798c26ddaeba 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1909,6 +1909,7 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage, } input_abs_set_res(input, code, resolution); break; + case EV_REL: case EV_KEY: case EV_MSC: case EV_SW: @@ -2045,7 +2046,10 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHRING: - wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); + if (field->flags & HID_MAIN_ITEM_RELATIVE) + wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL, 0); + else + wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHRINGSTATUS: @@ -2110,7 +2114,10 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field return; if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) { - if (usage->hid != WACOM_HID_WD_TOUCHRING) + bool is_abs_touchring = usage->hid == WACOM_HID_WD_TOUCHRING && + !(field->flags & HID_MAIN_ITEM_RELATIVE); + + if (!is_abs_touchring) wacom_wac->hid_data.inrange_state |= value; } @@ -2163,6 +2170,15 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field hdev->product == 0x3AA) value = wacom_offset_rotation(input, usage, value, 1, 2); } + else if (field->flags & HID_MAIN_ITEM_RELATIVE) { + /* We must invert the sign for vertical + * relative scrolling. Clockwise rotation + * produces positive values from HW, but + * userspace treats positive REL_WHEEL as a + * scroll *up*! + */ + value = -value; + } else { value = wacom_offset_rotation(input, usage, value, 1, 4); } -- cgit v1.2.3 From 7ca234e3ae457f6941601d58db22736cd133ef4c Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 30 Jul 2024 08:51:58 -0700 Subject: HID: wacom: Add preliminary support for high-resolution wheel scrolling Modern userspace (i.e. libinput) will make use of high-resolution scrolling if supported. Hardware does not currently set a resolution multiplier needed for effective high-res scrolling, but we can still write code to support it in the future. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 24 ++++++++++++++++++++---- drivers/hid/wacom_wac.h | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 798c26ddaeba..9e9cfc55b47b 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2046,10 +2046,12 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHRING: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL, 0); - else + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL_HI_RES, 0); + set_bit(REL_WHEEL, input->relbit); + } else { wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); + } features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHRINGSTATUS: @@ -2177,7 +2179,21 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field * userspace treats positive REL_WHEEL as a * scroll *up*! */ - value = -value; + int hires_value = -value * 120 / usage->resolution_multiplier; + int *ring_value = &wacom_wac->hid_data.ring_value; + + value = hires_value; + *ring_value += hires_value; + + /* Emulate a legacy wheel click for every 120 + * units of hi-res travel. + */ + if (*ring_value >= 120 || *ring_value <= -120) { + int clicks = *ring_value / 120; + + input_event(input, usage->type, REL_WHEEL, clicks); + *ring_value -= clicks * 120; + } } else { value = wacom_offset_rotation(input, usage, value, 1, 4); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 6ec499841f70..aeba2f3082f0 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -312,6 +312,7 @@ struct hid_data { int width; int height; int id; + int ring_value; int cc_report; int cc_index; int cc_value_index; -- cgit v1.2.3 From 19591e1a8a2e9e8ff53cc3121e6650bbf02f8403 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 30 Jul 2024 08:51:59 -0700 Subject: HID: wacom: Support devices with two touchrings If a device has more than one touchring, we want to be sure that userspace is able to distinguish them. Following previous standards, the first absolute ring will be reported as ABS_WHEEL and the second as ABS_THROTTLE. Relative rings will use REL_WHEEL_HI_RES / REL_WHEEL for the first and REL_HWHEEL_HI_RES / REL_HWHEEL for the second. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 58 +++++++++++++++++++++++++++++++++++++++---------- drivers/hid/wacom_wac.h | 3 +++ 2 files changed, 49 insertions(+), 12 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 9e9cfc55b47b..36010c515f39 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2047,10 +2047,21 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, break; case WACOM_HID_WD_TOUCHRING: if (field->flags & HID_MAIN_ITEM_RELATIVE) { - wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL_HI_RES, 0); - set_bit(REL_WHEEL, input->relbit); + wacom_wac->relring_count++; + if (wacom_wac->relring_count == 1) { + wacom_map_usage(input, usage, field, EV_REL, REL_WHEEL_HI_RES, 0); + set_bit(REL_WHEEL, input->relbit); + } + else if (wacom_wac->relring_count == 2) { + wacom_map_usage(input, usage, field, EV_REL, REL_HWHEEL_HI_RES, 0); + set_bit(REL_HWHEEL, input->relbit); + } } else { - wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); + wacom_wac->absring_count++; + if (wacom_wac->absring_count == 1) + wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); + else if (wacom_wac->absring_count == 2) + wacom_map_usage(input, usage, field, EV_ABS, ABS_THROTTLE, 0); } features->device_type |= WACOM_DEVICETYPE_PAD; break; @@ -2173,14 +2184,37 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field value = wacom_offset_rotation(input, usage, value, 1, 2); } else if (field->flags & HID_MAIN_ITEM_RELATIVE) { - /* We must invert the sign for vertical - * relative scrolling. Clockwise rotation - * produces positive values from HW, but - * userspace treats positive REL_WHEEL as a - * scroll *up*! - */ - int hires_value = -value * 120 / usage->resolution_multiplier; - int *ring_value = &wacom_wac->hid_data.ring_value; + int hires_value = value * 120 / usage->resolution_multiplier; + int *ring_value; + int lowres_code; + + if (usage->code == REL_WHEEL_HI_RES) { + /* We must invert the sign for vertical + * relative scrolling. Clockwise + * rotation produces positive values + * from HW, but userspace treats + * positive REL_WHEEL as a scroll *up*! + */ + hires_value = -hires_value; + ring_value = &wacom_wac->hid_data.ring_value; + lowres_code = REL_WHEEL; + } + else if (usage->code == REL_HWHEEL_HI_RES) { + /* No need to invert the sign for + * horizontal relative scrolling. + * Clockwise rotation produces positive + * values from HW and userspace treats + * positive REL_HWHEEL as a scroll + * right. + */ + ring_value = &wacom_wac->hid_data.ring2_value; + lowres_code = REL_HWHEEL; + } + else { + hid_err(wacom->hdev, "unrecognized relative wheel with code %d\n", + usage->code); + break; + } value = hires_value; *ring_value += hires_value; @@ -2191,7 +2225,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field if (*ring_value >= 120 || *ring_value <= -120) { int clicks = *ring_value / 120; - input_event(input, usage->type, REL_WHEEL, clicks); + input_event(input, usage->type, lowres_code, clicks); *ring_value -= clicks * 120; } } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index aeba2f3082f0..55e0c7a9fdcb 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -313,6 +313,7 @@ struct hid_data { int height; int id; int ring_value; + int ring2_value; int cc_report; int cc_index; int cc_value_index; @@ -356,6 +357,8 @@ struct wacom_wac { int num_contacts_left; u8 bt_features; u8 bt_high_speed; + u8 absring_count; + u8 relring_count; int mode_report; int mode_value; struct hid_data hid_data; -- cgit v1.2.3 From 359673ea3a203611b4f6d0f28922a4b9d2cfbcc8 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 9 Sep 2024 13:32:07 -0700 Subject: HID: wacom: Support sequence numbers smaller than 16-bit The current dropped packet reporting assumes that all sequence numbers are 16 bits in length. This results in misleading "Dropped" messages if the hardware uses fewer bits. For example, if a tablet uses only 8 bits to store its sequence number, once it rolls over from 255 -> 0, the driver will still be expecting a packet "256". This patch adjusts the logic to reset the next expected packet to logical_minimum whenever it overflows beyond logical_maximum. Signed-off-by: Jason Gerecke Tested-by: Joshua Dickens Fixes: 6d09085b38e5 ("HID: wacom: Adding Support for new usages") Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 36010c515f39..22b0d281ff5c 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2510,9 +2510,14 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field wacom_wac->hid_data.barrelswitch3 = value; return; case WACOM_HID_WD_SEQUENCENUMBER: - if (wacom_wac->hid_data.sequence_number != value) - hid_warn(hdev, "Dropped %hu packets", (unsigned short)(value - wacom_wac->hid_data.sequence_number)); + if (wacom_wac->hid_data.sequence_number != value) { + int sequence_size = field->logical_maximum - field->logical_minimum + 1; + int drop_count = (value - wacom_wac->hid_data.sequence_number) % sequence_size; + hid_warn(hdev, "Dropped %d packets", drop_count); + } wacom_wac->hid_data.sequence_number = value + 1; + if (wacom_wac->hid_data.sequence_number > field->logical_maximum) + wacom_wac->hid_data.sequence_number = field->logical_minimum; return; } -- cgit v1.2.3 From 84aecf2d251a3359bc78b7c8e58f54b9fc966e89 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 9 Sep 2024 13:32:08 -0700 Subject: HID: wacom: Do not warn about dropped packets for first packet The driver currently assumes that the first sequence number it will see is going to be 0. This is not a realiable assumption and can break if, for example, the tablet has already been running for some time prior to the kernel driver connecting to the device. This commit initializes the expected sequence number to -1 and will only print the "Dropped" warning the it has been updated to a non-negative value. Signed-off-by: Jason Gerecke Tested-by: Joshua Dickens Fixes: 6d09085b38e5 ("HID: wacom: Adding Support for new usages") Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 6 +++++- drivers/hid/wacom_wac.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/hid') diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 22b0d281ff5c..b7129cc7c6bf 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2386,6 +2386,9 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS3, 0); features->quirks &= ~WACOM_QUIRK_PEN_BUTTON3; break; + case WACOM_HID_WD_SEQUENCENUMBER: + wacom_wac->hid_data.sequence_number = -1; + break; } } @@ -2510,7 +2513,8 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field wacom_wac->hid_data.barrelswitch3 = value; return; case WACOM_HID_WD_SEQUENCENUMBER: - if (wacom_wac->hid_data.sequence_number != value) { + if (wacom_wac->hid_data.sequence_number != value && + wacom_wac->hid_data.sequence_number >= 0) { int sequence_size = field->logical_maximum - field->logical_minimum + 1; int drop_count = (value - wacom_wac->hid_data.sequence_number) % sequence_size; hid_warn(hdev, "Dropped %d packets", drop_count); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 55e0c7a9fdcb..c8803d5c6a71 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -326,7 +326,7 @@ struct hid_data { int bat_connected; int ps_connected; bool pad_input_event_flag; - unsigned short sequence_number; + int sequence_number; ktime_t time_delayed; }; -- cgit v1.2.3