diff options
author | Jiri Kosina <jkosina@suse.cz> | 2022-03-23 10:10:56 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2022-03-23 10:11:39 +0100 |
commit | b146dbbd3bc61678165f3de7904ab613865385ba (patch) | |
tree | ea3a63babcd9dc01af8065c33a217326a46166d7 /drivers/hid | |
parent | Merge branch 'for-5.18/sigma-micro' into for-linus (diff) | |
parent | HID: uclogic: Support multiple frame input devices (diff) | |
download | linux-b146dbbd3bc61678165f3de7904ab613865385ba.tar.xz linux-b146dbbd3bc61678165f3de7904ab613865385ba.zip |
Merge branch 'for-5.18/uclogic' into for-linus
- integration of first part of DIGImend [1] patches in order to vastly
improve Linux support of tablets (Nikolai Kondrashov, José Expósito)
[1] https://github.com/DIGImend/digimend-kernel-drivers
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/hid-ids.h | 2 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-core.c | 258 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-params.c | 198 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-params.h | 92 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-rdesc.c | 69 | ||||
-rw-r--r-- | drivers/hid/hid-uclogic-rdesc.h | 38 |
6 files changed, 358 insertions, 299 deletions
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index afd3a3e118a4..053853a891c5 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -614,7 +614,7 @@ #define USB_VENDOR_ID_HUION 0x256c #define USB_DEVICE_ID_HUION_TABLET 0x006e -#define USB_DEVICE_ID_HUION_HS64 0x006d +#define USB_DEVICE_ID_HUION_TABLET2 0x006d #define USB_VENDOR_ID_IBM 0x04b3 #define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100 diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index d8ab0139e5cd..05147f2d7564 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -81,24 +81,6 @@ 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 the unused pen interface */ - if (params->pen_unused && (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) { @@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev) } #endif +/** + * uclogic_raw_event_pen - handle raw pen events (pen HID reports). + * + * @drvdata: Driver data. + * @data: Report data buffer, can be modified. + * @size: Report data size, bytes. + * + * Returns: + * Negative value on error (stops event delivery), zero for success. + */ +static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata, + u8 *data, int size) +{ + struct uclogic_params_pen *pen = &drvdata->params.pen; + + WARN_ON(drvdata == NULL); + WARN_ON(data == NULL && size != 0); + + /* If in-range reports are inverted */ + if (pen->inrange == + UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) { + /* Invert the in-range bit */ + data[1] ^= 0x40; + } + /* + * If report contains fragmented high-resolution pen + * coordinates + */ + if (size >= 10 && pen->fragmented_hires) { + u8 pressure_low_byte; + u8 pressure_high_byte; + + /* Lift pressure bytes */ + pressure_low_byte = data[6]; + pressure_high_byte = data[7]; + /* + * Move Y coord to make space for high-order X + * coord byte + */ + data[6] = data[5]; + data[5] = data[4]; + /* Move high-order X coord byte */ + data[4] = data[8]; + /* Move high-order Y coord byte */ + data[7] = data[9]; + /* Place pressure bytes */ + data[8] = pressure_low_byte; + data[9] = pressure_high_byte; + } + /* If we need to emulate in-range detection */ + if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) { + /* Set in-range bit */ + data[1] |= 0x40; + /* (Re-)start in-range timeout */ + mod_timer(&drvdata->inrange_timer, + jiffies + msecs_to_jiffies(100)); + } + /* If we report tilt and Y direction is flipped */ + if (size >= 12 && pen->tilt_y_flipped) + data[11] = -data[11]; + + return 0; +} + +/** + * uclogic_raw_event_frame - handle raw frame events (frame HID reports). + * + * @drvdata: Driver data. + * @frame: The parameters of the frame controls to handle. + * @data: Report data buffer, can be modified. + * @size: Report data size, bytes. + * + * Returns: + * Negative value on error (stops event delivery), zero for success. + */ +static int uclogic_raw_event_frame( + struct uclogic_drvdata *drvdata, + const struct uclogic_params_frame *frame, + u8 *data, int size) +{ + WARN_ON(drvdata == NULL); + WARN_ON(data == NULL && size != 0); + + /* 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 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; + unsigned int bit = frame->re_lsb % 8; + + u8 change; + u8 prev_state = drvdata->re_state; + /* Read Gray-coded state */ + u8 state = (data[byte] >> bit) & 0x3; + /* Encode state change into 2-bit signed integer */ + if ((prev_state == 1 && state == 0) || + (prev_state == 2 && state == 3)) { + change = 1; + } else if ((prev_state == 2 && state == 0) || + (prev_state == 1 && state == 3)) { + change = 3; + } else { + change = 0; + } + /* Write change */ + data[byte] = (data[byte] & ~((u8)3 << bit)) | + (change << bit); + /* Remember state */ + drvdata->re_state = state; + } + + return 0; +} + static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { + unsigned int report_id = report->id; struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev); struct uclogic_params *params = &drvdata->params; + struct uclogic_params_pen_subreport *subreport; + struct uclogic_params_pen_subreport *subreport_list_end; + size_t i; - /* Tweak pen reports, if necessary */ - if (!params->pen_unused && - (report->type == HID_INPUT_REPORT) && - (report->id == params->pen.id) && - (size >= 2)) { - /* If it's the "virtual" frame controls report */ - if (params->frame.id != 0 && - data[1] & params->pen_frame_flag) { - /* Change to virtual frame controls report ID */ - data[0] = params->frame.id; - return 0; - } - /* If in-range reports are inverted */ - if (params->pen.inrange == - UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) { - /* Invert the in-range bit */ - data[1] ^= 0x40; - } - /* - * If report contains fragmented high-resolution pen - * coordinates - */ - if (size >= 10 && params->pen.fragmented_hires) { - u8 pressure_low_byte; - u8 pressure_high_byte; - - /* Lift pressure bytes */ - pressure_low_byte = data[6]; - pressure_high_byte = data[7]; - /* - * Move Y coord to make space for high-order X - * coord byte - */ - data[6] = data[5]; - data[5] = data[4]; - /* Move high-order X coord byte */ - data[4] = data[8]; - /* Move high-order Y coord byte */ - data[7] = data[9]; - /* Place pressure bytes */ - data[8] = pressure_low_byte; - data[9] = pressure_high_byte; - } - /* If we need to emulate in-range detection */ - if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) { - /* Set in-range bit */ - data[1] |= 0x40; - /* (Re-)start in-range timeout */ - mod_timer(&drvdata->inrange_timer, - jiffies + msecs_to_jiffies(100)); - } - } + /* Do not handle anything but input reports */ + if (report->type != HID_INPUT_REPORT) + return 0; - /* Tweak frame control reports, if necessary */ - if ((report->type == HID_INPUT_REPORT) && - (report->id == params->frame.id)) { - /* If need to, and can, set pad device ID for Wacom drivers */ - if (params->frame.dev_id_byte > 0 && - params->frame.dev_id_byte < size) { - data[params->frame.dev_id_byte] = 0xf; - } - /* If need to, and can, read rotary encoder state change */ - if (params->frame.re_lsb > 0 && - params->frame.re_lsb / 8 < size) { - unsigned int byte = params->frame.re_lsb / 8; - unsigned int bit = params->frame.re_lsb % 8; - - u8 change; - u8 prev_state = drvdata->re_state; - /* Read Gray-coded state */ - u8 state = (data[byte] >> bit) & 0x3; - /* Encode state change into 2-bit signed integer */ - if ((prev_state == 1 && state == 0) || - (prev_state == 2 && state == 3)) { - change = 1; - } else if ((prev_state == 2 && state == 0) || - (prev_state == 1 && state == 3)) { - change = 3; + while (true) { + /* Tweak pen reports, if necessary */ + if ((report_id == params->pen.id) && (size >= 2)) { + subreport_list_end = + params->pen.subreport_list + + ARRAY_SIZE(params->pen.subreport_list); + /* Try to match a subreport */ + for (subreport = params->pen.subreport_list; + subreport < subreport_list_end; subreport++) { + if (subreport->value != 0 && + subreport->value == data[1]) { + break; + } + } + /* If a subreport matched */ + if (subreport < subreport_list_end) { + /* Change to subreport ID, and restart */ + report_id = data[0] = subreport->id; + continue; } else { - change = 0; + return uclogic_raw_event_pen(drvdata, data, size); + } + } + + /* Tweak frame control reports, if necessary */ + for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { + if (report_id == params->frame_list[i].id) { + return uclogic_raw_event_frame( + drvdata, ¶ms->frame_list[i], + data, size); } - /* Write change */ - data[byte] = (data[byte] & ~((u8)3 << bit)) | - (change << bit); - /* Remember state */ - drvdata->re_state = state; } + + break; } return 0; @@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_HUION, - USB_DEVICE_ID_HUION_HS64) }, + USB_DEVICE_ID_HUION_TABLET2) }, { HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, @@ -415,7 +468,6 @@ 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.c b/drivers/hid/hid-uclogic-params.c index 3e70f969fb84..5f50ceb875d6 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, * Generate pen report descriptor */ desc_ptr = uclogic_rdesc_template_apply( - uclogic_rdesc_pen_v1_template_arr, - uclogic_rdesc_pen_v1_template_size, + uclogic_rdesc_v1_pen_template_arr, + uclogic_rdesc_v1_pen_template_size, desc_params, ARRAY_SIZE(desc_params)); if (desc_ptr == NULL) { rc = -ENOMEM; @@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, memset(pen, 0, sizeof(*pen)); pen->desc_ptr = desc_ptr; desc_ptr = NULL; - pen->desc_size = uclogic_rdesc_pen_v1_template_size; - pen->id = UCLOGIC_RDESC_PEN_V1_ID; + pen->desc_size = uclogic_rdesc_v1_pen_template_size; + pen->id = UCLOGIC_RDESC_V1_PEN_ID; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED; found = true; finish: @@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, * Generate pen report descriptor */ desc_ptr = uclogic_rdesc_template_apply( - uclogic_rdesc_pen_v2_template_arr, - uclogic_rdesc_pen_v2_template_size, + uclogic_rdesc_v2_pen_template_arr, + uclogic_rdesc_v2_pen_template_size, desc_params, ARRAY_SIZE(desc_params)); if (desc_ptr == NULL) { rc = -ENOMEM; @@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, memset(pen, 0, sizeof(*pen)); pen->desc_ptr = desc_ptr; desc_ptr = NULL; - pen->desc_size = uclogic_rdesc_pen_v2_template_size; - pen->id = UCLOGIC_RDESC_PEN_V2_ID; + pen->desc_size = uclogic_rdesc_v2_pen_template_size; + pen->id = UCLOGIC_RDESC_V2_PEN_ID; pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE; pen->fragmented_hires = true; + pen->tilt_y_flipped = true; found = true; finish: *pfound = found; @@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc( } /** - * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad - * on a v1 tablet interface. + * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame + * controls. * * @frame: Pointer to the frame parameters to initialize (to be cleaned * up with uclogic_params_frame_cleanup()). Not modified in case @@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc( * Returns: * Zero, if successful. A negative errno code on error. */ -static int uclogic_params_frame_init_v1_buttonpad( - struct uclogic_params_frame *frame, +static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame, bool *pfound, struct hid_device *hdev) { @@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad( hid_dbg(hdev, "generic buttons enabled\n"); rc = uclogic_params_frame_init_with_desc( frame, - uclogic_rdesc_buttonpad_v1_arr, - uclogic_rdesc_buttonpad_v1_size, - UCLOGIC_RDESC_BUTTONPAD_V1_ID); + uclogic_rdesc_v1_frame_arr, + uclogic_rdesc_v1_frame_size, + UCLOGIC_RDESC_V1_FRAME_ID); if (rc != 0) goto cleanup; found = true; @@ -512,10 +512,12 @@ cleanup: void uclogic_params_cleanup(struct uclogic_params *params) { if (!params->invalid) { + size_t i; kfree(params->desc_ptr); - if (!params->pen_unused) - uclogic_params_pen_cleanup(¶ms->pen); - uclogic_params_frame_cleanup(¶ms->frame); + uclogic_params_pen_cleanup(¶ms->pen); + for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) + uclogic_params_frame_cleanup(¶ms->frame_list[i]); + memset(params, 0, sizeof(*params)); } } @@ -543,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params, __u8 **pdesc, unsigned int *psize) { - bool common_present; - bool pen_present; - bool frame_present; - unsigned int size; + int rc = -ENOMEM; + bool present = false; + unsigned int size = 0; __u8 *desc = NULL; + size_t i; /* Check arguments */ if (params == NULL || pdesc == NULL || psize == NULL) return -EINVAL; - size = 0; - - common_present = (params->desc_ptr != NULL); - pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL); - frame_present = (params->frame.desc_ptr != NULL); - - if (common_present) - size += params->desc_size; - if (pen_present) - size += params->pen.desc_size; - if (frame_present) - size += params->frame.desc_size; - - if (common_present || pen_present || frame_present) { - __u8 *p; - - desc = kmalloc(size, GFP_KERNEL); - if (desc == NULL) - return -ENOMEM; - p = desc; - - if (common_present) { - memcpy(p, params->desc_ptr, - params->desc_size); - p += params->desc_size; - } - if (pen_present) { - memcpy(p, params->pen.desc_ptr, - params->pen.desc_size); - p += params->pen.desc_size; - } - if (frame_present) { - memcpy(p, params->frame.desc_ptr, - params->frame.desc_size); - p += params->frame.desc_size; - } + /* Concatenate descriptors */ +#define ADD_DESC(_desc_ptr, _desc_size) \ + do { \ + unsigned int new_size; \ + __u8 *new_desc; \ + if ((_desc_ptr) == NULL) { \ + break; \ + } \ + new_size = size + (_desc_size); \ + new_desc = krealloc(desc, new_size, GFP_KERNEL); \ + if (new_desc == NULL) { \ + goto cleanup; \ + } \ + memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \ + desc = new_desc; \ + size = new_size; \ + present = true; \ + } while (0) + + ADD_DESC(params->desc_ptr, params->desc_size); + ADD_DESC(params->pen.desc_ptr, params->pen.desc_size); + for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) { + ADD_DESC(params->frame_list[i].desc_ptr, + params->frame_list[i].desc_size); + } - WARN_ON(p != desc + size); +#undef ADD_DESC + if (present) { + *pdesc = desc; *psize = size; + desc = NULL; } - - *pdesc = desc; - return 0; + rc = 0; +cleanup: + kfree(desc); + return rc; } /** @@ -680,21 +675,6 @@ cleanup: } /** - * uclogic_params_init_with_pen_unused() - initialize tablet interface - * parameters preserving original reports and generic HID processing, but - * disabling pen usage. - * - * @params: Parameters to initialize (to be cleaned with - * uclogic_params_cleanup()). Not modified in case of - * error. Cannot be NULL. - */ -static void uclogic_params_init_with_pen_unused(struct uclogic_params *params) -{ - memset(params, 0, sizeof(*params)); - params->pen_unused = true; -} - -/** * uclogic_params_huion_init() - initialize a Huion tablet interface and discover * its parameters. * @@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params, /* If it's not a pen interface */ if (bInterfaceNumber != 0) { - /* TODO: Consider marking the interface invalid */ - uclogic_params_init_with_pen_unused(&p); + uclogic_params_init_invalid(&p); goto output; } @@ -766,20 +745,22 @@ 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 buttonpad parameters */ + /* Create v2 frame parameters */ rc = uclogic_params_frame_init_with_desc( - &p.frame, - uclogic_rdesc_buttonpad_v2_arr, - uclogic_rdesc_buttonpad_v2_size, - UCLOGIC_RDESC_BUTTONPAD_V2_ID); + &p.frame_list[0], + uclogic_rdesc_v2_frame_arr, + uclogic_rdesc_v2_frame_size, + UCLOGIC_RDESC_V2_FRAME_ID); if (rc != 0) { hid_err(hdev, - "failed creating v2 buttonpad parameters: %d\n", + "failed creating v2 frame parameters: %d\n", rc); goto cleanup; } - /* Set bitmask marking frame reports in pen reports */ - p.pen_frame_flag = 0x20; + /* Link frame button subreports from pen reports */ + p.pen.subreport_list[0].value = 0xe0; + p.pen.subreport_list[0].id = + UCLOGIC_RDESC_V2_FRAME_ID; goto output; } hid_dbg(hdev, "pen v2 parameters not found\n"); @@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params, goto cleanup; } else if (found) { hid_dbg(hdev, "pen v1 parameters found\n"); - /* Try to probe v1 buttonpad */ - rc = uclogic_params_frame_init_v1_buttonpad( - &p.frame, - &found, hdev); + /* Try to probe v1 frame */ + rc = uclogic_params_frame_init_v1(&p.frame_list[0], + &found, hdev); if (rc != 0) { - hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc); + hid_err(hdev, "v1 frame probing failed: %d\n", rc); goto cleanup; } - hid_dbg(hdev, "buttonpad v1 parameters%s found\n", + hid_dbg(hdev, "frame v1 parameters%s found\n", (found ? "" : " not")); if (found) { - /* Set bitmask marking frame reports */ - p.pen_frame_flag = 0x20; + /* Link frame button subreports from pen reports */ + p.pen.subreport_list[0].value = 0xe0; + p.pen.subreport_list[0].id = + UCLOGIC_RDESC_V1_FRAME_ID; } goto output; } @@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params, case VID_PID(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_HUION, - USB_DEVICE_ID_HUION_HS64): + USB_DEVICE_ID_HUION_TABLET2): case VID_PID(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET): case VID_PID(USB_VENDOR_ID_UCLOGIC, @@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params, uclogic_params_init_invalid(&p); } } else { - /* TODO: Consider marking the interface invalid */ - uclogic_params_init_with_pen_unused(&p); + uclogic_params_init_invalid(&p); } break; case VID_PID(USB_VENDOR_ID_UGEE, @@ -1048,15 +1029,14 @@ int uclogic_params_init(struct uclogic_params *params, } /* Initialize frame parameters */ rc = uclogic_params_frame_init_with_desc( - &p.frame, + &p.frame_list[0], uclogic_rdesc_xppen_deco01_frame_arr, uclogic_rdesc_xppen_deco01_frame_size, 0); if (rc != 0) goto cleanup; } else { - /* TODO: Consider marking the interface invalid */ - uclogic_params_init_with_pen_unused(&p); + uclogic_params_init_invalid(&p); } break; case VID_PID(USB_VENDOR_ID_TRUST, @@ -1075,19 +1055,19 @@ int uclogic_params_init(struct uclogic_params *params, goto cleanup; } else if (found) { rc = uclogic_params_frame_init_with_desc( - &p.frame, + &p.frame_list[0], uclogic_rdesc_ugee_g5_frame_arr, uclogic_rdesc_ugee_g5_frame_size, UCLOGIC_RDESC_UGEE_G5_FRAME_ID); if (rc != 0) { hid_err(hdev, - "failed creating buttonpad parameters: %d\n", + "failed creating frame parameters: %d\n", rc); goto cleanup; } - p.frame.re_lsb = + p.frame_list[0].re_lsb = UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB; - p.frame.dev_id_byte = + p.frame_list[0].dev_id_byte = UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE; } else { hid_warn(hdev, "pen parameters not found"); @@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params, goto cleanup; } else if (found) { rc = uclogic_params_frame_init_with_desc( - &p.frame, - uclogic_rdesc_ugee_ex07_buttonpad_arr, - uclogic_rdesc_ugee_ex07_buttonpad_size, + &p.frame_list[0], + uclogic_rdesc_ugee_ex07_frame_arr, + uclogic_rdesc_ugee_ex07_frame_size, 0); if (rc != 0) { hid_err(hdev, - "failed creating buttonpad parameters: %d\n", + "failed creating frame parameters: %d\n", rc); goto cleanup; } diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h index ba48b1c7a0e5..86f616dfbb53 100644 --- a/drivers/hid/hid-uclogic-params.h +++ b/drivers/hid/hid-uclogic-params.h @@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange { extern const char *uclogic_params_pen_inrange_to_str( enum uclogic_params_pen_inrange inrange); + +/* + * Pen report's subreport data. + */ +struct uclogic_params_pen_subreport { + /* + * The value of the second byte of the pen report indicating this + * subreport. If zero, the subreport should be considered invalid and + * not matched. + */ + __u8 value; + + /* + * The ID to be assigned to the report, if the second byte of the pen + * report is equal to "value". Only valid if "value" is not zero. + */ + __u8 id; +}; + /* * Tablet interface's pen input parameters. * @@ -54,6 +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]; /* Type of in-range reporting, only valid if "id" is not zero */ enum uclogic_params_pen_inrange inrange; /* @@ -62,6 +83,12 @@ struct uclogic_params_pen { * Only valid if "id" is not zero. */ bool fragmented_hires; + /* + * True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y), + * and the Y tilt direction is flipped. + * Only valid if "id" is not zero. + */ + bool tilt_y_flipped; }; /* @@ -133,27 +160,15 @@ struct uclogic_params { */ unsigned int desc_size; /* - * True, if pen usage in report descriptor is invalid, when present. - * Only valid, if "invalid" is false. - */ - bool pen_unused; - /* * Pen parameters and optional report descriptor part. - * Only valid if "pen_unused" is valid and false. - */ - struct uclogic_params_pen pen; - /* - * Frame control parameters and optional report descriptor part. * Only valid, if "invalid" is false. */ - struct uclogic_params_frame frame; + struct uclogic_params_pen pen; /* - * Bitmask matching frame controls "sub-report" flag in the second - * byte of the pen report, or zero if it's not expected. - * Only valid if both "pen" and "frame" are valid, and "frame.id" is - * not zero. + * The list of frame control parameters and optional report descriptor + * parts. Only valid, if "invalid" is false. */ - __u8 pen_frame_flag; + struct uclogic_params_frame frame_list[1]; }; /* Initialize a tablet interface and discover its parameters */ @@ -162,39 +177,40 @@ 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_unused = %s\n" \ - ".pen.desc_ptr = %p\n" \ - ".pen.desc_size = %u\n" \ - ".pen.id = %u\n" \ - ".pen.inrange = %s\n" \ - ".pen.fragmented_hires = %s\n" \ - ".frame.desc_ptr = %p\n" \ - ".frame.desc_size = %u\n" \ - ".frame.id = %u\n" \ - ".frame.re_lsb = %u\n" \ - ".frame.dev_id_byte = %u\n" \ - ".pen_frame_flag = 0x%02x\n" + ".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.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].re_lsb = %u\n" \ + ".frame_list[0].dev_id_byte = %u\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_unused ? "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, \ uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \ ((_params)->pen.fragmented_hires ? "true" : "false"), \ - (_params)->frame.desc_ptr, \ - (_params)->frame.desc_size, \ - (_params)->frame.id, \ - (_params)->frame.re_lsb, \ - (_params)->frame.dev_id_byte, \ - (_params)->pen_frame_flag + ((_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].re_lsb, \ + (_params)->frame_list[0].dev_id_byte /* Get a replacement report descriptor for a tablet's interface. */ extern int uclogic_params_get_desc(const struct uclogic_params *params, diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 6dd6dcd09c8b..04644d93bd11 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -532,7 +532,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size = sizeof(uclogic_rdesc_twha60_fixed1_arr); /* Fixed report descriptor template for (tweaked) v1 pen reports */ -const __u8 uclogic_rdesc_pen_v1_template_arr[] = { +const __u8 uclogic_rdesc_v1_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x02, /* Usage (Pen), */ 0xA1, 0x01, /* Collection (Application), */ @@ -582,11 +582,11 @@ const __u8 uclogic_rdesc_pen_v1_template_arr[] = { 0xC0 /* End Collection */ }; -const size_t uclogic_rdesc_pen_v1_template_size = - sizeof(uclogic_rdesc_pen_v1_template_arr); +const size_t uclogic_rdesc_v1_pen_template_size = + sizeof(uclogic_rdesc_v1_pen_template_arr); /* Fixed report descriptor template for (tweaked) v2 pen reports */ -const __u8 uclogic_rdesc_pen_v2_template_arr[] = { +const __u8 uclogic_rdesc_v2_pen_template_arr[] = { 0x05, 0x0D, /* Usage Page (Digitizer), */ 0x09, 0x02, /* Usage (Pen), */ 0xA1, 0x01, /* Collection (Application), */ @@ -633,25 +633,35 @@ const __u8 uclogic_rdesc_pen_v2_template_arr[] = { 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), /* Logical Maximum (PLACEHOLDER), */ 0x81, 0x02, /* Input (Variable), */ - 0x81, 0x03, /* Input (Constant, Variable), */ + 0x54, /* Unit Exponent (0), */ + 0x65, 0x14, /* Unit (Degrees), */ + 0x35, 0xC4, /* Physical Minimum (-60), */ + 0x45, 0x3C, /* Physical Maximum (60), */ + 0x15, 0xC4, /* Logical Minimum (-60), */ + 0x25, 0x3C, /* Logical Maximum (60), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x09, 0x3D, /* Usage (X Tilt), */ + 0x09, 0x3E, /* Usage (Y Tilt), */ + 0x81, 0x02, /* Input (Variable), */ 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; -const size_t uclogic_rdesc_pen_v2_template_size = - sizeof(uclogic_rdesc_pen_v2_template_arr); +const size_t uclogic_rdesc_v2_pen_template_size = + sizeof(uclogic_rdesc_v2_pen_template_arr); /* - * Expand to the contents of a generic buttonpad report descriptor. + * Expand to the contents of a generic frame report descriptor. * - * @_padding: Padding from the end of button bits at bit 44, until - * the end of the report, in bits. + * @_id: The report ID to use. + * @_size: Size of the report to pad to, including report ID, bytes. */ -#define UCLOGIC_RDESC_BUTTONPAD_BYTES(_padding) \ +#define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \ 0x05, 0x01, /* Usage Page (Desktop), */ \ 0x09, 0x07, /* Usage (Keypad), */ \ 0xA1, 0x01, /* Collection (Application), */ \ - 0x85, 0xF7, /* Report ID (247), */ \ + 0x85, (_id), /* Report ID (_id), */ \ 0x14, /* Logical Minimum (0), */ \ 0x25, 0x01, /* Logical Maximum (1), */ \ 0x75, 0x01, /* Report Size (1), */ \ @@ -679,30 +689,31 @@ const size_t uclogic_rdesc_pen_v2_template_size = 0xA0, /* Collection (Physical), */ \ 0x05, 0x09, /* Usage Page (Button), */ \ 0x19, 0x01, /* Usage Minimum (01h), */ \ - 0x29, 0x02, /* Usage Maximum (02h), */ \ - 0x95, 0x02, /* Report Count (2), */ \ + 0x29, 0x03, /* Usage Maximum (03h), */ \ + 0x95, 0x03, /* Report Count (3), */ \ 0x81, 0x02, /* Input (Variable), */ \ - 0x95, _padding, /* Report Count (_padding), */ \ + 0x95, ((_size) * 8 - 45), \ + /* Report Count (padding), */ \ 0x81, 0x01, /* Input (Constant), */ \ 0xC0, /* End Collection, */ \ 0xC0 /* End Collection */ -/* Fixed report descriptor for (tweaked) v1 buttonpad reports */ -const __u8 uclogic_rdesc_buttonpad_v1_arr[] = { - UCLOGIC_RDESC_BUTTONPAD_BYTES(20) +/* 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) }; -const size_t uclogic_rdesc_buttonpad_v1_size = - sizeof(uclogic_rdesc_buttonpad_v1_arr); +const size_t uclogic_rdesc_v1_frame_size = + sizeof(uclogic_rdesc_v1_frame_arr); -/* Fixed report descriptor for (tweaked) v2 buttonpad reports */ -const __u8 uclogic_rdesc_buttonpad_v2_arr[] = { - UCLOGIC_RDESC_BUTTONPAD_BYTES(52) +/* 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) }; -const size_t uclogic_rdesc_buttonpad_v2_size = - sizeof(uclogic_rdesc_buttonpad_v2_arr); +const size_t uclogic_rdesc_v2_frame_size = + sizeof(uclogic_rdesc_v2_frame_arr); -/* Fixed report descriptor for Ugee EX07 buttonpad */ -const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = { +/* Fixed report descriptor for Ugee EX07 frame */ +const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x07, /* Usage (Keypad), */ 0xA1, 0x01, /* Collection (Application), */ @@ -725,8 +736,8 @@ const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = { 0xC0, /* End Collection, */ 0xC0 /* End Collection */ }; -const size_t uclogic_rdesc_ugee_ex07_buttonpad_size = - sizeof(uclogic_rdesc_ugee_ex07_buttonpad_arr); +const size_t uclogic_rdesc_ugee_ex07_frame_size = + sizeof(uclogic_rdesc_ugee_ex07_frame_arr); /* Fixed report descriptor for Ugee G5 frame controls */ const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = { diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index c5da51055af3..3d904c27b86a 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -104,36 +104,36 @@ enum uclogic_rdesc_pen_ph_id { UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID /* Report ID for v1 pen reports */ -#define UCLOGIC_RDESC_PEN_V1_ID 0x07 +#define UCLOGIC_RDESC_V1_PEN_ID 0x07 /* Fixed report descriptor template for (tweaked) v1 pen reports */ -extern const __u8 uclogic_rdesc_pen_v1_template_arr[]; -extern const size_t uclogic_rdesc_pen_v1_template_size; +extern const __u8 uclogic_rdesc_v1_pen_template_arr[]; +extern const size_t uclogic_rdesc_v1_pen_template_size; /* Report ID for v2 pen reports */ -#define UCLOGIC_RDESC_PEN_V2_ID 0x08 +#define UCLOGIC_RDESC_V2_PEN_ID 0x08 /* Fixed report descriptor template for (tweaked) v2 pen reports */ -extern const __u8 uclogic_rdesc_pen_v2_template_arr[]; -extern const size_t uclogic_rdesc_pen_v2_template_size; +extern const __u8 uclogic_rdesc_v2_pen_template_arr[]; +extern const size_t uclogic_rdesc_v2_pen_template_size; -/* Fixed report descriptor for (tweaked) v1 buttonpad reports */ -extern const __u8 uclogic_rdesc_buttonpad_v1_arr[]; -extern const size_t uclogic_rdesc_buttonpad_v1_size; +/* Report ID for tweaked v1 frame reports */ +#define UCLOGIC_RDESC_V1_FRAME_ID 0xf7 -/* Report ID for tweaked v1 buttonpad reports */ -#define UCLOGIC_RDESC_BUTTONPAD_V1_ID 0xf7 +/* Fixed report descriptor for (tweaked) v1 frame reports */ +extern const __u8 uclogic_rdesc_v1_frame_arr[]; +extern const size_t uclogic_rdesc_v1_frame_size; -/* Fixed report descriptor for (tweaked) v2 buttonpad reports */ -extern const __u8 uclogic_rdesc_buttonpad_v2_arr[]; -extern const size_t uclogic_rdesc_buttonpad_v2_size; +/* Report ID for tweaked v2 frame reports */ +#define UCLOGIC_RDESC_V2_FRAME_ID 0xf7 -/* Report ID for tweaked v2 buttonpad reports */ -#define UCLOGIC_RDESC_BUTTONPAD_V2_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 Ugee EX07 buttonpad */ -extern const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[]; -extern const size_t uclogic_rdesc_ugee_ex07_buttonpad_size; +/* 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; /* Fixed report descriptor for XP-Pen Deco 01 frame controls */ extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[]; |