Skip to content

Commit a60885b

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.20/uclogic' into for-linus
- XP-PEN Deco L support (José Expósito)
2 parents db24433 + 0cb1fc0 commit a60885b

File tree

9 files changed

+581
-14
lines changed

9 files changed

+581
-14
lines changed

drivers/hid/.kunitconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CONFIG_KUNIT=y
2+
CONFIG_USB=y
3+
CONFIG_USB_HID=y
4+
CONFIG_HID_UCLOGIC=y
5+
CONFIG_HID_KUNIT_TEST=y

drivers/hid/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,22 @@ config HID_MCP2221
13061306
To compile this driver as a module, choose M here: the module
13071307
will be called hid-mcp2221.ko.
13081308

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+
13091325
endmenu
13101326

13111327
endif # HID

drivers/hid/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o
144144
obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o
145145
obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o
146146

147+
obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \
148+
hid-uclogic-rdesc-test.o
149+
147150
obj-$(CONFIG_USB_HID) += usbhid/
148151
obj-$(CONFIG_USB_MOUSE) += usbhid/
149152
obj-$(CONFIG_USB_KBD) += usbhid/

drivers/hid/hid-ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,7 @@
12791279
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075
12801280
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094
12811281
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042
1282+
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935
12821283
#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078
12831284
#define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074
12841285
#define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071

drivers/hid/hid-uclogic-core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,8 @@ static const struct hid_device_id uclogic_devices[] = {
521521
USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
522522
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
523523
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
524+
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
525+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) },
524526
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
525527
USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) },
526528
{ }

drivers/hid/hid-uclogic-params.c

Lines changed: 199 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
238238
const int len = 12;
239239
s32 resolution;
240240
/* Pen report descriptor template parameters */
241-
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
241+
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
242242
__u8 *desc_ptr = NULL;
243243

244244
/* Check arguments */
@@ -383,7 +383,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
383383
size_t i;
384384
s32 resolution;
385385
/* Pen report descriptor template parameters */
386-
s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
386+
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
387387
__u8 *desc_ptr = NULL;
388388

389389
/* Check arguments */
@@ -1006,6 +1006,197 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
10061006
return rc;
10071007
}
10081008

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+
10091200
/**
10101201
* uclogic_params_init() - initialize a tablet interface and discover its
10111202
* parameters.
@@ -1241,6 +1432,12 @@ int uclogic_params_init(struct uclogic_params *params,
12411432
uclogic_params_init_invalid(&p);
12421433
}
12431434
break;
1435+
case VID_PID(USB_VENDOR_ID_UGEE,
1436+
USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L):
1437+
rc = uclogic_params_ugee_v2_init(&p, hdev);
1438+
if (rc != 0)
1439+
goto cleanup;
1440+
break;
12441441
case VID_PID(USB_VENDOR_ID_TRUST,
12451442
USB_DEVICE_ID_TRUST_PANORA_TABLET):
12461443
case VID_PID(USB_VENDOR_ID_UGEE,

0 commit comments

Comments
 (0)