Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-5.20/uclogic' into for-linus

- XP-PEN Deco L support (José Expósito)

+581 -14
+5
drivers/hid/.kunitconfig
··· 1 + CONFIG_KUNIT=y 2 + CONFIG_USB=y 3 + CONFIG_USB_HID=y 4 + CONFIG_HID_UCLOGIC=y 5 + CONFIG_HID_KUNIT_TEST=y
+16
drivers/hid/Kconfig
··· 1306 1306 To compile this driver as a module, choose M here: the module 1307 1307 will be called hid-mcp2221.ko. 1308 1308 1309 + config HID_KUNIT_TEST 1310 + bool "KUnit tests for HID" if !KUNIT_ALL_TESTS 1311 + depends on KUNIT=y 1312 + depends on HID_UCLOGIC 1313 + default KUNIT_ALL_TESTS 1314 + help 1315 + This builds unit tests for HID. This option is not useful for 1316 + distributions or general kernels, but only for kernel 1317 + developers working on HID and associated drivers. 1318 + 1319 + For more information on KUnit and unit tests in general, 1320 + please refer to the KUnit documentation in 1321 + Documentation/dev-tools/kunit/. 1322 + 1323 + If in doubt, say "N". 1324 + 1309 1325 endmenu 1310 1326 1311 1327 endif # HID
+3
drivers/hid/Makefile
··· 144 144 obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o 145 145 obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o 146 146 147 + obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \ 148 + hid-uclogic-rdesc-test.o 149 + 147 150 obj-$(CONFIG_USB_HID) += usbhid/ 148 151 obj-$(CONFIG_USB_MOUSE) += usbhid/ 149 152 obj-$(CONFIG_USB_KBD) += usbhid/
+1
drivers/hid/hid-ids.h
··· 1279 1279 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 1280 1280 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 1281 1281 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 1282 + #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 1282 1283 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 1283 1284 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 1284 1285 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
+2
drivers/hid/hid-uclogic-core.c
··· 522 522 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 523 523 USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, 524 524 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 525 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, 526 + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 525 527 USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, 526 528 { } 527 529 };
+199 -2
drivers/hid/hid-uclogic-params.c
··· 238 238 const int len = 12; 239 239 s32 resolution; 240 240 /* Pen report descriptor template parameters */ 241 - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 241 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 242 242 __u8 *desc_ptr = NULL; 243 243 244 244 /* Check arguments */ ··· 383 383 size_t i; 384 384 s32 resolution; 385 385 /* Pen report descriptor template parameters */ 386 - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 386 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 387 387 __u8 *desc_ptr = NULL; 388 388 389 389 /* Check arguments */ ··· 1007 1007 } 1008 1008 1009 1009 /** 1010 + * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or 1011 + * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data. 1012 + * 1013 + * @hdev: The HID device of the tablet interface to initialize and get 1014 + * parameters from. Cannot be NULL. 1015 + * @magic_arr: The magic data that should be sent to probe the interface. 1016 + * Cannot be NULL. 1017 + * @magic_size: Size of the magic data. 1018 + * @endpoint: Endpoint where the magic data should be sent. 1019 + * 1020 + * Returns: 1021 + * Zero, if successful. A negative errno code on error. 1022 + */ 1023 + static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr, 1024 + int magic_size, int endpoint) 1025 + { 1026 + struct usb_device *udev; 1027 + unsigned int pipe = 0; 1028 + int sent; 1029 + u8 *buf = NULL; 1030 + int rc = 0; 1031 + 1032 + if (!hdev || !magic_arr) { 1033 + rc = -EINVAL; 1034 + goto cleanup; 1035 + } 1036 + 1037 + buf = kmemdup(magic_arr, magic_size, GFP_KERNEL); 1038 + if (!buf) { 1039 + rc = -ENOMEM; 1040 + goto cleanup; 1041 + } 1042 + 1043 + udev = hid_to_usb_dev(hdev); 1044 + pipe = usb_sndintpipe(udev, endpoint); 1045 + 1046 + rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000); 1047 + if (rc || sent != magic_size) { 1048 + hid_err(hdev, "Interface probing failed: %d\n", rc); 1049 + rc = -1; 1050 + goto cleanup; 1051 + } 1052 + 1053 + rc = 0; 1054 + cleanup: 1055 + kfree(buf); 1056 + return rc; 1057 + } 1058 + 1059 + /** 1060 + * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by 1061 + * discovering their parameters. 1062 + * 1063 + * These tables, internally designed as v2 to differentiate them from older 1064 + * models, expect a payload of magic data in orther to be switched to the fully 1065 + * functional mode and expose their parameters in a similar way to the 1066 + * information present in uclogic_params_pen_init_v1() but with some 1067 + * differences. 1068 + * 1069 + * @params: Parameters to fill in (to be cleaned with 1070 + * uclogic_params_cleanup()). Not modified in case of error. 1071 + * Cannot be NULL. 1072 + * @hdev: The HID device of the tablet interface to initialize and get 1073 + * parameters from. Cannot be NULL. 1074 + * 1075 + * Returns: 1076 + * Zero, if successful. A negative errno code on error. 1077 + */ 1078 + static int uclogic_params_ugee_v2_init(struct uclogic_params *params, 1079 + struct hid_device *hdev) 1080 + { 1081 + int rc = 0; 1082 + struct usb_interface *iface; 1083 + __u8 bInterfaceNumber; 1084 + const int str_desc_len = 12; 1085 + __u8 *str_desc = NULL; 1086 + __u8 *rdesc_pen = NULL; 1087 + __u8 *rdesc_frame = NULL; 1088 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 1089 + s32 resolution; 1090 + __u8 magic_arr[] = { 1091 + 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 1092 + }; 1093 + /* The resulting parameters (noop) */ 1094 + struct uclogic_params p = {0, }; 1095 + 1096 + if (!params || !hdev) { 1097 + rc = -EINVAL; 1098 + goto cleanup; 1099 + } 1100 + 1101 + iface = to_usb_interface(hdev->dev.parent); 1102 + bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; 1103 + if (bInterfaceNumber != 2) { 1104 + uclogic_params_init_invalid(&p); 1105 + goto output; 1106 + } 1107 + 1108 + /* 1109 + * Initialize the interface by sending magic data. 1110 + * The specific data was discovered by sniffing the Windows driver 1111 + * traffic. 1112 + */ 1113 + rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03); 1114 + if (rc) { 1115 + uclogic_params_init_invalid(&p); 1116 + goto output; 1117 + } 1118 + 1119 + /* 1120 + * Read the string descriptor containing pen and frame parameters. 1121 + * The specific string descriptor and data were discovered by sniffing 1122 + * the Windows driver traffic. 1123 + */ 1124 + rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); 1125 + if (rc != str_desc_len) { 1126 + hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc); 1127 + uclogic_params_init_invalid(&p); 1128 + goto output; 1129 + } 1130 + 1131 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 1132 + get_unaligned_le16(str_desc + 2); 1133 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 1134 + get_unaligned_le16(str_desc + 4); 1135 + desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6]; 1136 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 1137 + get_unaligned_le16(str_desc + 8); 1138 + resolution = get_unaligned_le16(str_desc + 10); 1139 + if (resolution == 0) { 1140 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; 1141 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; 1142 + } else { 1143 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 1144 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / 1145 + resolution; 1146 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 1147 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / 1148 + resolution; 1149 + } 1150 + kfree(str_desc); 1151 + str_desc = NULL; 1152 + 1153 + /* Initialize the pen interface */ 1154 + rdesc_pen = uclogic_rdesc_template_apply( 1155 + uclogic_rdesc_ugee_v2_pen_template_arr, 1156 + uclogic_rdesc_ugee_v2_pen_template_size, 1157 + desc_params, ARRAY_SIZE(desc_params)); 1158 + if (!rdesc_pen) { 1159 + rc = -ENOMEM; 1160 + goto cleanup; 1161 + } 1162 + 1163 + p.pen.desc_ptr = rdesc_pen; 1164 + p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; 1165 + p.pen.id = 0x02; 1166 + p.pen.subreport_list[0].value = 0xf0; 1167 + p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; 1168 + 1169 + /* Initialize the frame interface */ 1170 + rdesc_frame = uclogic_rdesc_template_apply( 1171 + uclogic_rdesc_ugee_v2_frame_btn_template_arr, 1172 + uclogic_rdesc_ugee_v2_frame_btn_template_size, 1173 + desc_params, ARRAY_SIZE(desc_params)); 1174 + if (!rdesc_frame) { 1175 + rc = -ENOMEM; 1176 + goto cleanup; 1177 + } 1178 + 1179 + rc = uclogic_params_frame_init_with_desc(&p.frame_list[0], 1180 + rdesc_frame, 1181 + uclogic_rdesc_ugee_v2_frame_btn_template_size, 1182 + UCLOGIC_RDESC_V1_FRAME_ID); 1183 + kfree(rdesc_frame); 1184 + if (rc) { 1185 + uclogic_params_init_invalid(&p); 1186 + goto output; 1187 + } 1188 + 1189 + output: 1190 + /* Output parameters */ 1191 + memcpy(params, &p, sizeof(*params)); 1192 + memset(&p, 0, sizeof(p)); 1193 + rc = 0; 1194 + cleanup: 1195 + kfree(str_desc); 1196 + uclogic_params_cleanup(&p); 1197 + return rc; 1198 + } 1199 + 1200 + /** 1010 1201 * uclogic_params_init() - initialize a tablet interface and discover its 1011 1202 * parameters. 1012 1203 * ··· 1431 1240 } else { 1432 1241 uclogic_params_init_invalid(&p); 1433 1242 } 1243 + break; 1244 + case VID_PID(USB_VENDOR_ID_UGEE, 1245 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): 1246 + rc = uclogic_params_ugee_v2_init(&p, hdev); 1247 + if (rc != 0) 1248 + goto cleanup; 1434 1249 break; 1435 1250 case VID_PID(USB_VENDOR_ID_TRUST, 1436 1251 USB_DEVICE_ID_TRUST_PANORA_TABLET):
+219
drivers/hid/hid-uclogic-rdesc-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* 4 + * HID driver for UC-Logic devices not fully compliant with HID standard 5 + * 6 + * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> 7 + */ 8 + 9 + #include <kunit/test.h> 10 + #include "./hid-uclogic-rdesc.h" 11 + 12 + struct uclogic_template_case { 13 + const char *name; 14 + const __u8 *template; 15 + size_t template_size; 16 + const s32 *param_list; 17 + size_t param_num; 18 + const __u8 *expected; 19 + }; 20 + 21 + static const s32 params_pen_all[UCLOGIC_RDESC_PH_ID_NUM] = { 22 + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, 23 + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, 24 + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0xCC, 25 + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0xDD, 26 + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0xEE, 27 + }; 28 + 29 + static const s32 params_pen_some[] = { 30 + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, 31 + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, 32 + }; 33 + 34 + static const s32 params_frame_all[UCLOGIC_RDESC_PH_ID_NUM] = { 35 + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0xFF, 36 + }; 37 + 38 + static const __u8 template_empty[] = { }; 39 + static const __u8 template_small[] = { 0x00 }; 40 + static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D }; 41 + 42 + static const __u8 template_pen_ph_end[] = { 43 + 0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD 44 + }; 45 + 46 + static const __u8 template_btn_ph_end[] = { 47 + 0xAA, 0xBB, UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 48 + }; 49 + 50 + static const __u8 template_pen_all_params[] = { 51 + UCLOGIC_RDESC_PEN_PH(X_LM), 52 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 53 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 54 + UCLOGIC_RDESC_PEN_PH(Y_PM), 55 + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 56 + }; 57 + 58 + static const __u8 expected_pen_all_params[] = { 59 + 0xAA, 0x00, 0x00, 0x00, 60 + 0x47, 0xBB, 0x00, 0x00, 0x00, 61 + 0x27, 0xCC, 0x00, 0x00, 0x00, 62 + 0xDD, 0x00, 0x00, 0x00, 63 + 0x00, 0xEE, 0x00, 0x00, 0x00, 64 + }; 65 + 66 + static const __u8 template_frame_all_params[] = { 67 + 0x01, 0x02, 68 + UCLOGIC_RDESC_FRAME_PH_BTN, 69 + 0x99, 70 + }; 71 + 72 + static const __u8 expected_frame_all_params[] = { 73 + 0x01, 0x02, 74 + 0x2A, 0xFF, 0x00, 75 + 0x99, 76 + }; 77 + 78 + static const __u8 template_pen_some_params[] = { 79 + 0x01, 0x02, 80 + UCLOGIC_RDESC_PEN_PH(X_LM), 81 + 0x03, UCLOGIC_RDESC_PEN_PH(X_PM), 82 + 0x04, 0x05, 83 + }; 84 + 85 + static const __u8 expected_pen_some_params[] = { 86 + 0x01, 0x02, 87 + 0xAA, 0x00, 0x00, 0x00, 88 + 0x03, 0xBB, 0x00, 0x00, 0x00, 89 + 0x04, 0x05, 90 + }; 91 + 92 + static const __u8 template_params_none[] = { 93 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 94 + UCLOGIC_RDESC_PEN_PH(Y_PM), 95 + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 96 + }; 97 + 98 + static struct uclogic_template_case uclogic_template_cases[] = { 99 + { 100 + .name = "Empty template", 101 + .template = template_empty, 102 + .template_size = sizeof(template_empty), 103 + .param_list = params_pen_all, 104 + .param_num = ARRAY_SIZE(params_pen_all), 105 + .expected = template_empty, 106 + }, 107 + { 108 + .name = "Template smaller than the placeholder", 109 + .template = template_small, 110 + .template_size = sizeof(template_small), 111 + .param_list = params_pen_all, 112 + .param_num = ARRAY_SIZE(params_pen_all), 113 + .expected = template_small, 114 + }, 115 + { 116 + .name = "No placeholder", 117 + .template = template_no_ph, 118 + .template_size = sizeof(template_no_ph), 119 + .param_list = params_pen_all, 120 + .param_num = ARRAY_SIZE(params_pen_all), 121 + .expected = template_no_ph, 122 + }, 123 + { 124 + .name = "Pen placeholder at the end, without ID", 125 + .template = template_pen_ph_end, 126 + .template_size = sizeof(template_pen_ph_end), 127 + .param_list = params_pen_all, 128 + .param_num = ARRAY_SIZE(params_pen_all), 129 + .expected = template_pen_ph_end, 130 + }, 131 + { 132 + .name = "Frame button placeholder at the end, without ID", 133 + .template = template_btn_ph_end, 134 + .template_size = sizeof(template_btn_ph_end), 135 + .param_list = params_frame_all, 136 + .param_num = ARRAY_SIZE(params_frame_all), 137 + .expected = template_btn_ph_end, 138 + }, 139 + { 140 + .name = "All params present in the pen template", 141 + .template = template_pen_all_params, 142 + .template_size = sizeof(template_pen_all_params), 143 + .param_list = params_pen_all, 144 + .param_num = ARRAY_SIZE(params_pen_all), 145 + .expected = expected_pen_all_params, 146 + }, 147 + { 148 + .name = "All params present in the frame template", 149 + .template = template_frame_all_params, 150 + .template_size = sizeof(template_frame_all_params), 151 + .param_list = params_frame_all, 152 + .param_num = ARRAY_SIZE(params_frame_all), 153 + .expected = expected_frame_all_params, 154 + }, 155 + { 156 + .name = "Some params present in the pen template (complete param list)", 157 + .template = template_pen_some_params, 158 + .template_size = sizeof(template_pen_some_params), 159 + .param_list = params_pen_all, 160 + .param_num = ARRAY_SIZE(params_pen_all), 161 + .expected = expected_pen_some_params, 162 + }, 163 + { 164 + .name = "Some params present in the pen template (incomplete param list)", 165 + .template = template_pen_some_params, 166 + .template_size = sizeof(template_pen_some_params), 167 + .param_list = params_pen_some, 168 + .param_num = ARRAY_SIZE(params_pen_some), 169 + .expected = expected_pen_some_params, 170 + }, 171 + { 172 + .name = "No params present in the template", 173 + .template = template_params_none, 174 + .template_size = sizeof(template_params_none), 175 + .param_list = params_pen_some, 176 + .param_num = ARRAY_SIZE(params_pen_some), 177 + .expected = template_params_none, 178 + }, 179 + }; 180 + 181 + static void uclogic_template_case_desc(struct uclogic_template_case *t, 182 + char *desc) 183 + { 184 + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 185 + } 186 + 187 + KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases, 188 + uclogic_template_case_desc); 189 + 190 + static void uclogic_template_test(struct kunit *test) 191 + { 192 + __u8 *res; 193 + const struct uclogic_template_case *params = test->param_value; 194 + 195 + res = uclogic_rdesc_template_apply(params->template, 196 + params->template_size, 197 + params->param_list, 198 + params->param_num); 199 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res); 200 + KUNIT_EXPECT_EQ(test, 0, 201 + memcmp(res, params->expected, params->template_size)); 202 + kfree(res); 203 + } 204 + 205 + static struct kunit_case hid_uclogic_rdesc_test_cases[] = { 206 + KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params), 207 + {} 208 + }; 209 + 210 + static struct kunit_suite hid_uclogic_rdesc_test_suite = { 211 + .name = "hid-uclogic-rdesc-test", 212 + .test_cases = hid_uclogic_rdesc_test_cases, 213 + }; 214 + 215 + kunit_test_suite(hid_uclogic_rdesc_test_suite); 216 + 217 + MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); 218 + MODULE_LICENSE("GPL"); 219 + MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
+117 -7
drivers/hid/hid-uclogic-rdesc.c
··· 859 859 const size_t uclogic_rdesc_v2_frame_dial_size = 860 860 sizeof(uclogic_rdesc_v2_frame_dial_arr); 861 861 862 + /* Fixed report descriptor template for UGEE v2 pen reports */ 863 + const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = { 864 + 0x05, 0x0d, /* Usage Page (Digitizers), */ 865 + 0x09, 0x01, /* Usage (Digitizer), */ 866 + 0xa1, 0x01, /* Collection (Application), */ 867 + 0x85, 0x02, /* Report ID (2), */ 868 + 0x09, 0x20, /* Usage (Stylus), */ 869 + 0xa1, 0x00, /* Collection (Physical), */ 870 + 0x09, 0x42, /* Usage (Tip Switch), */ 871 + 0x09, 0x44, /* Usage (Barrel Switch), */ 872 + 0x09, 0x46, /* Usage (Tablet Pick), */ 873 + 0x75, 0x01, /* Report Size (1), */ 874 + 0x95, 0x03, /* Report Count (3), */ 875 + 0x14, /* Logical Minimum (0), */ 876 + 0x25, 0x01, /* Logical Maximum (1), */ 877 + 0x81, 0x02, /* Input (Variable), */ 878 + 0x95, 0x02, /* Report Count (2), */ 879 + 0x81, 0x03, /* Input (Constant, Variable), */ 880 + 0x09, 0x32, /* Usage (In Range), */ 881 + 0x95, 0x01, /* Report Count (1), */ 882 + 0x81, 0x02, /* Input (Variable), */ 883 + 0x95, 0x02, /* Report Count (2), */ 884 + 0x81, 0x03, /* Input (Constant, Variable), */ 885 + 0x75, 0x10, /* Report Size (16), */ 886 + 0x95, 0x01, /* Report Count (1), */ 887 + 0x35, 0x00, /* Physical Minimum (0), */ 888 + 0xa4, /* Push, */ 889 + 0x05, 0x01, /* Usage Page (Desktop), */ 890 + 0x09, 0x30, /* Usage (X), */ 891 + 0x65, 0x13, /* Unit (Inch), */ 892 + 0x55, 0x0d, /* Unit Exponent (-3), */ 893 + 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), 894 + /* Logical Maximum (PLACEHOLDER), */ 895 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 896 + /* Physical Maximum (PLACEHOLDER), */ 897 + 0x81, 0x02, /* Input (Variable), */ 898 + 0x09, 0x31, /* Usage (Y), */ 899 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 900 + /* Logical Maximum (PLACEHOLDER), */ 901 + 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), 902 + /* Physical Maximum (PLACEHOLDER), */ 903 + 0x81, 0x02, /* Input (Variable), */ 904 + 0xb4, /* Pop, */ 905 + 0x09, 0x30, /* Usage (Tip Pressure), */ 906 + 0x45, 0x00, /* Physical Maximum (0), */ 907 + 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 908 + /* Logical Maximum (PLACEHOLDER), */ 909 + 0x75, 0x0D, /* Report Size (13), */ 910 + 0x95, 0x01, /* Report Count (1), */ 911 + 0x81, 0x02, /* Input (Variable), */ 912 + 0x75, 0x01, /* Report Size (1), */ 913 + 0x95, 0x03, /* Report Count (3), */ 914 + 0x81, 0x01, /* Input (Constant), */ 915 + 0x09, 0x3d, /* Usage (X Tilt), */ 916 + 0x35, 0xC3, /* Physical Minimum (-61), */ 917 + 0x45, 0x3C, /* Physical Maximum (60), */ 918 + 0x15, 0xC3, /* Logical Minimum (-61), */ 919 + 0x25, 0x3C, /* Logical Maximum (60), */ 920 + 0x75, 0x08, /* Report Size (8), */ 921 + 0x95, 0x01, /* Report Count (1), */ 922 + 0x81, 0x02, /* Input (Variable), */ 923 + 0x09, 0x3e, /* Usage (Y Tilt), */ 924 + 0x35, 0xC3, /* Physical Minimum (-61), */ 925 + 0x45, 0x3C, /* Physical Maximum (60), */ 926 + 0x15, 0xC3, /* Logical Minimum (-61), */ 927 + 0x25, 0x3C, /* Logical Maximum (60), */ 928 + 0x81, 0x02, /* Input (Variable), */ 929 + 0xc0, /* End Collection, */ 930 + 0xc0, /* End Collection */ 931 + }; 932 + const size_t uclogic_rdesc_ugee_v2_pen_template_size = 933 + sizeof(uclogic_rdesc_ugee_v2_pen_template_arr); 934 + 935 + /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ 936 + const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = { 937 + 0x05, 0x01, /* Usage Page (Desktop), */ 938 + 0x09, 0x07, /* Usage (Keypad), */ 939 + 0xA1, 0x01, /* Collection (Application), */ 940 + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, 941 + /* Report ID, */ 942 + 0x05, 0x0D, /* Usage Page (Digitizer), */ 943 + 0x09, 0x39, /* Usage (Tablet Function Keys), */ 944 + 0xA0, /* Collection (Physical), */ 945 + 0x75, 0x01, /* Report Size (1), */ 946 + 0x95, 0x08, /* Report Count (8), */ 947 + 0x81, 0x01, /* Input (Constant), */ 948 + 0x05, 0x09, /* Usage Page (Button), */ 949 + 0x19, 0x01, /* Usage Minimum (01h), */ 950 + UCLOGIC_RDESC_FRAME_PH_BTN, 951 + /* Usage Maximum (PLACEHOLDER), */ 952 + 0x95, 0x0A, /* Report Count (10), */ 953 + 0x14, /* Logical Minimum (0), */ 954 + 0x25, 0x01, /* Logical Maximum (1), */ 955 + 0x81, 0x02, /* Input (Variable), */ 956 + 0x95, 0x46, /* Report Count (70), */ 957 + 0x81, 0x01, /* Input (Constant), */ 958 + 0xC0, /* End Collection, */ 959 + 0xC0 /* End Collection */ 960 + }; 961 + const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size = 962 + sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr); 963 + 862 964 /* Fixed report descriptor for Ugee EX07 frame */ 863 965 const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 864 966 0x05, 0x01, /* Usage Page (Desktop), */ ··· 1081 979 * uclogic_rdesc_template_apply() - apply report descriptor parameters to a 1082 980 * report descriptor template, creating a report descriptor. Copies the 1083 981 * template over to the new report descriptor and replaces every occurrence of 1084 - * UCLOGIC_RDESC_PH_HEAD, followed by an index byte, with the value from the 982 + * the template placeholders, followed by an index byte, with the value from the 1085 983 * parameter list at that index. 1086 984 * 1087 985 * @template_ptr: Pointer to the template buffer. ··· 1098 996 const s32 *param_list, 1099 997 size_t param_num) 1100 998 { 1101 - static const __u8 head[] = {UCLOGIC_RDESC_PH_HEAD}; 999 + static const __u8 btn_head[] = {UCLOGIC_RDESC_FRAME_PH_BTN_HEAD}; 1000 + static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD}; 1102 1001 __u8 *rdesc_ptr; 1103 1002 __u8 *p; 1104 1003 s32 v; ··· 1108 1005 if (rdesc_ptr == NULL) 1109 1006 return NULL; 1110 1007 1111 - for (p = rdesc_ptr; p + sizeof(head) < rdesc_ptr + template_size;) { 1112 - if (memcmp(p, head, sizeof(head)) == 0 && 1113 - p[sizeof(head)] < param_num) { 1114 - v = param_list[p[sizeof(head)]]; 1008 + for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) { 1009 + if (p + sizeof(pen_head) < rdesc_ptr + template_size && 1010 + memcmp(p, pen_head, sizeof(pen_head)) == 0 && 1011 + p[sizeof(pen_head)] < param_num) { 1012 + v = param_list[p[sizeof(pen_head)]]; 1115 1013 put_unaligned(cpu_to_le32(v), (s32 *)p); 1116 - p += sizeof(head) + 1; 1014 + p += sizeof(pen_head) + 1; 1015 + } else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 && 1016 + p[sizeof(btn_head)] < param_num) { 1017 + v = param_list[p[sizeof(btn_head)]]; 1018 + put_unaligned((__u8)0x2A, p); /* Usage Maximum */ 1019 + put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1); 1020 + p += sizeof(btn_head) + 1; 1117 1021 } else { 1118 1022 p++; 1119 1023 }
+19 -5
drivers/hid/hid-uclogic-rdesc.h
··· 81 81 extern const size_t uclogic_rdesc_twha60_fixed1_size; 82 82 83 83 /* Report descriptor template placeholder head */ 84 - #define UCLOGIC_RDESC_PH_HEAD 0xFE, 0xED, 0x1D 84 + #define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D 85 + #define UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 0xFE, 0xED 85 86 86 87 /* Apply report descriptor parameters to a report descriptor template */ 87 88 extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, ··· 90 89 const s32 *param_list, 91 90 size_t param_num); 92 91 93 - /* Pen report descriptor template placeholder IDs */ 94 - enum uclogic_rdesc_pen_ph_id { 92 + /* Report descriptor template placeholder IDs */ 93 + enum uclogic_rdesc_ph_id { 95 94 UCLOGIC_RDESC_PEN_PH_ID_X_LM, 96 95 UCLOGIC_RDESC_PEN_PH_ID_X_PM, 97 96 UCLOGIC_RDESC_PEN_PH_ID_Y_LM, 98 97 UCLOGIC_RDESC_PEN_PH_ID_Y_PM, 99 98 UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM, 100 - UCLOGIC_RDESC_PEN_PH_ID_NUM 99 + UCLOGIC_RDESC_FRAME_PH_ID_UM, 100 + UCLOGIC_RDESC_PH_ID_NUM 101 101 }; 102 102 103 103 /* Report descriptor pen template placeholder */ 104 104 #define UCLOGIC_RDESC_PEN_PH(_ID) \ 105 - UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID 105 + UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID 106 + 107 + /* Report descriptor frame buttons template placeholder */ 108 + #define UCLOGIC_RDESC_FRAME_PH_BTN \ 109 + UCLOGIC_RDESC_FRAME_PH_BTN_HEAD, UCLOGIC_RDESC_FRAME_PH_ID_UM 106 110 107 111 /* Report ID for v1 pen reports */ 108 112 #define UCLOGIC_RDESC_V1_PEN_ID 0x07 ··· 160 154 161 155 /* Device ID byte offset in v2 frame dial reports */ 162 156 #define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 157 + 158 + /* Fixed report descriptor template for UGEE v2 pen reports */ 159 + extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[]; 160 + extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; 161 + 162 + /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ 163 + extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[]; 164 + extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size; 163 165 164 166 /* Fixed report descriptor for Ugee EX07 frame */ 165 167 extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];