Commit 5d28bc6b authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-6.15/bpf' into for-linus

- a few hid-bpf device fixes from udev-hid-bpf; XP-Pen and Huion plus one from
  TUXEDO (Benjamin Tissoires)
parents ac91d5c7 834da375
Loading
Loading
Loading
Loading
+71 −4
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ static const __u8 fixed_rdesc[] = {
	0x15, 0x00,                    //   Logical Minimum (0)               22
	0x25, 0x01,                    //   Logical Maximum (1)               24
	0x75, 0x01,                    //   Report Size (1)                   26
	0x95, 0x05,                    //   Report Count (5)                  28 /* changed (was 5) */
	0x95, 0x05,                    //   Report Count (5)                  28 /* changed (was 6) */
	0x81, 0x02,                    //   Input (Data,Var,Abs)              30
	0x05, 0x09,                    //   Usage Page (Button)                  /* inserted */
	0x09, 0x4a,                    //   Usage (0x4a)                         /* inserted to be translated as input usage 0x149: BTN_STYLUS3 */
@@ -189,8 +189,68 @@ static const __u8 fixed_rdesc[] = {
	0x96, 0x00, 0x01,              //  Report Count (256)                 322
	0xb1, 0x02,                    //  Feature (Data,Var,Abs)             325
	0xc0,                          // End Collection                      327
	/* New in Firmware Version: HUION_M220_240524 */
	0x05, 0x01,                    // Usage Page (Generic Desktop)            328
	0x09, 0x01,                    // Usage (Pointer)                         330
	0xa1, 0x01,                    // Collection (Application)                332
	0x09, 0x01,                    //   Usage (Pointer)                       334
	0xa1, 0x00,                    //   Collection (Physical)                 336
	0x05, 0x09,                    //     Usage Page (Button)                 338
	0x19, 0x01,                    //     UsageMinimum (1)                    340
	0x29, 0x03,                    //     UsageMaximum (3)                    342
	0x15, 0x00,                    //     Logical Minimum (0)                 344
	0x25, 0x01,                    //     Logical Maximum (1)                 346
	0x85, 0x02,                    //     Report ID (2)                       348
	0x95, 0x03,                    //     Report Count (3)                    350
	0x75, 0x01,                    //     Report Size (1)                     352
	0x81, 0x02,                    //     Input (Data,Var,Abs)                354
	0x95, 0x01,                    //     Report Count (1)                    356
	0x75, 0x05,                    //     Report Size (5)                     358
	0x81, 0x01,                    //     Input (Cnst,Arr,Abs)                360
	0x05, 0x01,                    //     Usage Page (Generic Desktop)        362
	0x09, 0x30,                    //     Usage (X)                           364
	0x09, 0x31,                    //     Usage (Y)                           366
	0x15, 0x81,                    //     Logical Minimum (-127)              368
	0x25, 0x7f,                    //     Logical Maximum (127)               370
	0x75, 0x08,                    //     Report Size (8)                     372
	0x95, 0x02,                    //     Report Count (2)                    374
	0x81, 0x06,                    //     Input (Data,Var,Rel)                376
	0x95, 0x04,                    //     Report Count (4)                    378
	0x75, 0x08,                    //     Report Size (8)                     380
	0x81, 0x01,                    //     Input (Cnst,Arr,Abs)                382
	0xc0,                          //   End Collection                        384
	0xc0,                          // End Collection                          385
	0x05, 0x0d,                    // Usage Page (Digitizers)                 386
	0x09, 0x05,                    // Usage (Touch Pad)                       388
	0xa1, 0x01,                    // Collection (Application)                390
	0x06, 0x00, 0xff,              //   Usage Page (Vendor Defined Page FF00) 392
	0x09, 0x0c,                    //   Usage (Vendor Usage 0x0c)             395
	0x15, 0x00,                    //   Logical Minimum (0)                   397
	0x26, 0xff, 0x00,              //   Logical Maximum (255)                 399
	0x75, 0x08,                    //   Report Size (8)                       402
	0x95, 0x10,                    //   Report Count (16)                     404
	0x85, 0x3f,                    //   Report ID (63)                        406
	0x81, 0x22,                    //   Input (Data,Var,Abs,NoPref)           408
	0xc0,                          // End Collection                          410
	0x06, 0x00, 0xff,              // Usage Page (Vendor Defined Page FF00)   411
	0x09, 0x0c,                    // Usage (Vendor Usage 0x0c)               414
	0xa1, 0x01,                    // Collection (Application)                416
	0x06, 0x00, 0xff,              //   Usage Page (Vendor Defined Page FF00) 418
	0x09, 0x0c,                    //   Usage (Vendor Usage 0x0c)             421
	0x15, 0x00,                    //   Logical Minimum (0)                   423
	0x26, 0xff, 0x00,              //   Logical Maximum (255)                 425
	0x85, 0x44,                    //   Report ID (68)                        428
	0x75, 0x08,                    //   Report Size (8)                       430
	0x96, 0x6b, 0x05,              //   Report Count (1387)                   432
	0x81, 0x00,                    //   Input (Data,Arr,Abs)                  435
	0xc0,                          // End Collection                          437
};

#define PRE_240524_RDESC_SIZE 328
#define PRE_240524_RDESC_FIXED_SIZE 338 /* The original bits of the descriptor */
#define FW_240524_RDESC_SIZE 438
#define FW_240524_RDESC_FIXED_SIZE sizeof(fixed_rdesc)

SEC(HID_BPF_RDESC_FIXUP)
int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)
{
@@ -199,11 +259,16 @@ int BPF_PROG(hid_fix_rdesc_huion_kamvas_pro_19, struct hid_bpf_ctx *hctx)
	if (!data)
		return 0; /* EPERM check */

	__builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc));

	if (hctx->size == FW_240524_RDESC_SIZE) {
		__builtin_memcpy(data, fixed_rdesc, FW_240524_RDESC_FIXED_SIZE);
		return sizeof(fixed_rdesc);
	}

	__builtin_memcpy(data, fixed_rdesc, PRE_240524_RDESC_FIXED_SIZE);

	return PRE_240524_RDESC_FIXED_SIZE;
}

/*
 * This tablet reports the 3rd button through invert, but this conflict
 * with the normal eraser mode.
@@ -263,7 +328,9 @@ HID_BPF_OPS(huion_Kamvas_pro_19) = {
SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
	ctx->retval = ctx->rdesc_size != 328;

	ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||
			(ctx->rdesc_size == FW_240524_RDESC_SIZE));
	if (ctx->retval)
		ctx->retval = -EINVAL;

+531 −0

File added.

Preview size limit exceeded, changes collapsed.

+47 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (c) 2025 TUXEDO Computers GmbH
 */

#include "vmlinux.h"
#include "hid_bpf.h"
#include "hid_bpf_helpers.h"
#include <bpf/bpf_tracing.h>

HID_BPF_CONFIG(
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 0x048D, 0x8910)
);

SEC(HID_BPF_DEVICE_EVENT)
int BPF_PROG(ignore_key_fix_event, struct hid_bpf_ctx *hid_ctx)
{
	const int expected_length = 37;
	const int expected_report_id = 1;
	__u8 *data;
	int i;

	if (hid_ctx->size < expected_length)
		return 0;

	data = hid_bpf_get_data(hid_ctx, 0, expected_length);
	if (!data || data[0] != expected_report_id)
		return 0;

	// Zero out F13 (HID usage ID: 0x68) key press.
	// The first 6 parallel key presses (excluding modifier keys) are
	// encoded in an array containing usage IDs.
	for (i = 3; i < 9; ++i)
		if (data[i] == 0x68)
			data[i] = 0x00;
	// Additional parallel key presses starting with the 7th (excluding
	// modifier keys) are encoded as a bit flag with the offset being
	// the usage ID.
	data[22] &= 0xfe;

	return 0;
}

HID_BPF_OPS(ignore_button) = {
	.hid_device_event = (void *)ignore_key_fix_event,
};

char _license[] SEC("license") = "GPL";
+330 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2024 Red Hat, Inc
 */

#include "vmlinux.h"
#include "hid_bpf.h"
#include "hid_bpf_helpers.h"
#include "hid_report_helpers.h"
#include <bpf/bpf_tracing.h>

#define HID_BPF_ASYNC_MAX_CTX 1
#include "hid_bpf_async.h"

#define VID_UGEE		0x28BD
/* same PID whether connected directly or through the provided dongle: */
#define PID_ACK05_REMOTE	0x0202


HID_BPF_CONFIG(
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ACK05_REMOTE),
);

/*
 * By default, the pad reports the buttons through a set of key sequences.
 *
 * The pad reports a classic keyboard report descriptor:
 * # HANVON UGEE Shortcut Remote
 * Report descriptor length: 102 bytes
 *  0x05, 0x01,                    // Usage Page (Generic Desktop)              0
 *  0x09, 0x02,                    // Usage (Mouse)                             2
 *  0xa1, 0x01,                    // Collection (Application)                  4
 *  0x85, 0x09,                    //   Report ID (9)                           6
 *  0x09, 0x01,                    //   Usage (Pointer)                         8
 *  0xa1, 0x00,                    //   Collection (Physical)                   10
 *  0x05, 0x09,                    //     Usage Page (Button)                   12
 *  0x19, 0x01,                    //     UsageMinimum (1)                      14
 *  0x29, 0x03,                    //     UsageMaximum (3)                      16
 *  0x15, 0x00,                    //     Logical Minimum (0)                   18
 *  0x25, 0x01,                    //     Logical Maximum (1)                   20
 *  0x95, 0x03,                    //     Report Count (3)                      22
 *  0x75, 0x01,                    //     Report Size (1)                       24
 *  0x81, 0x02,                    //     Input (Data,Var,Abs)                  26
 *  0x95, 0x05,                    //     Report Count (5)                      28
 *  0x81, 0x01,                    //     Input (Cnst,Arr,Abs)                  30
 *  0x05, 0x01,                    //     Usage Page (Generic Desktop)          32
 *  0x09, 0x30,                    //     Usage (X)                             34
 *  0x09, 0x31,                    //     Usage (Y)                             36
 *  0x26, 0xff, 0x7f,              //     Logical Maximum (32767)               38
 *  0x95, 0x02,                    //     Report Count (2)                      41
 *  0x75, 0x10,                    //     Report Size (16)                      43
 *  0x81, 0x02,                    //     Input (Data,Var,Abs)                  45
 *  0x05, 0x0d,                    //     Usage Page (Digitizers)               47
 *  0x09, 0x30,                    //     Usage (Tip Pressure)                  49
 *  0x26, 0xff, 0x07,              //     Logical Maximum (2047)                51
 *  0x95, 0x01,                    //     Report Count (1)                      54
 *  0x75, 0x10,                    //     Report Size (16)                      56
 *  0x81, 0x02,                    //     Input (Data,Var,Abs)                  58
 *  0xc0,                          //   End Collection                          60
 *  0xc0,                          // End Collection                            61
 *  0x05, 0x01,                    // Usage Page (Generic Desktop)              62
 *  0x09, 0x06,                    // Usage (Keyboard)                          64
 *  0xa1, 0x01,                    // Collection (Application)                  66
 *  0x85, 0x06,                    //   Report ID (6)                           68
 *  0x05, 0x07,                    //   Usage Page (Keyboard/Keypad)            70
 *  0x19, 0xe0,                    //   UsageMinimum (224)                      72
 *  0x29, 0xe7,                    //   UsageMaximum (231)                      74
 *  0x15, 0x00,                    //   Logical Minimum (0)                     76
 *  0x25, 0x01,                    //   Logical Maximum (1)                     78
 *  0x75, 0x01,                    //   Report Size (1)                         80
 *  0x95, 0x08,                    //   Report Count (8)                        82
 *  0x81, 0x02,                    //   Input (Data,Var,Abs)                    84
 *  0x05, 0x07,                    //   Usage Page (Keyboard/Keypad)            86
 *  0x19, 0x00,                    //   UsageMinimum (0)                        88
 *  0x29, 0xff,                    //   UsageMaximum (255)                      90
 *  0x26, 0xff, 0x00,              //   Logical Maximum (255)                   92
 *  0x75, 0x08,                    //   Report Size (8)                         95
 *  0x95, 0x06,                    //   Report Count (6)                        97
 *  0x81, 0x00,                    //   Input (Data,Arr,Abs)                    99
 *  0xc0,                          // End Collection                            101
 *
 * Each button gets assigned the following events:
 *
 *   Buttons released: 06 00 00 00 00 00 00 00
 *   Button 1:         06 01 12 00 00 00 00 00 -> LControl + o
 *   Button 2:         06 01 11 00 00 00 00 00 -> LControl + n
 *   Button 3:         06 00 3e 00 00 00 00 00 -> F5
 *   Button 4:         06 02 00 00 00 00 00 00 -> LShift
 *   Button 5:         06 01 00 00 00 00 00 00 -> LControl
 *   Button 6:         06 04 00 00 00 00 00 00 -> LAlt
 *   Button 7:         06 01 16 00 00 00 00 00 -> LControl + s
 *   Button 8:         06 01 1d 00 00 00 00 00 -> LControl + z
 *   Button 9:         06 00 2c 00 00 00 00 00 -> Space
 *   Button 10:        06 03 1d 00 00 00 00 00 -> LControl + LShift + z
 *   Wheel:            06 01 57 00 00 00 00 00 -> clockwise rotation (LControl + Keypad Plus)
 *   Wheel:            06 01 56 00 00 00 00 00 -> counter-clockwise rotation
 *						  (LControl + Keypad Minus)
 *
 * However, multiple buttons can be pressed at the same time, and when this happens,
 * each button gets assigned a new slot in the Input (Data,Arr,Abs):
 *
 *   Button 1 + 3:     06 01 12 3e 00 00 00 00 -> LControl + o + F5
 *
 * When a modifier is pressed (Button 4, 5, or 6), the assigned key is set to 00:
 *
 *   Button 5 + 7:     06 01 00 16 00 00 00 00 -> LControl + s
 *
 * This is mostly fine, but with Button 8 and Button 10 sharing the same
 * key value ("z"), there are cases where we can not know which is which.
 *
 */

#define PAD_WIRED_DESCRIPTOR_LENGTH 102
#define PAD_DONGLE_DESCRIPTOR_LENGTH 177
#define STYLUS_DESCRIPTOR_LENGTH 109
#define VENDOR_DESCRIPTOR_LENGTH 36
#define PAD_REPORT_ID 6
#define RAW_PAD_REPORT_ID 0xf0
#define RAW_BATTERY_REPORT_ID 0xf2
#define VENDOR_REPORT_ID 2
#define PAD_REPORT_LENGTH 8
#define VENDOR_REPORT_LENGTH 12

__u16 last_button_state;

static const __u8 disabled_rdesc[] = {
	// Make sure we match our original report length
	FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
};

static const __u8 fixed_rdesc_vendor[] = {
	UsagePage_GenericDesktop
	Usage_GD_Keypad
	CollectionApplication(
		// -- Byte 0 in report
		ReportId(RAW_PAD_REPORT_ID)
		// Byte 1 in report - same than report ID
		ReportCount(1)
		ReportSize(8)
		Input(Const) // padding (internal report ID)
		LogicalMaximum_i8(0)
		LogicalMaximum_i8(1)
		UsagePage_Digitizers
		Usage_Dig_TabletFunctionKeys
		CollectionPhysical(
			// Byte 2-3 is the button state
			UsagePage_Button
			UsageMinimum_i8(0x01)
			UsageMaximum_i8(0x0a)
			LogicalMinimum_i8(0x0)
			LogicalMaximum_i8(0x1)
			ReportCount(10)
			ReportSize(1)
			Input(Var|Abs)
			Usage_i8(0x31) // will be mapped as BTN_A / BTN_SOUTH
			ReportCount(1)
			Input(Var|Abs)
			ReportCount(5) // padding
			Input(Const)
			// Byte 4 in report - just exists so we get to be a tablet pad
			Usage_Dig_BarrelSwitch // BTN_STYLUS
			ReportCount(1)
			ReportSize(1)
			Input(Var|Abs)
			ReportCount(7) // padding
			Input(Const)
			// Bytes 5/6 in report - just exists so we get to be a tablet pad
			UsagePage_GenericDesktop
			Usage_GD_X
			Usage_GD_Y
			ReportCount(2)
			ReportSize(8)
			Input(Var|Abs)
			// Byte 7 in report is the dial
			Usage_GD_Wheel
			LogicalMinimum_i8(-1)
			LogicalMaximum_i8(1)
			ReportCount(1)
			ReportSize(8)
			Input(Var|Rel)
		)
		// -- Byte 0 in report
		ReportId(RAW_BATTERY_REPORT_ID)
		// Byte 1 in report - same than report ID
		ReportCount(1)
		ReportSize(8)
		Input(Const) // padding (internal report ID)
		// Byte 2 in report - always 0x01
		Input(Const) // padding (internal report ID)
		UsagePage_Digitizers
		/*
		 * We represent the device as a stylus to force the kernel to not
		 * directly query its battery state. Instead the kernel will rely
		 * only on the provided events.
		 */
		Usage_Dig_Stylus
		CollectionPhysical(
			// Byte 3 in report - battery value
			UsagePage_BatterySystem
			Usage_BS_AbsoluteStateOfCharge
			LogicalMinimum_i8(0)
			LogicalMaximum_i8(100)
			ReportCount(1)
			ReportSize(8)
			Input(Var|Abs)
			// Byte 4 in report - charging state
			Usage_BS_Charging
			LogicalMinimum_i8(0)
			LogicalMaximum_i8(1)
			ReportCount(1)
			ReportSize(8)
			Input(Var|Abs)
		)
	)
};

SEC(HID_BPF_RDESC_FIXUP)
int BPF_PROG(ack05_fix_rdesc, struct hid_bpf_ctx *hctx)
{
	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
	__s32 rdesc_size = hctx->size;

	if (!data)
		return 0; /* EPERM check */

	if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) {
		/*
		 * The vendor fixed rdesc is appended after the current one,
		 * to keep the output reports working.
		 */
		__builtin_memcpy(data + rdesc_size, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
		return sizeof(fixed_rdesc_vendor) + rdesc_size;
	}

	hid_set_name(hctx->hid, "Disabled by HID-BPF Hanvon Ugee Shortcut Remote");

	__builtin_memcpy(data, disabled_rdesc, sizeof(disabled_rdesc));
	return sizeof(disabled_rdesc);
}

static int HID_BPF_ASYNC_FUN(switch_to_raw_mode)(struct hid_bpf_ctx *hid)
{
	static __u8 magic_0[32] = {0x02, 0xb0, 0x04, 0x00, 0x00};
	int err;

	/*
	 * The proprietary driver sends the 3 following packets after the
	 * above one.
	 * These don't seem to have any effect, so we don't send them to save
	 * some processing time.
	 *
	 * static __u8 magic_1[32] = {0x02, 0xb4, 0x01, 0x00, 0x01};
	 * static __u8 magic_2[32] = {0x02, 0xb4, 0x01, 0x00, 0xff};
	 * static __u8 magic_3[32] = {0x02, 0xb8, 0x04, 0x00, 0x00};
	 */

	err = hid_bpf_hw_output_report(hid, magic_0, sizeof(magic_0));
	if (err < 0)
		return err;

	return 0;
}

SEC(HID_BPF_DEVICE_EVENT)
int BPF_PROG(ack05_fix_events, struct hid_bpf_ctx *hctx)
{
	__u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH);
	int ret = 0;

	if (!data)
		return 0; /* EPERM check */

	if (data[0] != VENDOR_REPORT_ID)
		return 0;

	/* reconnect event */
	if (data[1] == 0xf8 && data[2] == 02 && data[3] == 0x01)
		HID_BPF_ASYNC_DELAYED_CALL(switch_to_raw_mode, hctx, 10);

	/* button event */
	if (data[1] == RAW_PAD_REPORT_ID) {
		data[0] = data[1];
		if (data[7] == 0x02)
			data[7] = 0xff;
		ret = 8;
	} else if (data[1] == RAW_BATTERY_REPORT_ID) {
		data[0] = data[1];
		ret = 5;
	}

	return ret;
}

HID_BPF_OPS(xppen_ack05_remote) = {
	.hid_device_event = (void *)ack05_fix_events,
	.hid_rdesc_fixup = (void *)ack05_fix_rdesc,
};

SEC("syscall")
int probe(struct hid_bpf_probe_args *ctx)
{
	switch (ctx->rdesc_size) {
	case PAD_WIRED_DESCRIPTOR_LENGTH:
	case PAD_DONGLE_DESCRIPTOR_LENGTH:
	case STYLUS_DESCRIPTOR_LENGTH:
	case VENDOR_DESCRIPTOR_LENGTH:
		ctx->retval = 0;
		break;
	default:
		ctx->retval = -EINVAL;
		break;
	}

	if (ctx->rdesc_size == VENDOR_DESCRIPTOR_LENGTH) {
		struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);

		if (!hctx) {
			ctx->retval = -EINVAL;
			return 0;
		}

		ctx->retval = HID_BPF_ASYNC_INIT(switch_to_raw_mode) ||
			      switch_to_raw_mode(hctx);

		hid_bpf_release_context(hctx);
	}

	return 0;
}

char _license[] SEC("license") = "GPL";
+40 −4
Original line number Diff line number Diff line
@@ -10,10 +10,12 @@
#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */
#define PID_ARTIST_PRO14_GEN2 0x095A
#define PID_ARTIST_PRO16_GEN2 0x095B
#define PID_ARTIST_PRO19_GEN2 0x096A

HID_BPF_CONFIG(
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO14_GEN2),
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO16_GEN2)
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO16_GEN2),
	HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_PRO19_GEN2)
);

/*
@@ -22,7 +24,7 @@ HID_BPF_CONFIG(
 * - when the eraser button is pressed and the stylus is touching the tablet,
 *   the device sends Tip Switch instead of sending Eraser
 *
 * This descriptor uses physical dimensions of the 16" device.
 * This descriptor uses the physical dimensions of the 16" device.
 */
static const __u8 fixed_rdesc[] = {
	0x05, 0x0d,                    // Usage Page (Digitizers)             0
@@ -100,6 +102,12 @@ int BPF_PROG(hid_fix_rdesc_xppen_artistpro16gen2, struct hid_bpf_ctx *hctx)
		data[62] = 0x62;
		data[73] = 0x1c;
		data[72] = 0xfd;
	} else if (hctx->hid->product == PID_ARTIST_PRO19_GEN2) {
		/* 19" screen reports 16.101" x 9.057" */
		data[63] = 0x3e;
		data[62] = 0xe5;
		data[73] = 0x23;
		data[72] = 0x61;
	}

	return sizeof(fixed_rdesc);
@@ -177,6 +185,27 @@ static const __u16 angle_offsets_vertical_16[128] = {
	188, 186, 184, 182, 180, 178, 176, 174, 172
};

/* 19" inch screen 16.101" x 9.057" */
static const __u16 angle_offsets_horizontal_19[128] = {
	0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 27, 29, 31, 33, 35, 37, 39, 41,
	42, 44, 46, 48, 50, 51, 53, 55, 57, 58, 60, 62, 63, 65, 67, 68, 70, 71, 73, 74, 76,
	77, 79, 80, 82, 83, 84, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, 100,
	101, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109, 109, 110, 110, 111,
	111, 112, 112, 112, 112, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
	113, 113, 112, 112, 112, 112, 111, 111, 110, 110, 109, 109, 108, 108, 107, 106,
	106, 105, 104, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 90
};
static const __u16 angle_offsets_vertical_19[128] = {
	0, 4, 7, 11, 14, 18, 21, 25, 28, 32, 35, 38, 42, 45, 49, 52, 56, 59, 62, 66, 69, 72,
	75, 79, 82, 85, 88, 91, 95, 98, 101, 104, 107, 110, 113, 116, 118, 121, 124, 127,
	129, 132, 135, 137, 140, 142, 145, 147, 150, 152, 154, 157, 159, 161, 163, 165, 167,
	169, 171, 173, 174, 176, 178, 179, 181, 183, 184, 185, 187, 188, 189, 190, 192, 193,
	194, 195, 195, 196, 197, 198, 198, 199, 199, 200, 200, 201, 201, 201, 201, 201, 201,
	201, 201, 201, 201, 201, 200, 200, 199, 199, 198, 198, 197, 196, 195, 195, 194, 193,
	192, 190, 189, 188, 187, 185, 184, 183, 181, 179, 178, 176, 174, 173, 171, 169, 167,
	165, 163, 161
};

static void compensate_coordinates_by_tilt(__u8 *data, const __u8 idx,
		const __s8 tilt, const __u16 (*compensation_table)[128])
{
@@ -241,12 +270,19 @@ static int xppen_16_fix_angle_offset(struct hid_bpf_ctx *hctx)
	__s8 tilt_x = (__s8) data[8];
	__s8 tilt_y = (__s8) data[9];

	if (hctx->hid->product == PID_ARTIST_PRO14_GEN2) {
	switch (hctx->hid->product) {
	case PID_ARTIST_PRO14_GEN2:
		compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_14);
		compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_14);
	} else if (hctx->hid->product == PID_ARTIST_PRO16_GEN2) {
		break;
	case PID_ARTIST_PRO16_GEN2:
		compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_16);
		compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_16);
		break;
	case PID_ARTIST_PRO19_GEN2:
		compensate_coordinates_by_tilt(data, 2, tilt_x, &angle_offsets_horizontal_19);
		compensate_coordinates_by_tilt(data, 4, tilt_y, &angle_offsets_vertical_19);
		break;
	}

	return 0;
Loading