From d170e8e02729ad3bc4924005cec1ad38409d82af Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 3 Mar 2022 08:47:31 +0100 Subject: [PATCH 01/20] HID: uclogic: Add support for touch ring reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for touch ring to UC-Logic driver. The touch ring reports can be flipped around a specific point to match the orientation and direction reported by the Wacom drivers. The proximity will also be reported similar to the Wacom drivers. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 39 +++++++++++++++++++++++++++++++- drivers/hid/hid-uclogic-params.h | 36 +++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 05147f2d75645..b448616dacb9d 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -90,6 +90,8 @@ static int uclogic_input_configured(struct hid_device *hdev, const char *suffix = NULL; struct hid_field *field; size_t len; + size_t i; + const struct uclogic_params_frame *frame; /* no report associated (HID_QUIRK_MULTI_INPUT not set) */ if (!hi->report) @@ -104,6 +106,19 @@ static int uclogic_input_configured(struct hid_device *hdev, drvdata->pen_input = hi->input; } + /* If it's one of the frame devices */ + for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { + frame = ¶ms->frame_list[i]; + if (hi->report->id == frame->id) { + /* + * Disable EV_MSC reports for touch ring interfaces to + * make the Wacom driver pickup touch ring extents + */ + if (frame->touch_ring_byte > 0) + __clear_bit(EV_MSC, hi->input->evbit); + } + } + field = hi->report->field[0]; switch (field->application) { @@ -313,8 +328,16 @@ static int uclogic_raw_event_frame( /* If need to, and can, set pad device ID for Wacom drivers */ if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) { - data[frame->dev_id_byte] = 0xf; + /* If we also have a touch ring and the finger left it */ + if (frame->touch_ring_byte > 0 && + frame->touch_ring_byte < size && + data[frame->touch_ring_byte] == 0) { + data[frame->dev_id_byte] = 0; + } else { + data[frame->dev_id_byte] = 0xf; + } } + /* If need to, and can, read rotary encoder state change */ if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) { unsigned int byte = frame->re_lsb / 8; @@ -341,6 +364,20 @@ static int uclogic_raw_event_frame( drvdata->re_state = state; } + /* If need to, and can, transform the touch ring reports */ + if (frame->touch_ring_byte > 0 && frame->touch_ring_byte < size && + frame->touch_ring_flip_at != 0) { + __s8 value = data[frame->touch_ring_byte]; + + if (value != 0) { + value = frame->touch_ring_flip_at - value; + if (value < 0) + value = frame->touch_ring_max + value; + + data[frame->touch_ring_byte] = value; + } + } + return 0; } diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index 86f616dfbb53d..fe13bc36983b4 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -123,10 +123,32 @@ struct uclogic_params_frame { /* * Offset of the Wacom-style device ID byte in the report, to be set * to pad device ID (0xf), for compatibility with Wacom drivers. Zero - * if no changes to the report should be made. Only valid if "id" is - * not zero. + * if no changes to the report should be made. The ID byte will be set + * to zero whenever the byte pointed by "touch_ring_byte" is zero, if + * the latter is valid. Only valid if "id" is not zero. */ unsigned int dev_id_byte; + /* + * Offset of the touch ring state byte, in the report. + * Zero if not present. If dev_id_byte is also valid and non-zero, + * then the device ID byte will be cleared when the byte pointed to by + * this offset is zero. Only valid if "id" is not zero. + */ + unsigned int touch_ring_byte; + + /* + * Maximum value of the touch ring report. + * The minimum valid value is considered to be one, + * with zero being out-of-proximity (finger lift) value. + */ + __s8 touch_ring_max; + + /* + * The value to anchor the reversed reports at. + * I.e. one, if the reports should be flipped without offset. + * Zero if no reversal should be done. + */ + __s8 touch_ring_flip_at; }; /* @@ -191,7 +213,10 @@ extern int uclogic_params_init(struct uclogic_params *params, ".frame_list[0].desc_size = %u\n" \ ".frame_list[0].id = %u\n" \ ".frame_list[0].re_lsb = %u\n" \ - ".frame_list[0].dev_id_byte = %u\n" + ".frame_list[0].dev_id_byte = %u\n" \ + ".frame_list[0].touch_ring_byte = %u\n" \ + ".frame_list[0].touch_ring_max = %hhd\n" \ + ".frame_list[0].touch_ring_flip_at = %hhd\n" /* Tablet interface parameters *printf format arguments */ #define UCLOGIC_PARAMS_FMT_ARGS(_params) \ @@ -210,7 +235,10 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[0].desc_size, \ (_params)->frame_list[0].id, \ (_params)->frame_list[0].re_lsb, \ - (_params)->frame_list[0].dev_id_byte + (_params)->frame_list[0].dev_id_byte, \ + (_params)->frame_list[0].touch_ring_byte, \ + (_params)->frame_list[0].touch_ring_max, \ + (_params)->frame_list[0].touch_ring_flip_at /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, From ee0070367e1da844e385562fb4f33453b7f7c587 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 3 Mar 2022 08:47:32 +0100 Subject: [PATCH 02/20] HID: uclogic: Support custom device suffix for frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support assigning custom device name suffixes to frame input devices instead of just "Pad". This allows distinguishing multiple frame input devices, e.g. for Huion HS610. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 46 +++++++++++++++++--------------- drivers/hid/hid-uclogic-params.h | 6 +++++ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index b448616dacb9d..96f3fb8c492c3 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -110,6 +110,8 @@ static int uclogic_input_configured(struct hid_device *hdev, for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { frame = ¶ms->frame_list[i]; if (hi->report->id == frame->id) { + /* Assign custom suffix, if any */ + suffix = frame->suffix; /* * Disable EV_MSC reports for touch ring interfaces to * make the Wacom driver pickup touch ring extents @@ -119,27 +121,29 @@ static int uclogic_input_configured(struct hid_device *hdev, } } - field = hi->report->field[0]; - - switch (field->application) { - case HID_GD_KEYBOARD: - suffix = "Keyboard"; - break; - case HID_GD_MOUSE: - suffix = "Mouse"; - break; - case HID_GD_KEYPAD: - suffix = "Pad"; - break; - case HID_DG_PEN: - suffix = "Pen"; - break; - case HID_CP_CONSUMER_CONTROL: - suffix = "Consumer Control"; - break; - case HID_GD_SYSTEM_CONTROL: - suffix = "System Control"; - break; + if (!suffix) { + field = hi->report->field[0]; + + switch (field->application) { + case HID_GD_KEYBOARD: + suffix = "Keyboard"; + break; + case HID_GD_MOUSE: + suffix = "Mouse"; + break; + case HID_GD_KEYPAD: + suffix = "Pad"; + break; + case HID_DG_PEN: + suffix = "Pen"; + break; + case HID_CP_CONSUMER_CONTROL: + suffix = "Consumer Control"; + break; + case HID_GD_SYSTEM_CONTROL: + suffix = "System Control"; + break; + } } if (suffix) { diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index fe13bc36983b4..8042820e78b13 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -114,6 +114,10 @@ struct uclogic_params_frame { * Report ID, if reports should be tweaked, zero if not. */ unsigned int id; + /* + * The suffix to add to the input device name, if not NULL. + */ + const char *suffix; /* * Number of the least-significant bit of the 2-bit state of a rotary * encoder, in the report. Cannot point to a 2-bit field crossing a @@ -212,6 +216,7 @@ extern int uclogic_params_init(struct uclogic_params *params, ".frame_list[0].desc_ptr = %p\n" \ ".frame_list[0].desc_size = %u\n" \ ".frame_list[0].id = %u\n" \ + ".frame_list[0].suffix = %s\n" \ ".frame_list[0].re_lsb = %u\n" \ ".frame_list[0].dev_id_byte = %u\n" \ ".frame_list[0].touch_ring_byte = %u\n" \ @@ -234,6 +239,7 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[0].desc_ptr, \ (_params)->frame_list[0].desc_size, \ (_params)->frame_list[0].id, \ + (_params)->frame_list[0].suffix, \ (_params)->frame_list[0].re_lsb, \ (_params)->frame_list[0].dev_id_byte, \ (_params)->frame_list[0].touch_ring_byte, \ From 3e200d6cdb7d5c892fb4819be66c65385673a980 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 3 Mar 2022 08:47:33 +0100 Subject: [PATCH 03/20] HID: uclogic: Allow three frame parameter sets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow three frame parameter sets per each UC-Logic tablet interface. Bump the number of supported subreports to three as well to accommodate ID routing. This allows supporting the dial on Huion Q620M. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.h | 52 +++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index 8042820e78b13..f2649e8f959d1 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -73,8 +73,8 @@ struct uclogic_params_pen { unsigned int desc_size; /* Report ID, if reports should be tweaked, zero if not */ unsigned int id; - /* The list of subreports */ - struct uclogic_params_pen_subreport subreport_list[1]; + /* The list of subreports, only valid if "id" is not zero */ + struct uclogic_params_pen_subreport subreport_list[3]; /* Type of in-range reporting, only valid if "id" is not zero */ enum uclogic_params_pen_inrange inrange; /* @@ -194,7 +194,7 @@ struct uclogic_params { * The list of frame control parameters and optional report descriptor * parts. Only valid, if "invalid" is false. */ - struct uclogic_params_frame frame_list[1]; + struct uclogic_params_frame frame_list[3]; }; /* Initialize a tablet interface and discover its parameters */ @@ -210,6 +210,8 @@ extern int uclogic_params_init(struct uclogic_params *params, ".pen.desc_size = %u\n" \ ".pen.id = %u\n" \ ".pen.subreport_list[0] = {0x%02hhx, %hhu}\n" \ + ".pen.subreport_list[1] = {0x%02hhx, %hhu}\n" \ + ".pen.subreport_list[2] = {0x%02hhx, %hhu}\n" \ ".pen.inrange = %s\n" \ ".pen.fragmented_hires = %s\n" \ ".pen.tilt_y_flipped = %s\n" \ @@ -221,7 +223,25 @@ extern int uclogic_params_init(struct uclogic_params *params, ".frame_list[0].dev_id_byte = %u\n" \ ".frame_list[0].touch_ring_byte = %u\n" \ ".frame_list[0].touch_ring_max = %hhd\n" \ - ".frame_list[0].touch_ring_flip_at = %hhd\n" + ".frame_list[0].touch_ring_flip_at = %hhd\n" \ + ".frame_list[1].desc_ptr = %p\n" \ + ".frame_list[1].desc_size = %u\n" \ + ".frame_list[1].id = %u\n" \ + ".frame_list[1].suffix = %s\n" \ + ".frame_list[1].re_lsb = %u\n" \ + ".frame_list[1].dev_id_byte = %u\n" \ + ".frame_list[1].touch_ring_byte = %u\n" \ + ".frame_list[1].touch_ring_max = %hhd\n" \ + ".frame_list[1].touch_ring_flip_at = %hhd\n" \ + ".frame_list[2].desc_ptr = %p\n" \ + ".frame_list[2].desc_size = %u\n" \ + ".frame_list[2].id = %u\n" \ + ".frame_list[2].suffix = %s\n" \ + ".frame_list[2].re_lsb = %u\n" \ + ".frame_list[2].dev_id_byte = %u\n" \ + ".frame_list[2].touch_ring_byte = %u\n" \ + ".frame_list[2].touch_ring_max = %hhd\n" \ + ".frame_list[2].touch_ring_flip_at = %hhd\n" /* Tablet interface parameters *printf format arguments */ #define UCLOGIC_PARAMS_FMT_ARGS(_params) \ @@ -233,6 +253,10 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->pen.id, \ (_params)->pen.subreport_list[0].value, \ (_params)->pen.subreport_list[0].id, \ + (_params)->pen.subreport_list[1].value, \ + (_params)->pen.subreport_list[1].id, \ + (_params)->pen.subreport_list[2].value, \ + (_params)->pen.subreport_list[2].id, \ uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ ((_params)->pen.fragmented_hires ? "true" : "false"), \ ((_params)->pen.tilt_y_flipped ? "true" : "false"), \ @@ -244,7 +268,25 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[0].dev_id_byte, \ (_params)->frame_list[0].touch_ring_byte, \ (_params)->frame_list[0].touch_ring_max, \ - (_params)->frame_list[0].touch_ring_flip_at + (_params)->frame_list[0].touch_ring_flip_at, \ + (_params)->frame_list[1].desc_ptr, \ + (_params)->frame_list[1].desc_size, \ + (_params)->frame_list[1].id, \ + (_params)->frame_list[1].suffix, \ + (_params)->frame_list[1].re_lsb, \ + (_params)->frame_list[1].dev_id_byte, \ + (_params)->frame_list[1].touch_ring_byte, \ + (_params)->frame_list[1].touch_ring_max, \ + (_params)->frame_list[1].touch_ring_flip_at, \ + (_params)->frame_list[2].desc_ptr, \ + (_params)->frame_list[2].desc_size, \ + (_params)->frame_list[2].id, \ + (_params)->frame_list[2].suffix, \ + (_params)->frame_list[2].re_lsb, \ + (_params)->frame_list[2].dev_id_byte, \ + (_params)->frame_list[2].touch_ring_byte, \ + (_params)->frame_list[2].touch_ring_max, \ + (_params)->frame_list[2].touch_ring_flip_at /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, From c3e6e59af2a0c7937815808804eb4d9ddc9df9be Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 3 Mar 2022 08:47:34 +0100 Subject: [PATCH 04/20] HID: uclogic: Add support for Huion touch ring reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support touch ring reports found in Huion HS610 to the UC-Logic driver. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 40 ++++++++++++++++---- drivers/hid/hid-uclogic-rdesc.c | 65 ++++++++++++++++++++++++++++---- drivers/hid/hid-uclogic-rdesc.h | 20 +++++++--- 3 files changed, 105 insertions(+), 20 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 5f50ceb875d6d..3ac45e7572a0c 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -745,22 +745,48 @@ static int uclogic_params_huion_init(struct uclogic_params *params, goto cleanup; } else if (found) { hid_dbg(hdev, "pen v2 parameters found\n"); - /* Create v2 frame parameters */ + /* Create v2 frame button parameters */ rc = uclogic_params_frame_init_with_desc( &p.frame_list[0], - uclogic_rdesc_v2_frame_arr, - uclogic_rdesc_v2_frame_size, - UCLOGIC_RDESC_V2_FRAME_ID); + uclogic_rdesc_v2_frame_buttons_arr, + uclogic_rdesc_v2_frame_buttons_size, + UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID); if (rc != 0) { hid_err(hdev, - "failed creating v2 frame parameters: %d\n", + "failed creating v2 frame button parameters: %d\n", rc); goto cleanup; } - /* Link frame button subreports from pen reports */ + + /* Create v2 frame touch ring parameters */ + rc = uclogic_params_frame_init_with_desc( + &p.frame_list[1], + uclogic_rdesc_v2_frame_touch_ring_arr, + uclogic_rdesc_v2_frame_touch_ring_size, + UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID); + if (rc != 0) { + hid_err(hdev, + "failed creating v2 frame touch ring parameters: %d\n", + rc); + goto cleanup; + } + p.frame_list[1].suffix = "Touch Ring"; + p.frame_list[1].dev_id_byte = + UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_DEV_ID_BYTE; + p.frame_list[1].touch_ring_byte = 5; + p.frame_list[1].touch_ring_max = 12; + p.frame_list[1].touch_ring_flip_at = 6; + + /* + * Link button and touch ring subreports from pen + * reports + */ p.pen.subreport_list[0].value = 0xe0; p.pen.subreport_list[0].id = - UCLOGIC_RDESC_V2_FRAME_ID; + UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID; + p.pen.subreport_list[1].value = 0xf0; + p.pen.subreport_list[1].id = + UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID; goto output; } hid_dbg(hdev, "pen v2 parameters not found\n"); diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 04644d93bd117..d64b607dce5d1 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -652,12 +652,12 @@ const size_t uclogic_rdesc_v2_pen_template_size = sizeof(uclogic_rdesc_v2_pen_template_arr); /* - * Expand to the contents of a generic frame report descriptor. + * Expand to the contents of a generic frame buttons report descriptor. * * @_id: The report ID to use. * @_size: Size of the report to pad to, including report ID, bytes. */ -#define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \ +#define UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(_id, _size) \ 0x05, 0x01, /* Usage Page (Desktop), */ \ 0x09, 0x07, /* Usage (Keypad), */ \ 0xA1, 0x01, /* Collection (Application), */ \ @@ -700,17 +700,66 @@ const size_t uclogic_rdesc_v2_pen_template_size = /* Fixed report descriptor for (tweaked) v1 frame reports */ const __u8 uclogic_rdesc_v1_frame_arr[] = { - UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8) + UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8) }; const size_t uclogic_rdesc_v1_frame_size = sizeof(uclogic_rdesc_v1_frame_arr); -/* Fixed report descriptor for (tweaked) v2 frame reports */ -const __u8 uclogic_rdesc_v2_frame_arr[] = { - UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V2_FRAME_ID, 12) +/* Fixed report descriptor for (tweaked) v2 frame button reports */ +const __u8 uclogic_rdesc_v2_frame_buttons_arr[] = { + UCLOGIC_RDESC_FRAME_BUTTONS_BYTES(UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID, + 12) }; -const size_t uclogic_rdesc_v2_frame_size = - sizeof(uclogic_rdesc_v2_frame_arr); +const size_t uclogic_rdesc_v2_frame_buttons_size = + sizeof(uclogic_rdesc_v2_frame_buttons_arr); + +/* Fixed report descriptor for (tweaked) v2 frame touch ring reports */ +const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID, + /* Report ID (DIAL_ID), */ + 0x14, /* Logical Minimum (0), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x39, /* Usage (Tablet Function Keys), */ + 0xA0, /* Collection (Physical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x09, 0x01, /* Usage (01h), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x38, /* Usage (Wheel), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x0B, /* Logical Maximum (11), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x2E, /* Report Count (46), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_v2_frame_touch_ring_size = + sizeof(uclogic_rdesc_v2_frame_touch_ring_arr); /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 3d904c27b86a4..f15a9d8a946b3 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -124,12 +124,22 @@ extern const size_t uclogic_rdesc_v2_pen_template_size; extern const __u8 uclogic_rdesc_v1_frame_arr[]; extern const size_t uclogic_rdesc_v1_frame_size; -/* Report ID for tweaked v2 frame reports */ -#define UCLOGIC_RDESC_V2_FRAME_ID 0xf7 +/* Report ID for tweaked v2 frame button reports */ +#define UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID 0xf7 -/* Fixed report descriptor for (tweaked) v2 frame reports */ -extern const __u8 uclogic_rdesc_v2_frame_arr[]; -extern const size_t uclogic_rdesc_v2_frame_size; +/* Fixed report descriptor for (tweaked) v2 frame button reports */ +extern const __u8 uclogic_rdesc_v2_frame_buttons_arr[]; +extern const size_t uclogic_rdesc_v2_frame_buttons_size; + +/* Report ID for tweaked v2 frame touch ring reports */ +#define UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID 0xf8 + +/* Fixed report descriptor for (tweaked) v2 frame touch ring reports */ +extern const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[]; +extern const size_t uclogic_rdesc_v2_frame_touch_ring_size; + +/* Device ID byte offset in v2 frame touch ring reports */ +#define UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_DEV_ID_BYTE 0x4 /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; From eea4269f135e7bc11eef125c4ab6c7f50fb5c809 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 14 Apr 2022 13:09:33 +0200 Subject: [PATCH 05/20] HID: uclogic: Compress params format string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorten the format string for printing out UC-Logic interface parameters so that it fits into a single log message. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.h | 90 ++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index f2649e8f959d1..ebf84b56746b5 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -203,45 +203,57 @@ extern int uclogic_params_init(struct uclogic_params *params, /* Tablet interface parameters *printf format string */ #define UCLOGIC_PARAMS_FMT_STR \ - ".invalid = %s\n" \ - ".desc_ptr = %p\n" \ - ".desc_size = %u\n" \ - ".pen.desc_ptr = %p\n" \ - ".pen.desc_size = %u\n" \ - ".pen.id = %u\n" \ - ".pen.subreport_list[0] = {0x%02hhx, %hhu}\n" \ - ".pen.subreport_list[1] = {0x%02hhx, %hhu}\n" \ - ".pen.subreport_list[2] = {0x%02hhx, %hhu}\n" \ - ".pen.inrange = %s\n" \ - ".pen.fragmented_hires = %s\n" \ - ".pen.tilt_y_flipped = %s\n" \ - ".frame_list[0].desc_ptr = %p\n" \ - ".frame_list[0].desc_size = %u\n" \ - ".frame_list[0].id = %u\n" \ - ".frame_list[0].suffix = %s\n" \ - ".frame_list[0].re_lsb = %u\n" \ - ".frame_list[0].dev_id_byte = %u\n" \ - ".frame_list[0].touch_ring_byte = %u\n" \ - ".frame_list[0].touch_ring_max = %hhd\n" \ - ".frame_list[0].touch_ring_flip_at = %hhd\n" \ - ".frame_list[1].desc_ptr = %p\n" \ - ".frame_list[1].desc_size = %u\n" \ - ".frame_list[1].id = %u\n" \ - ".frame_list[1].suffix = %s\n" \ - ".frame_list[1].re_lsb = %u\n" \ - ".frame_list[1].dev_id_byte = %u\n" \ - ".frame_list[1].touch_ring_byte = %u\n" \ - ".frame_list[1].touch_ring_max = %hhd\n" \ - ".frame_list[1].touch_ring_flip_at = %hhd\n" \ - ".frame_list[2].desc_ptr = %p\n" \ - ".frame_list[2].desc_size = %u\n" \ - ".frame_list[2].id = %u\n" \ - ".frame_list[2].suffix = %s\n" \ - ".frame_list[2].re_lsb = %u\n" \ - ".frame_list[2].dev_id_byte = %u\n" \ - ".frame_list[2].touch_ring_byte = %u\n" \ - ".frame_list[2].touch_ring_max = %hhd\n" \ - ".frame_list[2].touch_ring_flip_at = %hhd\n" + ".invalid = %s\n" \ + ".desc_ptr = %p\n" \ + ".desc_size = %u\n" \ + ".pen = {\n" \ + "\t.desc_ptr = %p\n" \ + "\t.desc_size = %u\n" \ + "\t.id = %u\n" \ + "\t.subreport_list = {\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t}\n" \ + "\t.inrange = %s\n" \ + "\t.fragmented_hires = %s\n" \ + "\t.tilt_y_flipped = %s\n" \ + "}\n" \ + ".frame_list = {\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "}\n" /* Tablet interface parameters *printf format arguments */ #define UCLOGIC_PARAMS_FMT_ARGS(_params) \ From f25df3532832c93b7857a61266e48fa0ab87bca7 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 14 Apr 2022 13:09:34 +0200 Subject: [PATCH 06/20] HID: uclogic: Reduce indent for params format str/args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve legibility of UCLOGIC_PARAMS_FMT_STR/ARGS. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.h | 186 +++++++++++++++---------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index ebf84b56746b5..78965e683d20f 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -203,102 +203,102 @@ extern int uclogic_params_init(struct uclogic_params *params, /* Tablet interface parameters *printf format string */ #define UCLOGIC_PARAMS_FMT_STR \ - ".invalid = %s\n" \ - ".desc_ptr = %p\n" \ - ".desc_size = %u\n" \ - ".pen = {\n" \ - "\t.desc_ptr = %p\n" \ - "\t.desc_size = %u\n" \ - "\t.id = %u\n" \ - "\t.subreport_list = {\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t}\n" \ - "\t.inrange = %s\n" \ - "\t.fragmented_hires = %s\n" \ - "\t.tilt_y_flipped = %s\n" \ - "}\n" \ - ".frame_list = {\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t},\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t},\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t},\n" \ - "}\n" + ".invalid = %s\n" \ + ".desc_ptr = %p\n" \ + ".desc_size = %u\n" \ + ".pen = {\n" \ + "\t.desc_ptr = %p\n" \ + "\t.desc_size = %u\n" \ + "\t.id = %u\n" \ + "\t.subreport_list = {\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t\t{0x%02hhx, %hhu},\n" \ + "\t}\n" \ + "\t.inrange = %s\n" \ + "\t.fragmented_hires = %s\n" \ + "\t.tilt_y_flipped = %s\n" \ + "}\n" \ + ".frame_list = {\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "\t{\n" \ + "\t\t.desc_ptr = %p\n" \ + "\t\t.desc_size = %u\n" \ + "\t\t.id = %u\n" \ + "\t\t.suffix = %s\n" \ + "\t\t.re_lsb = %u\n" \ + "\t\t.dev_id_byte = %u\n" \ + "\t\t.touch_ring_byte = %u\n" \ + "\t\t.touch_ring_max = %hhd\n" \ + "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t},\n" \ + "}\n" /* Tablet interface parameters *printf format arguments */ #define UCLOGIC_PARAMS_FMT_ARGS(_params) \ - ((_params)->invalid ? "true" : "false"), \ - (_params)->desc_ptr, \ - (_params)->desc_size, \ - (_params)->pen.desc_ptr, \ - (_params)->pen.desc_size, \ - (_params)->pen.id, \ - (_params)->pen.subreport_list[0].value, \ - (_params)->pen.subreport_list[0].id, \ - (_params)->pen.subreport_list[1].value, \ - (_params)->pen.subreport_list[1].id, \ - (_params)->pen.subreport_list[2].value, \ - (_params)->pen.subreport_list[2].id, \ - uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ - ((_params)->pen.fragmented_hires ? "true" : "false"), \ - ((_params)->pen.tilt_y_flipped ? "true" : "false"), \ - (_params)->frame_list[0].desc_ptr, \ - (_params)->frame_list[0].desc_size, \ - (_params)->frame_list[0].id, \ - (_params)->frame_list[0].suffix, \ - (_params)->frame_list[0].re_lsb, \ - (_params)->frame_list[0].dev_id_byte, \ - (_params)->frame_list[0].touch_ring_byte, \ - (_params)->frame_list[0].touch_ring_max, \ - (_params)->frame_list[0].touch_ring_flip_at, \ - (_params)->frame_list[1].desc_ptr, \ - (_params)->frame_list[1].desc_size, \ - (_params)->frame_list[1].id, \ - (_params)->frame_list[1].suffix, \ - (_params)->frame_list[1].re_lsb, \ - (_params)->frame_list[1].dev_id_byte, \ - (_params)->frame_list[1].touch_ring_byte, \ - (_params)->frame_list[1].touch_ring_max, \ - (_params)->frame_list[1].touch_ring_flip_at, \ - (_params)->frame_list[2].desc_ptr, \ - (_params)->frame_list[2].desc_size, \ - (_params)->frame_list[2].id, \ - (_params)->frame_list[2].suffix, \ - (_params)->frame_list[2].re_lsb, \ - (_params)->frame_list[2].dev_id_byte, \ - (_params)->frame_list[2].touch_ring_byte, \ - (_params)->frame_list[2].touch_ring_max, \ - (_params)->frame_list[2].touch_ring_flip_at + ((_params)->invalid ? "true" : "false"), \ + (_params)->desc_ptr, \ + (_params)->desc_size, \ + (_params)->pen.desc_ptr, \ + (_params)->pen.desc_size, \ + (_params)->pen.id, \ + (_params)->pen.subreport_list[0].value, \ + (_params)->pen.subreport_list[0].id, \ + (_params)->pen.subreport_list[1].value, \ + (_params)->pen.subreport_list[1].id, \ + (_params)->pen.subreport_list[2].value, \ + (_params)->pen.subreport_list[2].id, \ + uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ + ((_params)->pen.fragmented_hires ? "true" : "false"), \ + ((_params)->pen.tilt_y_flipped ? "true" : "false"), \ + (_params)->frame_list[0].desc_ptr, \ + (_params)->frame_list[0].desc_size, \ + (_params)->frame_list[0].id, \ + (_params)->frame_list[0].suffix, \ + (_params)->frame_list[0].re_lsb, \ + (_params)->frame_list[0].dev_id_byte, \ + (_params)->frame_list[0].touch_ring_byte, \ + (_params)->frame_list[0].touch_ring_max, \ + (_params)->frame_list[0].touch_ring_flip_at, \ + (_params)->frame_list[1].desc_ptr, \ + (_params)->frame_list[1].desc_size, \ + (_params)->frame_list[1].id, \ + (_params)->frame_list[1].suffix, \ + (_params)->frame_list[1].re_lsb, \ + (_params)->frame_list[1].dev_id_byte, \ + (_params)->frame_list[1].touch_ring_byte, \ + (_params)->frame_list[1].touch_ring_max, \ + (_params)->frame_list[1].touch_ring_flip_at, \ + (_params)->frame_list[2].desc_ptr, \ + (_params)->frame_list[2].desc_size, \ + (_params)->frame_list[2].id, \ + (_params)->frame_list[2].suffix, \ + (_params)->frame_list[2].re_lsb, \ + (_params)->frame_list[2].dev_id_byte, \ + (_params)->frame_list[2].touch_ring_byte, \ + (_params)->frame_list[2].touch_ring_max, \ + (_params)->frame_list[2].touch_ring_flip_at /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, From 2112b49eaa5c5cffc22ddd8b3b09f7d20bf13819 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 14 Apr 2022 13:09:35 +0200 Subject: [PATCH 07/20] HID: uclogic: Add support for bitmap dials MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bitmap dial sends reports with a dedicated bit per direction: 1 means clockwise rotation, 2 means counterclockwise, as opposed to the normal 1 and -1 values. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 6 ++++++ drivers/hid/hid-uclogic-params.h | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 96f3fb8c492c3..627f1d0c52f23 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -382,6 +382,12 @@ static int uclogic_raw_event_frame( } } + /* If need to, and can, transform the bitmap dial reports */ + if (frame->bitmap_dial_byte > 0 && frame->bitmap_dial_byte < size) { + if (data[frame->bitmap_dial_byte] == 2) + data[frame->bitmap_dial_byte] = -1; + } + return 0; } diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index 78965e683d20f..e5ccc558abc34 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -153,6 +153,13 @@ struct uclogic_params_frame { * Zero if no reversal should be done. */ __s8 touch_ring_flip_at; + /* + * Offset of the bitmap dial byte, in the report. Zero if not present. + * Only valid if "id" is not zero. A bitmap dial sends reports with a + * dedicated bit per direction: 1 means clockwise rotation, 2 means + * counterclockwise, as opposed to the normal 1 and -1. + */ + unsigned int bitmap_dial_byte; }; /* @@ -230,6 +237,7 @@ extern int uclogic_params_init(struct uclogic_params *params, "\t\t.touch_ring_byte = %u\n" \ "\t\t.touch_ring_max = %hhd\n" \ "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t\t.bitmap_dial_byte = %u\n" \ "\t},\n" \ "\t{\n" \ "\t\t.desc_ptr = %p\n" \ @@ -241,6 +249,7 @@ extern int uclogic_params_init(struct uclogic_params *params, "\t\t.touch_ring_byte = %u\n" \ "\t\t.touch_ring_max = %hhd\n" \ "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t\t.bitmap_dial_byte = %u\n" \ "\t},\n" \ "\t{\n" \ "\t\t.desc_ptr = %p\n" \ @@ -252,6 +261,7 @@ extern int uclogic_params_init(struct uclogic_params *params, "\t\t.touch_ring_byte = %u\n" \ "\t\t.touch_ring_max = %hhd\n" \ "\t\t.touch_ring_flip_at = %hhd\n" \ + "\t\t.bitmap_dial_byte = %u\n" \ "\t},\n" \ "}\n" @@ -281,6 +291,7 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[0].touch_ring_byte, \ (_params)->frame_list[0].touch_ring_max, \ (_params)->frame_list[0].touch_ring_flip_at, \ + (_params)->frame_list[0].bitmap_dial_byte, \ (_params)->frame_list[1].desc_ptr, \ (_params)->frame_list[1].desc_size, \ (_params)->frame_list[1].id, \ @@ -290,6 +301,7 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[1].touch_ring_byte, \ (_params)->frame_list[1].touch_ring_max, \ (_params)->frame_list[1].touch_ring_flip_at, \ + (_params)->frame_list[1].bitmap_dial_byte, \ (_params)->frame_list[2].desc_ptr, \ (_params)->frame_list[2].desc_size, \ (_params)->frame_list[2].id, \ @@ -298,7 +310,8 @@ extern int uclogic_params_init(struct uclogic_params *params, (_params)->frame_list[2].dev_id_byte, \ (_params)->frame_list[2].touch_ring_byte, \ (_params)->frame_list[2].touch_ring_max, \ - (_params)->frame_list[2].touch_ring_flip_at + (_params)->frame_list[2].touch_ring_flip_at, \ + (_params)->frame_list[2].bitmap_dial_byte /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, From 6facd076f5a9827800894c77a53d100c5f0a7d2f Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 14 Apr 2022 13:09:36 +0200 Subject: [PATCH 08/20] HID: uclogic: Add support for Huion Q620M MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Huion Q620M tablet needs a v2 frame dial. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 20 +++++++++++++ drivers/hid/hid-uclogic-rdesc.c | 50 ++++++++++++++++++++++++++++++++ drivers/hid/hid-uclogic-rdesc.h | 10 +++++++ 3 files changed, 80 insertions(+) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 3ac45e7572a0c..09c332c6a4121 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -777,6 +777,23 @@ static int uclogic_params_huion_init(struct uclogic_params *params, p.frame_list[1].touch_ring_max = 12; p.frame_list[1].touch_ring_flip_at = 6; + /* Create v2 frame dial parameters */ + rc = uclogic_params_frame_init_with_desc( + &p.frame_list[2], + uclogic_rdesc_v2_frame_dial_arr, + uclogic_rdesc_v2_frame_dial_size, + UCLOGIC_RDESC_V2_FRAME_DIAL_ID); + if (rc != 0) { + hid_err(hdev, + "failed creating v2 frame dial parameters: %d\n", + rc); + goto cleanup; + } + p.frame_list[2].suffix = "Dial"; + p.frame_list[2].dev_id_byte = + UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE; + p.frame_list[2].bitmap_dial_byte = 5; + /* * Link button and touch ring subreports from pen * reports @@ -787,6 +804,9 @@ static int uclogic_params_huion_init(struct uclogic_params *params, p.pen.subreport_list[1].value = 0xf0; p.pen.subreport_list[1].id = UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID; + p.pen.subreport_list[2].value = 0xf1; + p.pen.subreport_list[2].id = + UCLOGIC_RDESC_V2_FRAME_DIAL_ID; goto output; } hid_dbg(hdev, "pen v2 parameters not found\n"); diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index d64b607dce5d1..dd792160fe7ef 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -761,6 +761,56 @@ const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = { const size_t uclogic_rdesc_v2_frame_touch_ring_size = sizeof(uclogic_rdesc_v2_frame_touch_ring_arr); +/* Fixed report descriptor for (tweaked) v2 frame dial reports */ +const __u8 uclogic_rdesc_v2_frame_dial_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_V2_FRAME_DIAL_ID, + /* Report ID (DIAL_ID), */ + 0x14, /* Logical Minimum (0), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x39, /* Usage (Tablet Function Keys), */ + 0xA0, /* Collection (Physical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x09, 0x01, /* Usage (01h), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x38, /* Usage (Wheel), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0xFF, /* Logical Minimum (-1), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x2E, /* Report Count (46), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_v2_frame_dial_size = + sizeof(uclogic_rdesc_v2_frame_dial_arr); + /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index f15a9d8a946b3..2ab6b7d5f5af4 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -141,6 +141,16 @@ extern const size_t uclogic_rdesc_v2_frame_touch_ring_size; /* Device ID byte offset in v2 frame touch ring reports */ #define UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_DEV_ID_BYTE 0x4 +/* Report ID for tweaked v2 frame dial reports */ +#define UCLOGIC_RDESC_V2_FRAME_DIAL_ID 0xf9 + +/* Fixed report descriptor for (tweaked) v2 frame dial reports */ +extern const __u8 uclogic_rdesc_v2_frame_dial_arr[]; +extern const size_t uclogic_rdesc_v2_frame_dial_size; + +/* Device ID byte offset in v2 frame dial reports */ +#define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 + /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; extern const size_t uclogic_rdesc_ugee_ex07_frame_size; From 87dc28eb11ac2f52b8f73af061f9acd32fb895c3 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 21 Apr 2022 19:50:48 +0200 Subject: [PATCH 09/20] HID: uclogic: Clarify params desc_size description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation improvements. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index e5ccc558abc34..a489c92cee435 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -189,7 +189,7 @@ struct uclogic_params { __u8 *desc_ptr; /* * Size of the common part of the replacement report descriptor. - * Only valid, if "desc_ptr" is not NULL. + * Only valid, if "desc_ptr" is valid and not NULL. */ unsigned int desc_size; /* From 4933a722a05c99be124bc31fbcc750d7c0a04bc9 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 21 Apr 2022 19:50:49 +0200 Subject: [PATCH 10/20] HID: uclogic: Clarify pen/frame desc_ptr description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation improvements. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index a489c92cee435..fa75efba3130e 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -62,8 +62,8 @@ struct uclogic_params_pen_subreport { */ struct uclogic_params_pen { /* - * Pointer to report descriptor describing the inputs. - * Allocated with kmalloc. + * Pointer to report descriptor part describing the pen inputs. + * Allocated with kmalloc. NULL if the part is not specified. */ __u8 *desc_ptr; /* @@ -101,8 +101,8 @@ struct uclogic_params_pen { */ struct uclogic_params_frame { /* - * Pointer to report descriptor describing the inputs. - * Allocated with kmalloc. + * Pointer to report descriptor part describing the frame inputs. + * Allocated with kmalloc. NULL if the part is not specified. */ __u8 *desc_ptr; /* From d64a6e4460d6415df37590ecb76fad6bd5f2c8a6 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 21 Apr 2022 19:50:50 +0200 Subject: [PATCH 11/20] HID: uclogic: Pass keyboard reports as is MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow keyboard reports from interface #1 of Huion tablets to pass unmodified, and stop the Wacom X.org driver from handling them. The method for the latter is rather crude and also take the Dial reports from the Wacom driver, but it's expected that libinput will be able to handle them (still to be tested). This enables Huion HS611 media and desktop keys. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 09c332c6a4121..b85585ac33722 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -711,8 +711,12 @@ static int uclogic_params_huion_init(struct uclogic_params *params, iface = to_usb_interface(hdev->dev.parent); bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; - /* If it's not a pen interface */ - if (bInterfaceNumber != 0) { + /* If it's a custom keyboard interface */ + if (bInterfaceNumber == 1) { + /* Keep everything intact */ + goto output; + /* Else, if it's not a pen interface */ + } else if (bInterfaceNumber != 0) { uclogic_params_init_invalid(&p); goto output; } From f5927973f8d667eb93b81f796039c0ef94449866 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 21 Apr 2022 19:50:51 +0200 Subject: [PATCH 12/20] HID: uclogic: Support disabling pen usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore the ability to disable pen usage in hid-uclogic to support e.g. keyboard interfaces which also have pen usages for some reason, but which we don't want to rewrite report descriptors for. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 19 +++++++++++++++++++ drivers/hid/hid-uclogic-params.h | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 627f1d0c52f23..8ef3d18300523 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -81,6 +81,24 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, return rdesc; } +static int uclogic_input_mapping(struct hid_device *hdev, + struct hid_input *hi, + struct hid_field *field, + struct hid_usage *usage, + unsigned long **bit, + int *max) +{ + struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); + struct uclogic_params *params = &drvdata->params; + + /* Discard invalid pen usages */ + if (params->pen.usage_invalid && (field->application == HID_DG_PEN)) + return -1; + + /* Let hid-core decide what to do */ + return 0; +} + static int uclogic_input_configured(struct hid_device *hdev, struct hid_input *hi) { @@ -515,6 +533,7 @@ static struct hid_driver uclogic_driver = { .remove = uclogic_remove, .report_fixup = uclogic_report_fixup, .raw_event = uclogic_raw_event, + .input_mapping = uclogic_input_mapping, .input_configured = uclogic_input_configured, #ifdef CONFIG_PM .resume = uclogic_resume, diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index fa75efba3130e..fb2001018c461 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -61,6 +61,11 @@ struct uclogic_params_pen_subreport { * Noop (preserving functionality) when filled with zeroes. */ struct uclogic_params_pen { + /* + * True if pen usage is invalid for this interface and should be + * ignored, false otherwise. + */ + bool usage_invalid; /* * Pointer to report descriptor part describing the pen inputs. * Allocated with kmalloc. NULL if the part is not specified. @@ -214,6 +219,7 @@ extern int uclogic_params_init(struct uclogic_params *params, ".desc_ptr = %p\n" \ ".desc_size = %u\n" \ ".pen = {\n" \ + "\t.usage_invalid = %s\n" \ "\t.desc_ptr = %p\n" \ "\t.desc_size = %u\n" \ "\t.id = %u\n" \ @@ -270,6 +276,7 @@ extern int uclogic_params_init(struct uclogic_params *params, ((_params)->invalid ? "true" : "false"), \ (_params)->desc_ptr, \ (_params)->desc_size, \ + ((_params)->pen.usage_invalid ? "true" : "false"), \ (_params)->pen.desc_ptr, \ (_params)->pen.desc_size, \ (_params)->pen.id, \ From 4c60bc7d1f2a908f53260bc4a0831b3ea204f327 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Thu, 21 Apr 2022 19:50:52 +0200 Subject: [PATCH 13/20] HID: uclogic: Disable pen usage for Huion keyboard interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable pen usage inputs for Huion interfaces reporting on-the-frame buttons. We don't want to change those, as they mostly work, but we want to avoid creation of a mute pen interface, confusing to users. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index b85585ac33722..22f9c4f9da8a6 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -713,7 +713,8 @@ static int uclogic_params_huion_init(struct uclogic_params *params, /* If it's a custom keyboard interface */ if (bInterfaceNumber == 1) { - /* Keep everything intact */ + /* Keep everything intact, but mark pen usage invalid */ + p.pen.usage_invalid = true; goto output; /* Else, if it's not a pen interface */ } else if (bInterfaceNumber != 0) { From a228809fa6f39c3fa46ac6b929024686750f7a09 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:40 +0200 Subject: [PATCH 14/20] HID: uclogic: Move param printing to a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move parameter printing from a format string/argument list to a function to allow printing the full parameters, which now wouldn't fit into a single print call. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 4 +- drivers/hid/hid-uclogic-params.c | 89 +++++++++++++++++++++++- drivers/hid/hid-uclogic-params.h | 116 ++----------------------------- 3 files changed, 93 insertions(+), 116 deletions(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 8ef3d18300523..8cac5944e63fd 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -209,8 +209,8 @@ static int uclogic_probe(struct hid_device *hdev, goto failure; } params_initialized = true; - hid_dbg(hdev, "parameters:\n" UCLOGIC_PARAMS_FMT_STR, - UCLOGIC_PARAMS_FMT_ARGS(&drvdata->params)); + hid_dbg(hdev, "parameters:\n"); + uclogic_params_hid_dbg(hdev, &drvdata->params); if (drvdata->params.invalid) { hid_info(hdev, "interface is invalid, ignoring\n"); rc = -ENODEV; diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 22f9c4f9da8a6..1d9168cc7dc01 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -29,8 +29,8 @@ * Returns: * The string representing the type, or NULL if the type is unknown. */ -const char *uclogic_params_pen_inrange_to_str( - enum uclogic_params_pen_inrange inrange) +static const char *uclogic_params_pen_inrange_to_str( + enum uclogic_params_pen_inrange inrange) { switch (inrange) { case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL: @@ -44,6 +44,91 @@ const char *uclogic_params_pen_inrange_to_str( } } +/** + * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. + * + * @hdev: The HID device the pen parameters describe. + * @pen: The pen parameters to dump. + */ +static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, + const struct uclogic_params_pen *pen) +{ + size_t i; + + hid_dbg(hdev, "\t.usage_invalid = %s\n", + (pen->usage_invalid ? "true" : "false")); + hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr); + hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size); + hid_dbg(hdev, "\t.id = %u\n", pen->id); + hid_dbg(hdev, "\t.subreport_list = {\n"); + for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) { + hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n", + pen->subreport_list[i].value, + pen->subreport_list[i].id, + i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : ""); + } + hid_dbg(hdev, "\t}\n"); + hid_dbg(hdev, "\t.inrange = %s\n", + uclogic_params_pen_inrange_to_str(pen->inrange)); + hid_dbg(hdev, "\t.fragmented_hires = %s\n", + (pen->fragmented_hires ? "true" : "false")); + hid_dbg(hdev, "\t.tilt_y_flipped = %s\n", + (pen->tilt_y_flipped ? "true" : "false")); +} + +/** + * Dump tablet interface frame parameters with hid_dbg(), indented with two + * tabs. + * + * @hdev: The HID device the pen parameters describe. + * @frame: The frame parameters to dump. + */ +static void uclogic_params_frame_hid_dbg( + const struct hid_device *hdev, + const struct uclogic_params_frame *frame) +{ + hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr); + hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size); + hid_dbg(hdev, "\t\t.id = %u\n", frame->id); + hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix); + hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb); + hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte); + hid_dbg(hdev, "\t\t.touch_ring_byte = %u\n", frame->touch_ring_byte); + hid_dbg(hdev, "\t\t.touch_ring_max = %hhd\n", frame->touch_ring_max); + hid_dbg(hdev, "\t\t.touch_ring_flip_at = %hhd\n", + frame->touch_ring_flip_at); + hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n", + frame->bitmap_dial_byte); +} + +/** + * Dump tablet interface parameters with hid_dbg(). + * + * @hdev: The HID device the parameters describe. + * @params: The parameters to dump. + */ +void uclogic_params_hid_dbg(const struct hid_device *hdev, + const struct uclogic_params *params) +{ + size_t i; + + hid_dbg(hdev, ".invalid = %s\n", + params->invalid ? "true" : "false"); + hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr); + hid_dbg(hdev, ".desc_size = %u\n", params->desc_size); + hid_dbg(hdev, ".pen = {\n"); + uclogic_params_pen_hid_dbg(hdev, ¶ms->pen); + hid_dbg(hdev, "\t}\n"); + hid_dbg(hdev, ".frame_list = {\n"); + for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { + hid_dbg(hdev, "\t{\n"); + uclogic_params_frame_hid_dbg(hdev, ¶ms->frame_list[i]); + hid_dbg(hdev, "\t}%s\n", + i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : ""); + } + hid_dbg(hdev, "}\n"); +} + /** * uclogic_params_get_str_desc - retrieve a string descriptor from a HID * device interface, putting it into a kmalloc-allocated buffer as is, without diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index fb2001018c461..c7573f70d35c9 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -29,11 +29,6 @@ enum uclogic_params_pen_inrange { UCLOGIC_PARAMS_PEN_INRANGE_NONE, }; -/* Convert a pen in-range reporting type to a string */ -extern const char *uclogic_params_pen_inrange_to_str( - enum uclogic_params_pen_inrange inrange); - - /* * Pen report's subreport data. */ @@ -213,113 +208,6 @@ struct uclogic_params { extern int uclogic_params_init(struct uclogic_params *params, struct hid_device *hdev); -/* Tablet interface parameters *printf format string */ -#define UCLOGIC_PARAMS_FMT_STR \ - ".invalid = %s\n" \ - ".desc_ptr = %p\n" \ - ".desc_size = %u\n" \ - ".pen = {\n" \ - "\t.usage_invalid = %s\n" \ - "\t.desc_ptr = %p\n" \ - "\t.desc_size = %u\n" \ - "\t.id = %u\n" \ - "\t.subreport_list = {\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t\t{0x%02hhx, %hhu},\n" \ - "\t}\n" \ - "\t.inrange = %s\n" \ - "\t.fragmented_hires = %s\n" \ - "\t.tilt_y_flipped = %s\n" \ - "}\n" \ - ".frame_list = {\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t\t.bitmap_dial_byte = %u\n" \ - "\t},\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t\t.bitmap_dial_byte = %u\n" \ - "\t},\n" \ - "\t{\n" \ - "\t\t.desc_ptr = %p\n" \ - "\t\t.desc_size = %u\n" \ - "\t\t.id = %u\n" \ - "\t\t.suffix = %s\n" \ - "\t\t.re_lsb = %u\n" \ - "\t\t.dev_id_byte = %u\n" \ - "\t\t.touch_ring_byte = %u\n" \ - "\t\t.touch_ring_max = %hhd\n" \ - "\t\t.touch_ring_flip_at = %hhd\n" \ - "\t\t.bitmap_dial_byte = %u\n" \ - "\t},\n" \ - "}\n" - -/* Tablet interface parameters *printf format arguments */ -#define UCLOGIC_PARAMS_FMT_ARGS(_params) \ - ((_params)->invalid ? "true" : "false"), \ - (_params)->desc_ptr, \ - (_params)->desc_size, \ - ((_params)->pen.usage_invalid ? "true" : "false"), \ - (_params)->pen.desc_ptr, \ - (_params)->pen.desc_size, \ - (_params)->pen.id, \ - (_params)->pen.subreport_list[0].value, \ - (_params)->pen.subreport_list[0].id, \ - (_params)->pen.subreport_list[1].value, \ - (_params)->pen.subreport_list[1].id, \ - (_params)->pen.subreport_list[2].value, \ - (_params)->pen.subreport_list[2].id, \ - uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ - ((_params)->pen.fragmented_hires ? "true" : "false"), \ - ((_params)->pen.tilt_y_flipped ? "true" : "false"), \ - (_params)->frame_list[0].desc_ptr, \ - (_params)->frame_list[0].desc_size, \ - (_params)->frame_list[0].id, \ - (_params)->frame_list[0].suffix, \ - (_params)->frame_list[0].re_lsb, \ - (_params)->frame_list[0].dev_id_byte, \ - (_params)->frame_list[0].touch_ring_byte, \ - (_params)->frame_list[0].touch_ring_max, \ - (_params)->frame_list[0].touch_ring_flip_at, \ - (_params)->frame_list[0].bitmap_dial_byte, \ - (_params)->frame_list[1].desc_ptr, \ - (_params)->frame_list[1].desc_size, \ - (_params)->frame_list[1].id, \ - (_params)->frame_list[1].suffix, \ - (_params)->frame_list[1].re_lsb, \ - (_params)->frame_list[1].dev_id_byte, \ - (_params)->frame_list[1].touch_ring_byte, \ - (_params)->frame_list[1].touch_ring_max, \ - (_params)->frame_list[1].touch_ring_flip_at, \ - (_params)->frame_list[1].bitmap_dial_byte, \ - (_params)->frame_list[2].desc_ptr, \ - (_params)->frame_list[2].desc_size, \ - (_params)->frame_list[2].id, \ - (_params)->frame_list[2].suffix, \ - (_params)->frame_list[2].re_lsb, \ - (_params)->frame_list[2].dev_id_byte, \ - (_params)->frame_list[2].touch_ring_byte, \ - (_params)->frame_list[2].touch_ring_max, \ - (_params)->frame_list[2].touch_ring_flip_at, \ - (_params)->frame_list[2].bitmap_dial_byte - /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, __u8 **pdesc, @@ -328,4 +216,8 @@ extern int uclogic_params_get_desc(const struct uclogic_params *params, /* Free resources used by tablet interface's parameters */ extern void uclogic_params_cleanup(struct uclogic_params *params); +/* Dump tablet interface parameters with hid_dbg() */ +extern void uclogic_params_hid_dbg(const struct hid_device *hdev, + const struct uclogic_params *params); + #endif /* _HID_UCLOGIC_PARAMS_H */ From 945d5dd5a5f88b99c090d80948f589416e2ceb37 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:41 +0200 Subject: [PATCH 15/20] HID: uclogic: Return raw parameters from v2 pen init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return the raw parameters buffer from uclogic_params_pen_init_v2(), if requested, as a way to identify the tablet. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 92 ++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 1d9168cc7dc01..91379d7cd33e4 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -338,28 +338,45 @@ static s32 uclogic_params_get_le24(const void *p) * uclogic_params_pen_init_v2() - initialize tablet interface pen * input and retrieve its parameters from the device, using v2 protocol. * - * @pen: Pointer to the pen parameters to initialize (to be - * cleaned up with uclogic_params_pen_cleanup()). Not modified in - * case of error, or if parameters are not found. Cannot be NULL. - * @pfound: Location for a flag which is set to true if the parameters - * were found, and to false if not (e.g. device was - * incompatible). Not modified in case of error. Cannot be NULL. - * @hdev: The HID device of the tablet interface to initialize and get - * parameters from. Cannot be NULL. + * @pen: Pointer to the pen parameters to initialize (to be + * cleaned up with uclogic_params_pen_cleanup()). Not + * modified in case of error, or if parameters are not + * found. Cannot be NULL. + * @pfound: Location for a flag which is set to true if the + * parameters were found, and to false if not (e.g. + * device was incompatible). Not modified in case of + * error. Cannot be NULL. + * @pparams_ptr: Location for a kmalloc'ed pointer to the retrieved raw + * parameters, which could be used to identify the tablet + * to some extent. Should be freed with kfree after use. + * NULL, if not needed. Not modified in case of error. + * Only set if *pfound is set to true. + * @pparams_len: Location for the length of the retrieved raw + * parameters. NULL, if not needed. Not modified in case + * of error. Only set if *pfound is set to true. + * @hdev: The HID device of the tablet interface to initialize + * and get parameters from. Cannot be NULL. * * Returns: * Zero, if successful. A negative errno code on error. */ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, bool *pfound, + __u8 **pparams_ptr, + size_t *pparams_len, struct hid_device *hdev) { int rc; bool found = false; - /* Buffer for (part of) the string descriptor */ + /* Buffer for (part of) the parameter string descriptor */ __u8 *buf = NULL; - /* Descriptor length required */ - const int len = 18; + /* Parameter string descriptor required length */ + const int params_len_min = 18; + /* Parameter string descriptor accepted length */ + const int params_len_max = 32; + /* Parameter string descriptor received length */ + int params_len; + size_t i; s32 resolution; /* Pen report descriptor template parameters */ s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; @@ -377,7 +394,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, * the Windows driver traffic. * NOTE: This enables fully-functional tablet mode. */ - rc = uclogic_params_get_str_desc(&buf, hdev, 200, len); + rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max); if (rc == -EPIPE) { hid_dbg(hdev, "string descriptor with pen parameters not found, assuming not compatible\n"); @@ -385,27 +402,28 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, } else if (rc < 0) { hid_err(hdev, "failed retrieving pen parameters: %d\n", rc); goto cleanup; - } else if (rc != len) { + } else if (rc < params_len_min) { hid_dbg(hdev, - "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n", - rc, len); + "string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n", + rc, params_len_min); + goto finish; + } + + params_len = rc; + + /* + * Check it's not just a catch-all UTF-16LE-encoded ASCII + * string (such as the model name) some tablets put into all + * unknown string descriptors. + */ + for (i = 2; + i < params_len && + (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0); + i += 2); + if (i >= params_len) { + hid_dbg(hdev, + "string descriptor with pen parameters seems to contain only text, assuming not compatible\n"); goto finish; - } else { - size_t i; - /* - * Check it's not just a catch-all UTF-16LE-encoded ASCII - * string (such as the model name) some tablets put into all - * unknown string descriptors. - */ - for (i = 2; - i < len && - (buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0); - i += 2); - if (i >= len) { - hid_dbg(hdev, - "string descriptor with pen parameters seems to contain only text, assuming not compatible\n"); - goto finish; - } } /* @@ -429,8 +447,6 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / resolution; } - kfree(buf); - buf = NULL; /* * Generate pen report descriptor @@ -456,6 +472,13 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, pen->fragmented_hires = true; pen->tilt_y_flipped = true; found = true; + if (pparams_ptr != NULL) { + *pparams_ptr = buf; + buf = NULL; + } + if (pparams_len != NULL) + *pparams_len = params_len; + finish: *pfound = found; rc = 0; @@ -828,7 +851,8 @@ static int uclogic_params_huion_init(struct uclogic_params *params, "transition firmware detected, not probing pen v2 parameters\n"); } else { /* Try to probe v2 pen parameters */ - rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev); + rc = uclogic_params_pen_init_v2(&p.pen, &found, + NULL, NULL, hdev); if (rc != 0) { hid_err(hdev, "failed probing pen v2 parameters: %d\n", rc); From caf7e93479c73374a9fcad29f90477280444584e Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:42 +0200 Subject: [PATCH 16/20] HID: uclogic: Do not focus on touch ring only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Accommodate both touch ring and touch strip in naming throughout hid-uclogic by talking about abstract "touch" instead of "touch ring", wherever possible. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 20 +++++++++----------- drivers/hid/hid-uclogic-params.c | 20 ++++++++++---------- drivers/hid/hid-uclogic-params.h | 27 ++++++++++++++------------- drivers/hid/hid-uclogic-rdesc.c | 4 ++-- drivers/hid/hid-uclogic-rdesc.h | 8 ++++---- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index 8cac5944e63fd..cc53625ed1f74 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -134,7 +134,7 @@ static int uclogic_input_configured(struct hid_device *hdev, * Disable EV_MSC reports for touch ring interfaces to * make the Wacom driver pickup touch ring extents */ - if (frame->touch_ring_byte > 0) + if (frame->touch_byte > 0) __clear_bit(EV_MSC, hi->input->evbit); } } @@ -351,9 +351,8 @@ static int uclogic_raw_event_frame( /* If need to, and can, set pad device ID for Wacom drivers */ if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) { /* If we also have a touch ring and the finger left it */ - if (frame->touch_ring_byte > 0 && - frame->touch_ring_byte < size && - data[frame->touch_ring_byte] == 0) { + if (frame->touch_byte > 0 && frame->touch_byte < size && + data[frame->touch_byte] == 0) { data[frame->dev_id_byte] = 0; } else { data[frame->dev_id_byte] = 0xf; @@ -387,16 +386,15 @@ static int uclogic_raw_event_frame( } /* If need to, and can, transform the touch ring reports */ - if (frame->touch_ring_byte > 0 && frame->touch_ring_byte < size && - frame->touch_ring_flip_at != 0) { - __s8 value = data[frame->touch_ring_byte]; - + if (frame->touch_byte > 0 && frame->touch_byte < size && + frame->touch_flip_at != 0) { + __s8 value = data[frame->touch_byte]; if (value != 0) { - value = frame->touch_ring_flip_at - value; + value = frame->touch_flip_at - value; if (value < 0) - value = frame->touch_ring_max + value; + value = frame->touch_max + value; - data[frame->touch_ring_byte] = value; + data[frame->touch_byte] = value; } } diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 91379d7cd33e4..459f15288ccc1 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -93,10 +93,10 @@ static void uclogic_params_frame_hid_dbg( hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix); hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb); hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte); - hid_dbg(hdev, "\t\t.touch_ring_byte = %u\n", frame->touch_ring_byte); - hid_dbg(hdev, "\t\t.touch_ring_max = %hhd\n", frame->touch_ring_max); - hid_dbg(hdev, "\t\t.touch_ring_flip_at = %hhd\n", - frame->touch_ring_flip_at); + hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte); + hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max); + hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n", + frame->touch_flip_at); hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n", frame->bitmap_dial_byte); } @@ -877,7 +877,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, &p.frame_list[1], uclogic_rdesc_v2_frame_touch_ring_arr, uclogic_rdesc_v2_frame_touch_ring_size, - UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID); + UCLOGIC_RDESC_V2_FRAME_TOUCH_ID); if (rc != 0) { hid_err(hdev, "failed creating v2 frame touch ring parameters: %d\n", @@ -886,10 +886,10 @@ static int uclogic_params_huion_init(struct uclogic_params *params, } p.frame_list[1].suffix = "Touch Ring"; p.frame_list[1].dev_id_byte = - UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_DEV_ID_BYTE; - p.frame_list[1].touch_ring_byte = 5; - p.frame_list[1].touch_ring_max = 12; - p.frame_list[1].touch_ring_flip_at = 6; + UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; + p.frame_list[1].touch_byte = 5; + p.frame_list[1].touch_max = 12; + p.frame_list[1].touch_flip_at = 6; /* Create v2 frame dial parameters */ rc = uclogic_params_frame_init_with_desc( @@ -917,7 +917,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID; p.pen.subreport_list[1].value = 0xf0; p.pen.subreport_list[1].id = - UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID; + UCLOGIC_RDESC_V2_FRAME_TOUCH_ID; p.pen.subreport_list[2].value = 0xf1; p.pen.subreport_list[2].id = UCLOGIC_RDESC_V2_FRAME_DIAL_ID; diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index c7573f70d35c9..5bef8daaa6074 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -128,31 +128,32 @@ struct uclogic_params_frame { * Offset of the Wacom-style device ID byte in the report, to be set * to pad device ID (0xf), for compatibility with Wacom drivers. Zero * if no changes to the report should be made. The ID byte will be set - * to zero whenever the byte pointed by "touch_ring_byte" is zero, if + * to zero whenever the byte pointed by "touch_byte" is zero, if * the latter is valid. Only valid if "id" is not zero. */ unsigned int dev_id_byte; /* - * Offset of the touch ring state byte, in the report. + * Offset of the touch ring/strip state byte, in the report. * Zero if not present. If dev_id_byte is also valid and non-zero, * then the device ID byte will be cleared when the byte pointed to by * this offset is zero. Only valid if "id" is not zero. */ - unsigned int touch_ring_byte; - - /* - * Maximum value of the touch ring report. - * The minimum valid value is considered to be one, - * with zero being out-of-proximity (finger lift) value. - */ - __s8 touch_ring_max; - + unsigned int touch_byte; /* - * The value to anchor the reversed reports at. + * The value to anchor the reversed touch ring/strip reports at. * I.e. one, if the reports should be flipped without offset. * Zero if no reversal should be done. + * Only valid if "touch_byte" is valid and not zero. + */ + __s8 touch_flip_at; + /* + * Maximum value of the touch ring/strip report around which the value + * should be wrapped when flipping according to "touch_flip_at". + * The minimum valid value is considered to be one, with zero being + * out-of-proximity (finger lift) value. + * Only valid if "touch_flip_at" is valid and not zero. */ - __s8 touch_ring_flip_at; + __s8 touch_max; /* * Offset of the bitmap dial byte, in the report. Zero if not present. * Only valid if "id" is not zero. A bitmap dial sends reports with a diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index dd792160fe7ef..e2bd3a91e6fdf 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -718,8 +718,8 @@ const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ - 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID, - /* Report ID (DIAL_ID), */ + 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID, + /* Report ID (TOUCH_ID), */ 0x14, /* Logical Minimum (0), */ 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x39, /* Usage (Tablet Function Keys), */ diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 2ab6b7d5f5af4..b7bbaa70261e2 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -131,15 +131,15 @@ extern const size_t uclogic_rdesc_v1_frame_size; extern const __u8 uclogic_rdesc_v2_frame_buttons_arr[]; extern const size_t uclogic_rdesc_v2_frame_buttons_size; -/* Report ID for tweaked v2 frame touch ring reports */ -#define UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_ID 0xf8 +/* Report ID for tweaked v2 frame touch ring/strip reports */ +#define UCLOGIC_RDESC_V2_FRAME_TOUCH_ID 0xf8 /* Fixed report descriptor for (tweaked) v2 frame touch ring reports */ extern const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[]; extern const size_t uclogic_rdesc_v2_frame_touch_ring_size; -/* Device ID byte offset in v2 frame touch ring reports */ -#define UCLOGIC_RDESC_V2_FRAME_TOUCH_RING_DEV_ID_BYTE 0x4 +/* Device ID byte offset in v2 frame touch ring/strip reports */ +#define UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE 0x4 /* Report ID for tweaked v2 frame dial reports */ #define UCLOGIC_RDESC_V2_FRAME_DIAL_ID 0xf9 From fbc08b4e8ea5582029dc3c05c954d4d157e4d3f8 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:43 +0200 Subject: [PATCH 17/20] HID: uclogic: Always shift touch reports to zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always decrement touch report values to have the range start with zero, regardless if flipped or not. This fixes the future non-flipped touch strip reports. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-core.c | 15 ++++++++------- drivers/hid/hid-uclogic-params.c | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index cc53625ed1f74..c4ab94d58a0fb 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -386,15 +386,16 @@ static int uclogic_raw_event_frame( } /* If need to, and can, transform the touch ring reports */ - if (frame->touch_byte > 0 && frame->touch_byte < size && - frame->touch_flip_at != 0) { + if (frame->touch_byte > 0 && frame->touch_byte < size) { __s8 value = data[frame->touch_byte]; - if (value != 0) { - value = frame->touch_flip_at - value; - if (value < 0) - value = frame->touch_max + value; - data[frame->touch_byte] = value; + if (value != 0) { + if (frame->touch_flip_at != 0) { + value = frame->touch_flip_at - value; + if (value <= 0) + value = frame->touch_max + value; + } + data[frame->touch_byte] = value - 1; } } diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 459f15288ccc1..163efd026881c 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -889,7 +889,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; p.frame_list[1].touch_byte = 5; p.frame_list[1].touch_max = 12; - p.frame_list[1].touch_flip_at = 6; + p.frame_list[1].touch_flip_at = 7; /* Create v2 frame dial parameters */ rc = uclogic_params_frame_init_with_desc( From 118dfdeaa3c64c781d0219fd58a65dc31b97c3f5 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:44 +0200 Subject: [PATCH 18/20] HID: uclogic: Differentiate touch ring and touch strip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve support for touch strips. Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 84 +++++++++++++++++++++++--------- drivers/hid/hid-uclogic-rdesc.c | 48 ++++++++++++++++++ drivers/hid/hid-uclogic-rdesc.h | 4 ++ 3 files changed, 112 insertions(+), 24 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 163efd026881c..7db63bb77158e 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -808,6 +808,14 @@ static int uclogic_params_huion_init(struct uclogic_params *params, static const char transition_ver[] = "HUION_T153_160607"; char *ver_ptr = NULL; const size_t ver_len = sizeof(transition_ver) + 1; + __u8 *params_ptr = NULL; + size_t params_len = 0; + /* Parameters string descriptor of a model with touch ring (HS610) */ + const __u8 touch_ring_model_params_buf[] = { + 0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00, + 0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01, + 0x04, 0x3C, 0x3E + }; /* Check arguments */ if (params == NULL || hdev == NULL) { @@ -852,7 +860,8 @@ static int uclogic_params_huion_init(struct uclogic_params *params, } else { /* Try to probe v2 pen parameters */ rc = uclogic_params_pen_init_v2(&p.pen, &found, - NULL, NULL, hdev); + ¶ms_ptr, ¶ms_len, + hdev); if (rc != 0) { hid_err(hdev, "failed probing pen v2 parameters: %d\n", rc); @@ -872,24 +881,58 @@ static int uclogic_params_huion_init(struct uclogic_params *params, goto cleanup; } - /* Create v2 frame touch ring parameters */ - rc = uclogic_params_frame_init_with_desc( + /* Link from pen sub-report */ + p.pen.subreport_list[0].value = 0xe0; + p.pen.subreport_list[0].id = + UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID; + + /* If this is the model with touch ring */ + if (params_ptr != NULL && + params_len == sizeof(touch_ring_model_params_buf) && + memcmp(params_ptr, touch_ring_model_params_buf, + params_len) == 0) { + /* Create touch ring parameters */ + rc = uclogic_params_frame_init_with_desc( &p.frame_list[1], uclogic_rdesc_v2_frame_touch_ring_arr, uclogic_rdesc_v2_frame_touch_ring_size, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID); - if (rc != 0) { - hid_err(hdev, - "failed creating v2 frame touch ring parameters: %d\n", - rc); - goto cleanup; + if (rc != 0) { + hid_err(hdev, + "failed creating v2 frame touch ring parameters: %d\n", + rc); + goto cleanup; + } + p.frame_list[1].suffix = "Touch Ring"; + p.frame_list[1].dev_id_byte = + UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; + p.frame_list[1].touch_byte = 5; + p.frame_list[1].touch_max = 12; + p.frame_list[1].touch_flip_at = 7; + } else { + /* Create touch strip parameters */ + rc = uclogic_params_frame_init_with_desc( + &p.frame_list[1], + uclogic_rdesc_v2_frame_touch_strip_arr, + uclogic_rdesc_v2_frame_touch_strip_size, + UCLOGIC_RDESC_V2_FRAME_TOUCH_ID); + if (rc != 0) { + hid_err(hdev, + "failed creating v2 frame touch strip parameters: %d\n", + rc); + goto cleanup; + } + p.frame_list[1].suffix = "Touch Strip"; + p.frame_list[1].dev_id_byte = + UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; + p.frame_list[1].touch_byte = 5; + p.frame_list[1].touch_max = 8; } - p.frame_list[1].suffix = "Touch Ring"; - p.frame_list[1].dev_id_byte = - UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE; - p.frame_list[1].touch_byte = 5; - p.frame_list[1].touch_max = 12; - p.frame_list[1].touch_flip_at = 7; + + /* Link from pen sub-report */ + p.pen.subreport_list[1].value = 0xf0; + p.pen.subreport_list[1].id = + UCLOGIC_RDESC_V2_FRAME_TOUCH_ID; /* Create v2 frame dial parameters */ rc = uclogic_params_frame_init_with_desc( @@ -908,19 +951,11 @@ static int uclogic_params_huion_init(struct uclogic_params *params, UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE; p.frame_list[2].bitmap_dial_byte = 5; - /* - * Link button and touch ring subreports from pen - * reports - */ - p.pen.subreport_list[0].value = 0xe0; - p.pen.subreport_list[0].id = - UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID; - p.pen.subreport_list[1].value = 0xf0; - p.pen.subreport_list[1].id = - UCLOGIC_RDESC_V2_FRAME_TOUCH_ID; + /* Link from pen sub-report */ p.pen.subreport_list[2].value = 0xf1; p.pen.subreport_list[2].id = UCLOGIC_RDESC_V2_FRAME_DIAL_ID; + goto output; } hid_dbg(hdev, "pen v2 parameters not found\n"); @@ -961,6 +996,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, memset(&p, 0, sizeof(p)); rc = 0; cleanup: + kfree(params_ptr); kfree(ver_ptr); uclogic_params_cleanup(&p); return rc; diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index e2bd3a91e6fdf..3c3d4e8780dc9 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -761,6 +761,54 @@ const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[] = { const size_t uclogic_rdesc_v2_frame_touch_ring_size = sizeof(uclogic_rdesc_v2_frame_touch_ring_arr); +/* Fixed report descriptor for (tweaked) v2 frame touch strip reports */ +const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_V2_FRAME_TOUCH_ID, + /* Report ID (TOUCH_ID), */ + 0x14, /* Logical Minimum (0), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x39, /* Usage (Tablet Function Keys), */ + 0xA0, /* Collection (Physical), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x09, 0x01, /* Usage (01h), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x07, /* Report Count (7), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x0A, 0xFF, 0xFF, /* Usage (FFFFh), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x38, /* Usage (Wheel), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x07, /* Logical Maximum (7), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x2E, /* Report Count (46), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_v2_frame_touch_strip_size = + sizeof(uclogic_rdesc_v2_frame_touch_strip_arr); + /* Fixed report descriptor for (tweaked) v2 frame dial reports */ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index b7bbaa70261e2..0c6e95e8bde74 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -138,6 +138,10 @@ extern const size_t uclogic_rdesc_v2_frame_buttons_size; extern const __u8 uclogic_rdesc_v2_frame_touch_ring_arr[]; extern const size_t uclogic_rdesc_v2_frame_touch_ring_size; +/* Fixed report descriptor for (tweaked) v2 frame touch strip reports */ +extern const __u8 uclogic_rdesc_v2_frame_touch_strip_arr[]; +extern const size_t uclogic_rdesc_v2_frame_touch_strip_size; + /* Device ID byte offset in v2 frame touch ring/strip reports */ #define UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE 0x4 From 61b1db5a14b7651e808176c17d629114763c3641 Mon Sep 17 00:00:00 2001 From: Roman Romanenko Date: Sun, 8 May 2022 18:01:45 +0200 Subject: [PATCH 19/20] HID: uclogic: Add pen support for XP-PEN Star 06 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to other UGEE pens, but the IDs were missing. Signed-off-by: Roman Romanenko Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-uclogic-core.c | 2 ++ drivers/hid/hid-uclogic-params.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 053853a891c50..f8b3774a3a105 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1272,6 +1272,7 @@ #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 #define USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720 0x0055 diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index c4ab94d58a0fb..c0fe66e50c58d 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -521,6 +521,8 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, { } }; MODULE_DEVICE_TABLE(hid, uclogic_devices); diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index 7db63bb77158e..db838f16282d6 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1195,6 +1195,8 @@ int uclogic_params_init(struct uclogic_params *params, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640): + case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06): case VID_PID(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720): /* If this is the pen interface */ From f7d8e387d9aeff963e6691c0166269b8042b4ff9 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov Date: Sun, 8 May 2022 18:01:46 +0200 Subject: [PATCH 20/20] HID: uclogic: Switch to Digitizer usage for styluses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The (incorrect) "Pen" (0x02) application usage used in replacement report descriptors throughout the drivers leads to all tablets recognized as a "direct" input device (i.e. a tablet monitor) by recent kernels, which messes up desktop environments [1]. Replace the application usage with "Digitizer" (0x01) for each non-display graphics tablet. [1] https://lore.kernel.org/linux-input/f39ce5d5-bd5b-bd3f-3ea2-9b2a89ba1eb1@gmail.com/ Signed-off-by: Nikolai Kondrashov Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-kye.c | 12 ++++++------ drivers/hid/hid-uclogic-rdesc.c | 18 +++++++++--------- drivers/hid/hid-viewsonic.c | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c index f46616390a984..da903138eee49 100644 --- a/drivers/hid/hid-kye.c +++ b/drivers/hid/hid-kye.c @@ -33,7 +33,7 @@ static __u8 easypen_i405x_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -91,7 +91,7 @@ static __u8 mousepen_i608x_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -190,7 +190,7 @@ static __u8 mousepen_i608x_v2_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -289,7 +289,7 @@ static __u8 easypen_m610x_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -368,7 +368,7 @@ static __u8 pensketch_m912_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -497,7 +497,7 @@ static __u8 easypen_m406xe_rdesc_fixed[] = { 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x10, /* Report ID (16), */ 0x09, 0x20, /* Usage (Stylus), */ diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 3c3d4e8780dc9..13f9ce73f1b16 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -21,7 +21,7 @@ /* Fixed WP4030U report descriptor */ __u8 uclogic_rdesc_wp4030u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -66,7 +66,7 @@ const size_t uclogic_rdesc_wp4030u_fixed_size = /* Fixed WP5540U report descriptor */ __u8 uclogic_rdesc_wp5540u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -143,7 +143,7 @@ const size_t uclogic_rdesc_wp5540u_fixed_size = /* Fixed WP8060U report descriptor */ __u8 uclogic_rdesc_wp8060u_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -220,7 +220,7 @@ const size_t uclogic_rdesc_wp8060u_fixed_size = /* Fixed WP1062 report descriptor */ __u8 uclogic_rdesc_wp1062_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -268,7 +268,7 @@ const size_t uclogic_rdesc_wp1062_fixed_size = /* Fixed PF1209 report descriptor */ __u8 uclogic_rdesc_pf1209_fixed_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -345,7 +345,7 @@ const size_t uclogic_rdesc_pf1209_fixed_size = /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */ __u8 uclogic_rdesc_twhl850_fixed0_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -457,7 +457,7 @@ const size_t uclogic_rdesc_twhl850_fixed2_size = /* Fixed TWHA60 report descriptor, interface 0 (stylus) */ __u8 uclogic_rdesc_twha60_fixed0_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x09, /* Report ID (9), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -534,7 +534,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size = /* Fixed report descriptor template for (tweaked) v1 pen reports */ const __u8 uclogic_rdesc_v1_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x07, /* Report ID (7), */ 0x09, 0x20, /* Usage (Stylus), */ @@ -588,7 +588,7 @@ const size_t uclogic_rdesc_v1_pen_template_size = /* Fixed report descriptor template for (tweaked) v2 pen reports */ const __u8 uclogic_rdesc_v2_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x08, /* Report ID (8), */ 0x09, 0x20, /* Usage (Stylus), */ diff --git a/drivers/hid/hid-viewsonic.c b/drivers/hid/hid-viewsonic.c index df60c8fc2efd8..8024b1d370e25 100644 --- a/drivers/hid/hid-viewsonic.c +++ b/drivers/hid/hid-viewsonic.c @@ -24,7 +24,7 @@ /* Fixed report descriptor of PD1011 signature pad */ static __u8 pd1011_rdesc_fixed[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ - 0x09, 0x02, /* Usage (Pen), */ + 0x09, 0x01, /* Usage (Digitizer), */ 0xA1, 0x01, /* Collection (Application), */ 0x85, 0x02, /* Report ID (2), */ 0x09, 0x20, /* Usage (Stylus), */