xref: /linux/drivers/hid/hid-uclogic-core.c (revision ff0c13d6d2edc9c4952c668f4503a51b5f101ab3)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  HID driver for UC-Logic devices not fully compliant with HID standard
4  *
5  *  Copyright (c) 2010-2014 Nikolai Kondrashov
6  *  Copyright (c) 2013 Martin Rusko
7  */
8 
9 /*
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  */
15 
16 #include <linux/device.h>
17 #include <linux/hid.h>
18 #include <linux/module.h>
19 #include <linux/usb.h>
20 #include "usbhid/usbhid.h"
21 #include "hid-uclogic-rdesc.h"
22 
23 #include "hid-ids.h"
24 
25 /* Parameter indices */
26 enum uclogic_prm {
27 	UCLOGIC_PRM_X_LM	= 1,
28 	UCLOGIC_PRM_Y_LM	= 2,
29 	UCLOGIC_PRM_PRESSURE_LM	= 4,
30 	UCLOGIC_PRM_RESOLUTION	= 5,
31 	UCLOGIC_PRM_NUM
32 };
33 
34 /* Driver data */
35 struct uclogic_drvdata {
36 	__u8 *rdesc;
37 	unsigned int rsize;
38 	bool invert_pen_inrange;
39 	bool ignore_pen_usage;
40 	bool has_virtual_pad_interface;
41 };
42 
43 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
44 					unsigned int *rsize)
45 {
46 	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
47 	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
48 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
49 
50 	if (drvdata->rdesc != NULL) {
51 		rdesc = drvdata->rdesc;
52 		*rsize = drvdata->rsize;
53 		return rdesc;
54 	}
55 
56 	switch (hdev->product) {
57 	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
58 		if (*rsize == UCLOGIC_RDESC_PF1209_ORIG_SIZE) {
59 			rdesc = uclogic_rdesc_pf1209_fixed_arr;
60 			*rsize = uclogic_rdesc_pf1209_fixed_size;
61 		}
62 		break;
63 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
64 		if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
65 			rdesc = uclogic_rdesc_wp4030u_fixed_arr;
66 			*rsize = uclogic_rdesc_wp4030u_fixed_size;
67 		}
68 		break;
69 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
70 		if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
71 			rdesc = uclogic_rdesc_wp5540u_fixed_arr;
72 			*rsize = uclogic_rdesc_wp5540u_fixed_size;
73 		}
74 		break;
75 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
76 		if (*rsize == UCLOGIC_RDESC_WPXXXXU_ORIG_SIZE) {
77 			rdesc = uclogic_rdesc_wp8060u_fixed_arr;
78 			*rsize = uclogic_rdesc_wp8060u_fixed_size;
79 		}
80 		break;
81 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
82 		if (*rsize == UCLOGIC_RDESC_WP1062_ORIG_SIZE) {
83 			rdesc = uclogic_rdesc_wp1062_fixed_arr;
84 			*rsize = uclogic_rdesc_wp1062_fixed_size;
85 		}
86 		break;
87 	case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
88 		switch (iface_num) {
89 		case 0:
90 			if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG0_SIZE) {
91 				rdesc = uclogic_rdesc_twhl850_fixed0_arr;
92 				*rsize = uclogic_rdesc_twhl850_fixed0_size;
93 			}
94 			break;
95 		case 1:
96 			if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG1_SIZE) {
97 				rdesc = uclogic_rdesc_twhl850_fixed1_arr;
98 				*rsize = uclogic_rdesc_twhl850_fixed1_size;
99 			}
100 			break;
101 		case 2:
102 			if (*rsize == UCLOGIC_RDESC_TWHL850_ORIG2_SIZE) {
103 				rdesc = uclogic_rdesc_twhl850_fixed2_arr;
104 				*rsize = uclogic_rdesc_twhl850_fixed2_size;
105 			}
106 			break;
107 		}
108 		break;
109 	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
110 		switch (iface_num) {
111 		case 0:
112 			if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG0_SIZE) {
113 				rdesc = uclogic_rdesc_twha60_fixed0_arr;
114 				*rsize = uclogic_rdesc_twha60_fixed0_size;
115 			}
116 			break;
117 		case 1:
118 			if (*rsize == UCLOGIC_RDESC_TWHA60_ORIG1_SIZE) {
119 				rdesc = uclogic_rdesc_twha60_fixed1_arr;
120 				*rsize = uclogic_rdesc_twha60_fixed1_size;
121 			}
122 			break;
123 		}
124 		break;
125 	}
126 
127 	return rdesc;
128 }
129 
130 static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
131 		struct hid_field *field, struct hid_usage *usage,
132 		unsigned long **bit, int *max)
133 {
134 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
135 
136 	/* discard the unused pen interface */
137 	if ((drvdata->ignore_pen_usage) &&
138 	    (field->application == HID_DG_PEN))
139 		return -1;
140 
141 	/* let hid-core decide what to do */
142 	return 0;
143 }
144 
145 static int uclogic_input_configured(struct hid_device *hdev,
146 		struct hid_input *hi)
147 {
148 	char *name;
149 	const char *suffix = NULL;
150 	struct hid_field *field;
151 	size_t len;
152 
153 	/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
154 	if (!hi->report)
155 		return 0;
156 
157 	field = hi->report->field[0];
158 
159 	switch (field->application) {
160 	case HID_GD_KEYBOARD:
161 		suffix = "Keyboard";
162 		break;
163 	case HID_GD_MOUSE:
164 		suffix = "Mouse";
165 		break;
166 	case HID_GD_KEYPAD:
167 		suffix = "Pad";
168 		break;
169 	case HID_DG_PEN:
170 		suffix = "Pen";
171 		break;
172 	case HID_CP_CONSUMER_CONTROL:
173 		suffix = "Consumer Control";
174 		break;
175 	case HID_GD_SYSTEM_CONTROL:
176 		suffix = "System Control";
177 		break;
178 	}
179 
180 	if (suffix) {
181 		len = strlen(hdev->name) + 2 + strlen(suffix);
182 		name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
183 		if (name) {
184 			snprintf(name, len, "%s %s", hdev->name, suffix);
185 			hi->input->name = name;
186 		}
187 	}
188 
189 	return 0;
190 }
191 
192 /**
193  * Enable fully-functional tablet mode and determine device parameters.
194  *
195  * @hdev:	HID device
196  */
197 static int uclogic_tablet_enable(struct hid_device *hdev)
198 {
199 	int rc;
200 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
201 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
202 	__le16 *buf = NULL;
203 	size_t len;
204 	s32 params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
205 	s32 resolution;
206 
207 	/*
208 	 * Read string descriptor containing tablet parameters. The specific
209 	 * string descriptor and data were discovered by sniffing the Windows
210 	 * driver traffic.
211 	 * NOTE: This enables fully-functional tablet mode.
212 	 */
213 	len = UCLOGIC_PRM_NUM * sizeof(*buf);
214 	buf = kmalloc(len, GFP_KERNEL);
215 	if (buf == NULL) {
216 		rc = -ENOMEM;
217 		goto cleanup;
218 	}
219 	rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
220 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
221 				(USB_DT_STRING << 8) + 0x64,
222 				0x0409, buf, len,
223 				USB_CTRL_GET_TIMEOUT);
224 	if (rc == -EPIPE) {
225 		hid_err(hdev, "device parameters not found\n");
226 		rc = -ENODEV;
227 		goto cleanup;
228 	} else if (rc < 0) {
229 		hid_err(hdev, "failed to get device parameters: %d\n", rc);
230 		rc = -ENODEV;
231 		goto cleanup;
232 	} else if (rc != len) {
233 		hid_err(hdev, "invalid device parameters\n");
234 		rc = -ENODEV;
235 		goto cleanup;
236 	}
237 
238 	/* Extract device parameters */
239 	params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
240 		le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
241 	params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
242 		le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
243 	params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
244 		le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
245 	resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
246 	if (resolution == 0) {
247 		params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
248 		params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
249 	} else {
250 		params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
251 			params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] *
252 			1000 / resolution;
253 		params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
254 			params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] *
255 			1000 / resolution;
256 	}
257 
258 	/* Format fixed report descriptor */
259 	drvdata->rdesc = uclogic_rdesc_template_apply(
260 				uclogic_rdesc_pen_template_arr,
261 				uclogic_rdesc_pen_template_size,
262 				params, ARRAY_SIZE(params));
263 	if (drvdata->rdesc == NULL) {
264 		rc = -ENOMEM;
265 		goto cleanup;
266 	}
267 	drvdata->rsize = uclogic_rdesc_pen_template_size;
268 
269 	rc = 0;
270 
271 cleanup:
272 	kfree(buf);
273 	return rc;
274 }
275 
276 /**
277  * Enable actual button mode.
278  *
279  * @hdev:	HID device
280  */
281 static int uclogic_button_enable(struct hid_device *hdev)
282 {
283 	int rc;
284 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
285 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
286 	char *str_buf;
287 	size_t str_len = 16;
288 	unsigned char *rdesc;
289 	size_t rdesc_len;
290 
291 	str_buf = kzalloc(str_len, GFP_KERNEL);
292 	if (str_buf == NULL) {
293 		rc = -ENOMEM;
294 		goto cleanup;
295 	}
296 
297 	/* Enable abstract keyboard mode */
298 	rc = usb_string(usb_dev, 0x7b, str_buf, str_len);
299 	if (rc == -EPIPE) {
300 		hid_info(hdev, "button mode setting not found\n");
301 		rc = 0;
302 		goto cleanup;
303 	} else if (rc < 0) {
304 		hid_err(hdev, "failed to enable abstract keyboard\n");
305 		goto cleanup;
306 	} else if (strncmp(str_buf, "HK On", rc)) {
307 		hid_info(hdev, "invalid answer when requesting buttons: '%s'\n",
308 			str_buf);
309 		rc = -EINVAL;
310 		goto cleanup;
311 	}
312 
313 	/* Re-allocate fixed report descriptor */
314 	rdesc_len = drvdata->rsize + uclogic_rdesc_buttonpad_size;
315 	rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL);
316 	if (!rdesc) {
317 		rc = -ENOMEM;
318 		goto cleanup;
319 	}
320 
321 	memcpy(rdesc, drvdata->rdesc, drvdata->rsize);
322 
323 	/* Append the buttonpad descriptor */
324 	memcpy(rdesc + drvdata->rsize, uclogic_rdesc_buttonpad_arr,
325 	       uclogic_rdesc_buttonpad_size);
326 
327 	/* clean up old rdesc and use the new one */
328 	drvdata->rsize = rdesc_len;
329 	devm_kfree(&hdev->dev, drvdata->rdesc);
330 	drvdata->rdesc = rdesc;
331 
332 	rc = 0;
333 
334 cleanup:
335 	kfree(str_buf);
336 	return rc;
337 }
338 
339 static int uclogic_probe(struct hid_device *hdev,
340 		const struct hid_device_id *id)
341 {
342 	int rc;
343 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
344 	struct usb_device *udev = hid_to_usb_dev(hdev);
345 	struct uclogic_drvdata *drvdata;
346 
347 	/*
348 	 * libinput requires the pad interface to be on a different node
349 	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
350 	 */
351 	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
352 
353 	/* Allocate and assign driver data */
354 	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
355 	if (drvdata == NULL)
356 		return -ENOMEM;
357 
358 	hid_set_drvdata(hdev, drvdata);
359 
360 	switch (id->product) {
361 	case USB_DEVICE_ID_HUION_TABLET:
362 	case USB_DEVICE_ID_YIYNOVA_TABLET:
363 	case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81:
364 	case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3:
365 	case USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45:
366 		/* If this is the pen interface */
367 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
368 			rc = uclogic_tablet_enable(hdev);
369 			if (rc) {
370 				hid_err(hdev, "tablet enabling failed\n");
371 				return rc;
372 			}
373 			drvdata->invert_pen_inrange = true;
374 
375 			rc = uclogic_button_enable(hdev);
376 			drvdata->has_virtual_pad_interface = !rc;
377 		} else {
378 			drvdata->ignore_pen_usage = true;
379 		}
380 		break;
381 	case USB_DEVICE_ID_UGTIZER_TABLET_GP0610:
382 	case USB_DEVICE_ID_UGEE_TABLET_EX07S:
383 		/* If this is the pen interface */
384 		if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
385 			rc = uclogic_tablet_enable(hdev);
386 			if (rc) {
387 				hid_err(hdev, "tablet enabling failed\n");
388 				return rc;
389 			}
390 			drvdata->invert_pen_inrange = true;
391 		} else {
392 			drvdata->ignore_pen_usage = true;
393 		}
394 		break;
395 	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
396 		/*
397 		 * If it is the three-interface version, which is known to
398 		 * respond to initialization.
399 		 */
400 		if (udev->config->desc.bNumInterfaces == 3) {
401 			/* If it is the pen interface */
402 			if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
403 				rc = uclogic_tablet_enable(hdev);
404 				if (rc) {
405 					hid_err(hdev, "tablet enabling failed\n");
406 					return rc;
407 				}
408 				drvdata->invert_pen_inrange = true;
409 
410 				rc = uclogic_button_enable(hdev);
411 				drvdata->has_virtual_pad_interface = !rc;
412 			} else {
413 				drvdata->ignore_pen_usage = true;
414 			}
415 		}
416 		break;
417 	}
418 
419 	rc = hid_parse(hdev);
420 	if (rc) {
421 		hid_err(hdev, "parse failed\n");
422 		return rc;
423 	}
424 
425 	rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
426 	if (rc) {
427 		hid_err(hdev, "hw start failed\n");
428 		return rc;
429 	}
430 
431 	return 0;
432 }
433 
434 static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
435 			u8 *data, int size)
436 {
437 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
438 
439 	if ((report->type == HID_INPUT_REPORT) &&
440 	    (report->id == UCLOGIC_RDESC_PEN_ID) &&
441 	    (size >= 2)) {
442 		if (drvdata->has_virtual_pad_interface && (data[1] & 0x20))
443 			/* Change to virtual frame button report ID */
444 			data[0] = 0xf7;
445 		else if (drvdata->invert_pen_inrange)
446 			/* Invert the in-range bit */
447 			data[1] ^= 0x40;
448 	}
449 
450 	return 0;
451 }
452 
453 static const struct hid_device_id uclogic_devices[] = {
454 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
455 				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
456 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
457 				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
458 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
459 				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
460 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
461 				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
462 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
463 				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
464 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
465 				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
466 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
467 				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
468 	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
469 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
470 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
471 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) },
472 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) },
473 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
474 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
475 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) },
476 	{ }
477 };
478 MODULE_DEVICE_TABLE(hid, uclogic_devices);
479 
480 static struct hid_driver uclogic_driver = {
481 	.name = "uclogic",
482 	.id_table = uclogic_devices,
483 	.probe = uclogic_probe,
484 	.report_fixup = uclogic_report_fixup,
485 	.raw_event = uclogic_raw_event,
486 	.input_mapping = uclogic_input_mapping,
487 	.input_configured = uclogic_input_configured,
488 };
489 module_hid_driver(uclogic_driver);
490 
491 MODULE_AUTHOR("Martin Rusko");
492 MODULE_AUTHOR("Nikolai Kondrashov");
493 MODULE_LICENSE("GPL");
494