HID: uclogic: Define report IDs before their descriptors
[linux-block.git] / drivers / hid / hid-uclogic-core.c
CommitLineData
ff0c13d6
NK
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>
01309e29 19#include <linux/timer.h>
ff0c13d6 20#include "usbhid/usbhid.h"
9614219e 21#include "hid-uclogic-params.h"
ff0c13d6
NK
22
23#include "hid-ids.h"
24
ff0c13d6
NK
25/* Driver data */
26struct uclogic_drvdata {
9614219e
NK
27 /* Interface parameters */
28 struct uclogic_params params;
29 /* Pointer to the replacement report descriptor. NULL if none. */
30 __u8 *desc_ptr;
31 /*
32 * Size of the replacement report descriptor.
33 * Only valid if desc_ptr is not NULL
34 */
35 unsigned int desc_size;
01309e29
NK
36 /* Pen input device */
37 struct input_dev *pen_input;
38 /* In-range timer */
39 struct timer_list inrange_timer;
8a47670c
NK
40 /* Last rotary encoder state, or U8_MAX for none */
41 u8 re_state;
ff0c13d6
NK
42};
43
01309e29
NK
44/**
45 * uclogic_inrange_timeout - handle pen in-range state timeout.
46 * Emulate input events normally generated when pen goes out of range for
47 * tablets which don't report that.
48 *
49 * @t: The timer the timeout handler is attached to, stored in a struct
50 * uclogic_drvdata.
51 */
52static void uclogic_inrange_timeout(struct timer_list *t)
53{
54 struct uclogic_drvdata *drvdata = from_timer(drvdata, t,
55 inrange_timer);
56 struct input_dev *input = drvdata->pen_input;
57
58 if (input == NULL)
59 return;
60 input_report_abs(input, ABS_PRESSURE, 0);
61 /* If BTN_TOUCH state is changing */
62 if (test_bit(BTN_TOUCH, input->key)) {
63 input_event(input, EV_MSC, MSC_SCAN,
64 /* Digitizer Tip Switch usage */
65 0xd0042);
66 input_report_key(input, BTN_TOUCH, 0);
67 }
68 input_report_key(input, BTN_TOOL_PEN, 0);
69 input_sync(input);
70}
71
ff0c13d6
NK
72static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
73 unsigned int *rsize)
74{
ff0c13d6
NK
75 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
76
9614219e
NK
77 if (drvdata->desc_ptr != NULL) {
78 rdesc = drvdata->desc_ptr;
79 *rsize = drvdata->desc_size;
ff0c13d6 80 }
ff0c13d6
NK
81 return rdesc;
82}
83
ff0c13d6
NK
84static int uclogic_input_configured(struct hid_device *hdev,
85 struct hid_input *hi)
86{
01309e29
NK
87 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
88 struct uclogic_params *params = &drvdata->params;
ff0c13d6
NK
89 char *name;
90 const char *suffix = NULL;
91 struct hid_field *field;
92 size_t len;
93
94 /* no report associated (HID_QUIRK_MULTI_INPUT not set) */
95 if (!hi->report)
96 return 0;
97
01309e29
NK
98 /*
99 * If this is the input corresponding to the pen report
100 * in need of tweaking.
101 */
102 if (hi->report->id == params->pen.id) {
103 /* Remember the input device so we can simulate events */
104 drvdata->pen_input = hi->input;
105 }
106
ff0c13d6
NK
107 field = hi->report->field[0];
108
109 switch (field->application) {
110 case HID_GD_KEYBOARD:
111 suffix = "Keyboard";
112 break;
113 case HID_GD_MOUSE:
114 suffix = "Mouse";
115 break;
116 case HID_GD_KEYPAD:
117 suffix = "Pad";
118 break;
119 case HID_DG_PEN:
120 suffix = "Pen";
121 break;
122 case HID_CP_CONSUMER_CONTROL:
123 suffix = "Consumer Control";
124 break;
125 case HID_GD_SYSTEM_CONTROL:
126 suffix = "System Control";
127 break;
128 }
129
130 if (suffix) {
131 len = strlen(hdev->name) + 2 + strlen(suffix);
132 name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
133 if (name) {
134 snprintf(name, len, "%s %s", hdev->name, suffix);
135 hi->input->name = name;
136 }
137 }
138
139 return 0;
140}
141
ff0c13d6
NK
142static int uclogic_probe(struct hid_device *hdev,
143 const struct hid_device_id *id)
144{
145 int rc;
9614219e
NK
146 struct uclogic_drvdata *drvdata = NULL;
147 bool params_initialized = false;
ff0c13d6 148
93020953
GKH
149 if (!hid_is_usb(hdev))
150 return -EINVAL;
151
ff0c13d6
NK
152 /*
153 * libinput requires the pad interface to be on a different node
154 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
155 */
156 hdev->quirks |= HID_QUIRK_MULTI_INPUT;
157
158 /* Allocate and assign driver data */
159 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
9614219e
NK
160 if (drvdata == NULL) {
161 rc = -ENOMEM;
162 goto failure;
163 }
01309e29 164 timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
8a47670c 165 drvdata->re_state = U8_MAX;
ff0c13d6
NK
166 hid_set_drvdata(hdev, drvdata);
167
9614219e
NK
168 /* Initialize the device and retrieve interface parameters */
169 rc = uclogic_params_init(&drvdata->params, hdev);
170 if (rc != 0) {
171 hid_err(hdev, "failed probing parameters: %d\n", rc);
172 goto failure;
173 }
174 params_initialized = true;
175 hid_dbg(hdev, "parameters:\n" UCLOGIC_PARAMS_FMT_STR,
176 UCLOGIC_PARAMS_FMT_ARGS(&drvdata->params));
177 if (drvdata->params.invalid) {
178 hid_info(hdev, "interface is invalid, ignoring\n");
179 rc = -ENODEV;
180 goto failure;
181 }
ff0c13d6 182
9614219e
NK
183 /* Generate replacement report descriptor */
184 rc = uclogic_params_get_desc(&drvdata->params,
185 &drvdata->desc_ptr,
186 &drvdata->desc_size);
187 if (rc) {
188 hid_err(hdev,
189 "failed generating replacement report descriptor: %d\n",
190 rc);
191 goto failure;
ff0c13d6
NK
192 }
193
194 rc = hid_parse(hdev);
195 if (rc) {
196 hid_err(hdev, "parse failed\n");
9614219e 197 goto failure;
ff0c13d6
NK
198 }
199
200 rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
201 if (rc) {
202 hid_err(hdev, "hw start failed\n");
9614219e 203 goto failure;
ff0c13d6
NK
204 }
205
206 return 0;
9614219e
NK
207failure:
208 /* Assume "remove" might not be called if "probe" failed */
209 if (params_initialized)
210 uclogic_params_cleanup(&drvdata->params);
211 return rc;
ff0c13d6
NK
212}
213
251b4275
NK
214#ifdef CONFIG_PM
215static int uclogic_resume(struct hid_device *hdev)
216{
217 int rc;
218 struct uclogic_params params;
219
220 /* Re-initialize the device, but discard parameters */
221 rc = uclogic_params_init(&params, hdev);
222 if (rc != 0)
223 hid_err(hdev, "failed to re-initialize the device\n");
224 else
225 uclogic_params_cleanup(&params);
226
227 return rc;
228}
229#endif
230
7e418667
NK
231/**
232 * uclogic_raw_event_pen - handle raw pen events (pen HID reports).
233 *
234 * @drvdata: Driver data.
235 * @data: Report data buffer, can be modified.
236 * @size: Report data size, bytes.
237 *
238 * Returns:
239 * Negative value on error (stops event delivery), zero for success.
240 */
241static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
242 u8 *data, int size)
243{
7f12dd24 244 struct uclogic_params_pen *pen = &drvdata->params.pen;
7e418667
NK
245
246 WARN_ON(drvdata == NULL);
247 WARN_ON(data == NULL && size != 0);
248
249 /* If in-range reports are inverted */
7f12dd24 250 if (pen->inrange ==
7e418667
NK
251 UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
252 /* Invert the in-range bit */
253 data[1] ^= 0x40;
254 }
255 /*
256 * If report contains fragmented high-resolution pen
257 * coordinates
258 */
7f12dd24 259 if (size >= 10 && pen->fragmented_hires) {
7e418667
NK
260 u8 pressure_low_byte;
261 u8 pressure_high_byte;
262
263 /* Lift pressure bytes */
264 pressure_low_byte = data[6];
265 pressure_high_byte = data[7];
266 /*
267 * Move Y coord to make space for high-order X
268 * coord byte
269 */
270 data[6] = data[5];
271 data[5] = data[4];
272 /* Move high-order X coord byte */
273 data[4] = data[8];
274 /* Move high-order Y coord byte */
275 data[7] = data[9];
276 /* Place pressure bytes */
277 data[8] = pressure_low_byte;
278 data[9] = pressure_high_byte;
279 }
280 /* If we need to emulate in-range detection */
7f12dd24 281 if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
7e418667
NK
282 /* Set in-range bit */
283 data[1] |= 0x40;
284 /* (Re-)start in-range timeout */
285 mod_timer(&drvdata->inrange_timer,
286 jiffies + msecs_to_jiffies(100));
287 }
288 /* If we report tilt and Y direction is flipped */
7f12dd24 289 if (size >= 12 && pen->tilt_y_flipped)
7e418667
NK
290 data[11] = -data[11];
291
292 return 0;
293}
294
295/**
296 * uclogic_raw_event_frame - handle raw frame events (frame HID reports).
297 *
298 * @drvdata: Driver data.
299 * @data: Report data buffer, can be modified.
300 * @size: Report data size, bytes.
301 *
302 * Returns:
303 * Negative value on error (stops event delivery), zero for success.
304 */
305static int uclogic_raw_event_frame(struct uclogic_drvdata *drvdata,
306 u8 *data, int size)
307{
7f12dd24 308 struct uclogic_params_frame *frame = &drvdata->params.frame;
7e418667
NK
309
310 WARN_ON(drvdata == NULL);
311 WARN_ON(data == NULL && size != 0);
312
313 /* If need to, and can, set pad device ID for Wacom drivers */
7f12dd24
NK
314 if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
315 data[frame->dev_id_byte] = 0xf;
7e418667
NK
316 }
317 /* If need to, and can, read rotary encoder state change */
7f12dd24
NK
318 if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
319 unsigned int byte = frame->re_lsb / 8;
320 unsigned int bit = frame->re_lsb % 8;
7e418667
NK
321
322 u8 change;
323 u8 prev_state = drvdata->re_state;
324 /* Read Gray-coded state */
325 u8 state = (data[byte] >> bit) & 0x3;
326 /* Encode state change into 2-bit signed integer */
327 if ((prev_state == 1 && state == 0) ||
328 (prev_state == 2 && state == 3)) {
329 change = 1;
330 } else if ((prev_state == 2 && state == 0) ||
331 (prev_state == 1 && state == 3)) {
332 change = 3;
333 } else {
334 change = 0;
335 }
336 /* Write change */
337 data[byte] = (data[byte] & ~((u8)3 << bit)) |
338 (change << bit);
339 /* Remember state */
340 drvdata->re_state = state;
341 }
342
343 return 0;
344}
345
9614219e
NK
346static int uclogic_raw_event(struct hid_device *hdev,
347 struct hid_report *report,
348 u8 *data, int size)
ff0c13d6 349{
044fa816 350 unsigned int report_id = report->id;
ff0c13d6 351 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
9614219e 352 struct uclogic_params *params = &drvdata->params;
8b013098
NK
353 struct uclogic_params_pen_subreport *subreport;
354 struct uclogic_params_pen_subreport *subreport_list_end;
ff0c13d6 355
fea53b9f
NK
356 /* Do not handle anything but input reports */
357 if (report->type != HID_INPUT_REPORT)
358 return 0;
359
8b013098
NK
360 while (true) {
361 /* Tweak pen reports, if necessary */
362 if ((report_id == params->pen.id) && (size >= 2)) {
363 subreport_list_end =
364 params->pen.subreport_list +
365 ARRAY_SIZE(params->pen.subreport_list);
366 /* Try to match a subreport */
367 for (subreport = params->pen.subreport_list;
e6be956f
NK
368 subreport < subreport_list_end; subreport++) {
369 if (subreport->value != 0 &&
370 subreport->value == data[1]) {
371 break;
372 }
373 }
8b013098
NK
374 /* If a subreport matched */
375 if (subreport < subreport_list_end) {
376 /* Change to subreport ID, and restart */
377 report_id = data[0] = subreport->id;
378 continue;
379 } else {
380 return uclogic_raw_event_pen(drvdata, data, size);
381 }
9614219e 382 }
ff0c13d6 383
8b013098
NK
384 /* Tweak frame control reports, if necessary */
385 if (report_id == params->frame.id)
386 return uclogic_raw_event_frame(drvdata, data, size);
387
388 break;
389 }
fde44ac5 390
ff0c13d6
NK
391 return 0;
392}
393
9614219e
NK
394static void uclogic_remove(struct hid_device *hdev)
395{
396 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
397
01309e29 398 del_timer_sync(&drvdata->inrange_timer);
9614219e
NK
399 hid_hw_stop(hdev);
400 kfree(drvdata->desc_ptr);
401 uclogic_params_cleanup(&drvdata->params);
402}
403
ff0c13d6
NK
404static const struct hid_device_id uclogic_devices[] = {
405 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
406 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
407 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
408 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
409 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
410 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
411 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
412 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
413 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
414 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
415 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
416 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
417 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
418 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
9614219e
NK
419 { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
420 USB_DEVICE_ID_HUION_TABLET) },
315ffcc9 421 { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
85e86071 422 USB_DEVICE_ID_HUION_TABLET2) },
f7271b2a
CK
423 { HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
424 USB_DEVICE_ID_TRUST_PANORA_TABLET) },
9614219e
NK
425 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
426 USB_DEVICE_ID_HUION_TABLET) },
427 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
428 USB_DEVICE_ID_YIYNOVA_TABLET) },
429 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
430 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81) },
431 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
432 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45) },
0c15efe9
NK
433 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
434 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47) },
9614219e
NK
435 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
436 USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
437 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
438 USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
022fc531
MS
439 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER,
440 USB_DEVICE_ID_UGTIZER_TABLET_GT5040) },
e902ed93
NK
441 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
442 USB_DEVICE_ID_UGEE_TABLET_G5) },
9614219e
NK
443 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
444 USB_DEVICE_ID_UGEE_TABLET_EX07S) },
88bb346d
WX
445 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
446 USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720) },
c3e5a67c
NK
447 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
448 USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540) },
492a9e9a
NK
449 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
450 USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) },
08367be1
NK
451 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE,
452 USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) },
ff0c13d6
NK
453 { }
454};
455MODULE_DEVICE_TABLE(hid, uclogic_devices);
456
457static struct hid_driver uclogic_driver = {
458 .name = "uclogic",
459 .id_table = uclogic_devices,
460 .probe = uclogic_probe,
9614219e 461 .remove = uclogic_remove,
ff0c13d6
NK
462 .report_fixup = uclogic_report_fixup,
463 .raw_event = uclogic_raw_event,
ff0c13d6 464 .input_configured = uclogic_input_configured,
251b4275
NK
465#ifdef CONFIG_PM
466 .resume = uclogic_resume,
467 .reset_resume = uclogic_resume,
468#endif
ff0c13d6
NK
469};
470module_hid_driver(uclogic_driver);
471
472MODULE_AUTHOR("Martin Rusko");
473MODULE_AUTHOR("Nikolai Kondrashov");
474MODULE_LICENSE("GPL");