Skip to content

Commit b146dbb

Browse files
author
Jiri Kosina
committed
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
2 parents bda3c85 + 337fa05 commit b146dbb

File tree

6 files changed

+358
-299
lines changed

6 files changed

+358
-299
lines changed

drivers/hid/hid-ids.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,7 @@
614614

615615
#define USB_VENDOR_ID_HUION 0x256c
616616
#define USB_DEVICE_ID_HUION_TABLET 0x006e
617-
#define USB_DEVICE_ID_HUION_HS64 0x006d
617+
#define USB_DEVICE_ID_HUION_TABLET2 0x006d
618618

619619
#define USB_VENDOR_ID_IBM 0x04b3
620620
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100

drivers/hid/hid-uclogic-core.c

Lines changed: 155 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
8181
return rdesc;
8282
}
8383

84-
static int uclogic_input_mapping(struct hid_device *hdev,
85-
struct hid_input *hi,
86-
struct hid_field *field,
87-
struct hid_usage *usage,
88-
unsigned long **bit,
89-
int *max)
90-
{
91-
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
92-
struct uclogic_params *params = &drvdata->params;
93-
94-
/* discard the unused pen interface */
95-
if (params->pen_unused && (field->application == HID_DG_PEN))
96-
return -1;
97-
98-
/* let hid-core decide what to do */
99-
return 0;
100-
}
101-
10284
static int uclogic_input_configured(struct hid_device *hdev,
10385
struct hid_input *hi)
10486
{
@@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev)
246228
}
247229
#endif
248230

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+
*/
241+
static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
242+
u8 *data, int size)
243+
{
244+
struct uclogic_params_pen *pen = &drvdata->params.pen;
245+
246+
WARN_ON(drvdata == NULL);
247+
WARN_ON(data == NULL && size != 0);
248+
249+
/* If in-range reports are inverted */
250+
if (pen->inrange ==
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+
*/
259+
if (size >= 10 && pen->fragmented_hires) {
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 */
281+
if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
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 */
289+
if (size >= 12 && pen->tilt_y_flipped)
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+
* @frame: The parameters of the frame controls to handle.
300+
* @data: Report data buffer, can be modified.
301+
* @size: Report data size, bytes.
302+
*
303+
* Returns:
304+
* Negative value on error (stops event delivery), zero for success.
305+
*/
306+
static int uclogic_raw_event_frame(
307+
struct uclogic_drvdata *drvdata,
308+
const struct uclogic_params_frame *frame,
309+
u8 *data, int size)
310+
{
311+
WARN_ON(drvdata == NULL);
312+
WARN_ON(data == NULL && size != 0);
313+
314+
/* If need to, and can, set pad device ID for Wacom drivers */
315+
if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
316+
data[frame->dev_id_byte] = 0xf;
317+
}
318+
/* If need to, and can, read rotary encoder state change */
319+
if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
320+
unsigned int byte = frame->re_lsb / 8;
321+
unsigned int bit = frame->re_lsb % 8;
322+
323+
u8 change;
324+
u8 prev_state = drvdata->re_state;
325+
/* Read Gray-coded state */
326+
u8 state = (data[byte] >> bit) & 0x3;
327+
/* Encode state change into 2-bit signed integer */
328+
if ((prev_state == 1 && state == 0) ||
329+
(prev_state == 2 && state == 3)) {
330+
change = 1;
331+
} else if ((prev_state == 2 && state == 0) ||
332+
(prev_state == 1 && state == 3)) {
333+
change = 3;
334+
} else {
335+
change = 0;
336+
}
337+
/* Write change */
338+
data[byte] = (data[byte] & ~((u8)3 << bit)) |
339+
(change << bit);
340+
/* Remember state */
341+
drvdata->re_state = state;
342+
}
343+
344+
return 0;
345+
}
346+
249347
static int uclogic_raw_event(struct hid_device *hdev,
250348
struct hid_report *report,
251349
u8 *data, int size)
252350
{
351+
unsigned int report_id = report->id;
253352
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
254353
struct uclogic_params *params = &drvdata->params;
354+
struct uclogic_params_pen_subreport *subreport;
355+
struct uclogic_params_pen_subreport *subreport_list_end;
356+
size_t i;
255357

256-
/* Tweak pen reports, if necessary */
257-
if (!params->pen_unused &&
258-
(report->type == HID_INPUT_REPORT) &&
259-
(report->id == params->pen.id) &&
260-
(size >= 2)) {
261-
/* If it's the "virtual" frame controls report */
262-
if (params->frame.id != 0 &&
263-
data[1] & params->pen_frame_flag) {
264-
/* Change to virtual frame controls report ID */
265-
data[0] = params->frame.id;
266-
return 0;
267-
}
268-
/* If in-range reports are inverted */
269-
if (params->pen.inrange ==
270-
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
271-
/* Invert the in-range bit */
272-
data[1] ^= 0x40;
273-
}
274-
/*
275-
* If report contains fragmented high-resolution pen
276-
* coordinates
277-
*/
278-
if (size >= 10 && params->pen.fragmented_hires) {
279-
u8 pressure_low_byte;
280-
u8 pressure_high_byte;
281-
282-
/* Lift pressure bytes */
283-
pressure_low_byte = data[6];
284-
pressure_high_byte = data[7];
285-
/*
286-
* Move Y coord to make space for high-order X
287-
* coord byte
288-
*/
289-
data[6] = data[5];
290-
data[5] = data[4];
291-
/* Move high-order X coord byte */
292-
data[4] = data[8];
293-
/* Move high-order Y coord byte */
294-
data[7] = data[9];
295-
/* Place pressure bytes */
296-
data[8] = pressure_low_byte;
297-
data[9] = pressure_high_byte;
298-
}
299-
/* If we need to emulate in-range detection */
300-
if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
301-
/* Set in-range bit */
302-
data[1] |= 0x40;
303-
/* (Re-)start in-range timeout */
304-
mod_timer(&drvdata->inrange_timer,
305-
jiffies + msecs_to_jiffies(100));
306-
}
307-
}
358+
/* Do not handle anything but input reports */
359+
if (report->type != HID_INPUT_REPORT)
360+
return 0;
308361

309-
/* Tweak frame control reports, if necessary */
310-
if ((report->type == HID_INPUT_REPORT) &&
311-
(report->id == params->frame.id)) {
312-
/* If need to, and can, set pad device ID for Wacom drivers */
313-
if (params->frame.dev_id_byte > 0 &&
314-
params->frame.dev_id_byte < size) {
315-
data[params->frame.dev_id_byte] = 0xf;
316-
}
317-
/* If need to, and can, read rotary encoder state change */
318-
if (params->frame.re_lsb > 0 &&
319-
params->frame.re_lsb / 8 < size) {
320-
unsigned int byte = params->frame.re_lsb / 8;
321-
unsigned int bit = params->frame.re_lsb % 8;
322-
323-
u8 change;
324-
u8 prev_state = drvdata->re_state;
325-
/* Read Gray-coded state */
326-
u8 state = (data[byte] >> bit) & 0x3;
327-
/* Encode state change into 2-bit signed integer */
328-
if ((prev_state == 1 && state == 0) ||
329-
(prev_state == 2 && state == 3)) {
330-
change = 1;
331-
} else if ((prev_state == 2 && state == 0) ||
332-
(prev_state == 1 && state == 3)) {
333-
change = 3;
362+
while (true) {
363+
/* Tweak pen reports, if necessary */
364+
if ((report_id == params->pen.id) && (size >= 2)) {
365+
subreport_list_end =
366+
params->pen.subreport_list +
367+
ARRAY_SIZE(params->pen.subreport_list);
368+
/* Try to match a subreport */
369+
for (subreport = params->pen.subreport_list;
370+
subreport < subreport_list_end; subreport++) {
371+
if (subreport->value != 0 &&
372+
subreport->value == data[1]) {
373+
break;
374+
}
375+
}
376+
/* If a subreport matched */
377+
if (subreport < subreport_list_end) {
378+
/* Change to subreport ID, and restart */
379+
report_id = data[0] = subreport->id;
380+
continue;
334381
} else {
335-
change = 0;
382+
return uclogic_raw_event_pen(drvdata, data, size);
383+
}
384+
}
385+
386+
/* Tweak frame control reports, if necessary */
387+
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
388+
if (report_id == params->frame_list[i].id) {
389+
return uclogic_raw_event_frame(
390+
drvdata, &params->frame_list[i],
391+
data, size);
336392
}
337-
/* Write change */
338-
data[byte] = (data[byte] & ~((u8)3 << bit)) |
339-
(change << bit);
340-
/* Remember state */
341-
drvdata->re_state = state;
342393
}
394+
395+
break;
343396
}
344397

345398
return 0;
@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
373426
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
374427
USB_DEVICE_ID_HUION_TABLET) },
375428
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
376-
USB_DEVICE_ID_HUION_HS64) },
429+
USB_DEVICE_ID_HUION_TABLET2) },
377430
{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
378431
USB_DEVICE_ID_TRUST_PANORA_TABLET) },
379432
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
415468
.remove = uclogic_remove,
416469
.report_fixup = uclogic_report_fixup,
417470
.raw_event = uclogic_raw_event,
418-
.input_mapping = uclogic_input_mapping,
419471
.input_configured = uclogic_input_configured,
420472
#ifdef CONFIG_PM
421473
.resume = uclogic_resume,

0 commit comments

Comments
 (0)