summaryrefslogtreecommitdiffstats
path: root/drivers/hid/bpf
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-09-25 15:55:03 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-09-25 15:55:03 -0700
commit75467f60a3d14f08f86f2b353298d2826382ff23 (patch)
treeacd8a7d5b5a675042449386efa5b42ec44d8bf81 /drivers/hid/bpf
downloadlinux-stable-75467f60a3d14f08f86f2b353298d2826382ff23.tar.gz
linux-stable-75467f60a3d14f08f86f2b353298d2826382ff23.zip
Merge tag 'ipe-pr-20260925' of git://git.kernel.org/pub/scm/linux/kernel/git/wufan/ipegrafted
Pull IPE fixes from Fan Wu: "Two fixes for use-after-free issues found by recent LLM-assisted code analysis. - move successful policy load auditing under the new policy directory's inode lock, preventing a concurrent policy deletion from freeing the policy while it is still being audited - protect the dm-verity root hash with RCU, preventing policy evaluation from racing with root hash replacement during preresume" * tag 'ipe-pr-20260925' of git://git.kernel.org/pub/scm/linux/kernel/git/wufan/ipe: ipe: protect the dm-verity root hash with RCU ipe: fix use-after-free when auditing a newly loaded policy
Diffstat (limited to 'drivers/hid/bpf')
-rw-r--r--drivers/hid/bpf/Kconfig16
-rw-r--r--drivers/hid/bpf/Makefile11
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.c689
-rw-r--r--drivers/hid/bpf/hid_bpf_dispatch.h22
-rw-r--r--drivers/hid/bpf/hid_bpf_struct_ops.c341
-rw-r--r--drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c190
-rw-r--r--drivers/hid/bpf/progs/Generic__touchpad.bpf.c90
-rw-r--r--drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c62
-rw-r--r--drivers/hid/bpf/progs/Huion__Dial-2.bpf.c636
-rw-r--r--drivers/hid/bpf/progs/Huion__Inspiroy-2-M.bpf.c563
-rw-r--r--drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c579
-rw-r--r--drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c87
-rw-r--r--drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c366
-rw-r--r--drivers/hid/bpf/progs/Huion__Kamvas13Gen3.bpf.c1395
-rw-r--r--drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c724
-rw-r--r--drivers/hid/bpf/progs/Huion__KeydialK20-Bluetooth.bpf.c492
-rw-r--r--drivers/hid/bpf/progs/Huion__KeydialK20.bpf.c532
-rw-r--r--drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c63
-rw-r--r--drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c86
-rw-r--r--drivers/hid/bpf/progs/Makefile93
-rw-r--r--drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c136
-rw-r--r--drivers/hid/bpf/progs/Mistel__MD770.bpf.c154
-rw-r--r--drivers/hid/bpf/progs/README102
-rw-r--r--drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c148
-rw-r--r--drivers/hid/bpf/progs/TUXEDO__Sirius-16-Gen1-and-Gen2.bpf.c47
-rw-r--r--drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c144
-rw-r--r--drivers/hid/bpf/progs/Trust__Philips-SPK6327.bpf.c49
-rw-r--r--drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c321
-rw-r--r--drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c177
-rw-r--r--drivers/hid/bpf/progs/XPPen__ACK05.bpf.c331
-rw-r--r--drivers/hid/bpf/progs/XPPen__Artist24.bpf.c231
-rw-r--r--drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c324
-rw-r--r--drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c305
-rw-r--r--drivers/hid/bpf/progs/XPPen__Deco02.bpf.c359
-rw-r--r--drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c231
-rw-r--r--drivers/hid/bpf/progs/hid_bpf.h21
-rw-r--r--drivers/hid/bpf/progs/hid_bpf_async.h219
-rw-r--r--drivers/hid/bpf/progs/hid_bpf_helpers.h507
-rw-r--r--drivers/hid/bpf/progs/hid_report_descriptor_helpers.h80
-rw-r--r--drivers/hid/bpf/progs/hid_report_helpers.h2982
-rw-r--r--drivers/hid/bpf/progs/hid_usages.h2810
41 files changed, 16715 insertions, 0 deletions
diff --git a/drivers/hid/bpf/Kconfig b/drivers/hid/bpf/Kconfig
new file mode 100644
index 000000000..d65482e02
--- /dev/null
+++ b/drivers/hid/bpf/Kconfig
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "HID-BPF support"
+
+config HID_BPF
+ bool "HID-BPF support"
+ depends on BPF_JIT
+ depends on BPF_SYSCALL
+ depends on DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+ help
+ This option allows to support eBPF programs on the HID subsystem.
+ eBPF programs can fix HID devices in a lighter way than a full
+ kernel patch and allow a lot more flexibility.
+
+ For documentation, see Documentation/hid/hid-bpf.rst
+
+endmenu
diff --git a/drivers/hid/bpf/Makefile b/drivers/hid/bpf/Makefile
new file mode 100644
index 000000000..d1f2b8178
--- /dev/null
+++ b/drivers/hid/bpf/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for HID-BPF
+#
+
+LIBBPF_INCLUDE = $(srctree)/tools/lib
+
+obj-$(CONFIG_HID_BPF) += hid_bpf.o
+CFLAGS_hid_bpf_dispatch.o += -I$(LIBBPF_INCLUDE)
+CFLAGS_hid_bpf_jmp_table.o += -I$(LIBBPF_INCLUDE)
+hid_bpf-objs += hid_bpf_dispatch.o hid_bpf_struct_ops.o
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c
new file mode 100644
index 000000000..d46779b63
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -0,0 +1,689 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * HID-BPF support for Linux
+ *
+ * Copyright (c) 2022-2024 Benjamin Tissoires
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/bitops.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/filter.h>
+#include <linux/hid.h>
+#include <linux/hid_bpf.h>
+#include <linux/init.h>
+#include <linux/kfifo.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include "hid_bpf_dispatch.h"
+
+const struct hid_ops *hid_ops;
+EXPORT_SYMBOL(hid_ops);
+
+u8 *
+dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
+ size_t *buf_size, u32 *size, int interrupt, u64 source,
+ bool from_bpf)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .allocated_size = hdev->bpf.allocated_data,
+ .size = *size,
+ },
+ .data = hdev->bpf.device_data,
+ .from_bpf = from_bpf,
+ };
+ struct hid_bpf_ops *e;
+ int ret;
+
+ if (unlikely(hdev->bpf.destroyed))
+ return ERR_PTR(-ENODEV);
+
+ if (type >= HID_REPORT_TYPES)
+ return ERR_PTR(-EINVAL);
+
+ /* no program has been attached yet */
+ if (!hdev->bpf.device_data)
+ return data;
+
+ memset(ctx_kern.data, 0, hdev->bpf.allocated_data);
+ memcpy(ctx_kern.data, data, *size);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) {
+ if (e->hid_device_event) {
+ ret = e->hid_device_event(&ctx_kern.ctx, type, source);
+ if (ret < 0) {
+ rcu_read_unlock();
+ return ERR_PTR(ret);
+ }
+
+ if (ret)
+ ctx_kern.ctx.size = ret;
+ }
+ }
+ rcu_read_unlock();
+
+ ret = ctx_kern.ctx.size;
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ return ERR_PTR(-EINVAL);
+
+ *size = ret;
+ }
+
+ *buf_size = ctx_kern.ctx.allocated_size;
+ return ctx_kern.data;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_device_event);
+
+int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
+ unsigned char reportnum, u8 *buf,
+ u32 size, enum hid_report_type rtype,
+ enum hid_class_request reqtype,
+ u64 source, bool from_bpf)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .allocated_size = size,
+ .size = size,
+ },
+ .data = buf,
+ .from_bpf = from_bpf,
+ };
+ struct hid_bpf_ops *e;
+ int ret, idx;
+
+ if (unlikely(hdev->bpf.destroyed))
+ return -ENODEV;
+
+ if (rtype >= HID_REPORT_TYPES)
+ return -EINVAL;
+
+ idx = srcu_read_lock(&hdev->bpf.srcu);
+ list_for_each_entry_srcu(e, &hdev->bpf.prog_list, list,
+ srcu_read_lock_held(&hdev->bpf.srcu)) {
+ if (!e->hid_hw_request)
+ continue;
+
+ ret = e->hid_hw_request(&ctx_kern.ctx, reportnum, rtype, reqtype, source);
+ if (ret)
+ goto out;
+ }
+ ret = 0;
+
+out:
+ srcu_read_unlock(&hdev->bpf.srcu, idx);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_raw_requests);
+
+int dispatch_hid_bpf_output_report(struct hid_device *hdev,
+ __u8 *buf, u32 size, u64 source,
+ bool from_bpf)
+{
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .allocated_size = size,
+ .size = size,
+ },
+ .data = buf,
+ .from_bpf = from_bpf,
+ };
+ struct hid_bpf_ops *e;
+ int ret, idx;
+
+ if (unlikely(hdev->bpf.destroyed))
+ return -ENODEV;
+
+ idx = srcu_read_lock(&hdev->bpf.srcu);
+ list_for_each_entry_srcu(e, &hdev->bpf.prog_list, list,
+ srcu_read_lock_held(&hdev->bpf.srcu)) {
+ if (!e->hid_hw_output_report)
+ continue;
+
+ ret = e->hid_hw_output_report(&ctx_kern.ctx, source);
+ if (ret)
+ goto out;
+ }
+ ret = 0;
+
+out:
+ srcu_read_unlock(&hdev->bpf.srcu, idx);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dispatch_hid_bpf_output_report);
+
+const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size)
+{
+ int ret;
+ struct hid_bpf_ctx_kern ctx_kern = {
+ .ctx = {
+ .hid = hdev,
+ .size = *size,
+ .allocated_size = HID_MAX_DESCRIPTOR_SIZE,
+ },
+ };
+
+ if (!hdev->bpf.rdesc_ops)
+ goto ignore_bpf;
+
+ ctx_kern.data = kzalloc(ctx_kern.ctx.allocated_size, GFP_KERNEL);
+ if (!ctx_kern.data)
+ goto ignore_bpf;
+
+ memcpy(ctx_kern.data, rdesc, min_t(unsigned int, *size, HID_MAX_DESCRIPTOR_SIZE));
+
+ ret = hdev->bpf.rdesc_ops->hid_rdesc_fixup(&ctx_kern.ctx);
+ if (ret < 0)
+ goto ignore_bpf;
+
+ if (ret) {
+ if (ret > ctx_kern.ctx.allocated_size)
+ goto ignore_bpf;
+
+ *size = ret;
+ }
+
+ return krealloc(ctx_kern.data, *size, GFP_KERNEL);
+
+ ignore_bpf:
+ kfree(ctx_kern.data);
+ return rdesc;
+}
+EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
+
+static int device_match_id(struct device *dev, const void *id)
+{
+ struct hid_device *hdev = to_hid_device(dev);
+
+ return hdev->id == *(int *)id;
+}
+
+struct hid_device *hid_get_device(unsigned int hid_id)
+{
+ struct device *dev;
+
+ if (!hid_ops)
+ return ERR_PTR(-EINVAL);
+
+ dev = bus_find_device(hid_ops->bus_type, NULL, &hid_id, device_match_id);
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ return to_hid_device(dev);
+}
+
+void hid_put_device(struct hid_device *hid)
+{
+ put_device(&hid->dev);
+}
+
+static int __hid_bpf_allocate_data(struct hid_device *hdev, u8 **data, u32 *size)
+{
+ u8 *alloc_data;
+ unsigned int i, j, max_report_len = 0;
+ size_t alloc_size = 0;
+
+ /* compute the maximum report length for this device */
+ for (i = 0; i < HID_REPORT_TYPES; i++) {
+ struct hid_report_enum *report_enum = hdev->report_enum + i;
+
+ for (j = 0; j < HID_MAX_IDS; j++) {
+ struct hid_report *report = report_enum->report_id_hash[j];
+
+ if (report)
+ max_report_len = max(max_report_len, hid_report_len(report));
+ }
+ }
+
+ /*
+ * Give us a little bit of extra space and some predictability in the
+ * buffer length we create. This way, we can tell users that they can
+ * work on chunks of 64 bytes of memory without having the bpf verifier
+ * scream at them.
+ */
+ alloc_size = DIV_ROUND_UP(max_report_len, 64) * 64;
+
+ alloc_data = kzalloc(alloc_size, GFP_KERNEL);
+ if (!alloc_data)
+ return -ENOMEM;
+
+ *data = alloc_data;
+ *size = alloc_size;
+
+ return 0;
+}
+
+int hid_bpf_allocate_event_data(struct hid_device *hdev)
+{
+ /* hdev->bpf.device_data is already allocated, abort */
+ if (hdev->bpf.device_data)
+ return 0;
+
+ return __hid_bpf_allocate_data(hdev, &hdev->bpf.device_data, &hdev->bpf.allocated_data);
+}
+
+int hid_bpf_reconnect(struct hid_device *hdev)
+{
+ if (!test_and_set_bit(ffs(HID_STAT_REPROBED), &hdev->status)) {
+ /* trigger call to call_hid_bpf_rdesc_fixup() during the next probe */
+ hdev->bpf_rsize = 0;
+ return device_reprobe(&hdev->dev);
+ }
+
+ return 0;
+}
+
+/* Disables missing prototype warnings */
+__bpf_kfunc_start_defs();
+
+/**
+ * hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
+ *
+ * @ctx: The HID-BPF context
+ * @offset: The offset within the memory
+ * @rdwr_buf_size: the const size of the buffer
+ *
+ * @returns %NULL on error, an %__u8 memory pointer on success
+ */
+__bpf_kfunc __u8 *
+hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ size_t end;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+ if (check_add_overflow(rdwr_buf_size, offset, &end) ||
+ end > ctx->allocated_size)
+ return NULL;
+
+ return ctx_kern->data + offset;
+}
+
+/**
+ * hid_bpf_allocate_context - Allocate a context to the given HID device
+ *
+ * @hid_id: the system unique identifier of the HID device
+ *
+ * @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
+ */
+__bpf_kfunc struct hid_bpf_ctx *
+hid_bpf_allocate_context(unsigned int hid_id)
+{
+ struct hid_device *hdev;
+ struct hid_bpf_ctx_kern *ctx_kern = NULL;
+
+ hdev = hid_get_device(hid_id);
+ if (IS_ERR(hdev))
+ return NULL;
+
+ ctx_kern = kzalloc_obj(*ctx_kern);
+ if (!ctx_kern) {
+ hid_put_device(hdev);
+ return NULL;
+ }
+
+ ctx_kern->ctx.hid = hdev;
+
+ return &ctx_kern->ctx;
+}
+
+/**
+ * hid_bpf_release_context - Release the previously allocated context @ctx
+ *
+ * @ctx: the HID-BPF context to release
+ *
+ */
+__bpf_kfunc void
+hid_bpf_release_context(struct hid_bpf_ctx *ctx)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ struct hid_device *hid;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+ hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */
+
+ kfree(ctx_kern);
+
+ /* get_device() is called by bus_find_device() */
+ hid_put_device(hid);
+}
+
+static int
+__hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
+ enum hid_report_type rtype, bool hw_request)
+{
+ struct hid_report_enum *report_enum;
+ struct hid_report *report;
+ u32 report_len;
+
+ /* check arguments */
+ if (!hid_ops)
+ return -EINVAL;
+
+ switch (rtype) {
+ case HID_INPUT_REPORT:
+ case HID_OUTPUT_REPORT:
+ case HID_FEATURE_REPORT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (*buf__sz < 1)
+ return -EINVAL;
+
+ report_enum = ctx->hid->report_enum + rtype;
+ report = hid_ops->hid_get_report(report_enum, buf);
+ if (!report)
+ return -EINVAL;
+
+ report_len = hid_report_len(report);
+
+ /* unnumbered reports need to have a report ID reserved in the first byte */
+ if (hw_request && report_enum->numbered == 0)
+ report_len += 1;
+
+ if (*buf__sz > report_len)
+ *buf__sz = report_len;
+
+ return 0;
+}
+
+/**
+ * hid_bpf_hw_request - Communicate with a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ * @rtype: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @reqtype: the type of the request (%HID_REQ_GET_REPORT, %HID_REQ_SET_REPORT, ...)
+ *
+ * @returns %0 on success, a negative error code otherwise.
+ */
+__bpf_kfunc int
+hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
+ enum hid_report_type rtype, enum hid_class_request reqtype)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ size_t size = buf__sz;
+ u8 *dma_data;
+ int ret;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+
+ if (ctx_kern->from_bpf)
+ return -EDEADLOCK;
+
+ /* check arguments */
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true);
+ if (ret)
+ return ret;
+
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ case HID_REQ_GET_IDLE:
+ case HID_REQ_GET_PROTOCOL:
+ case HID_REQ_SET_REPORT:
+ case HID_REQ_SET_IDLE:
+ case HID_REQ_SET_PROTOCOL:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dma_data = kmemdup(buf, size, GFP_KERNEL);
+ if (!dma_data)
+ return -ENOMEM;
+
+ ret = hid_ops->hid_hw_raw_request(ctx->hid,
+ dma_data[0],
+ dma_data,
+ size,
+ rtype,
+ reqtype,
+ (u64)(long)ctx,
+ true); /* prevent infinite recursions */
+
+ if (ret > size)
+ ret = size;
+ if (ret > 0)
+ memcpy(buf, dma_data, ret);
+
+ kfree(dma_data);
+ return ret;
+}
+
+/**
+ * hid_bpf_hw_output_report - Send an output report to a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * Returns the number of bytes transferred on success, a negative error code otherwise.
+ */
+__bpf_kfunc int
+hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ size_t size = buf__sz;
+ u8 *dma_data;
+ int ret;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+ if (ctx_kern->from_bpf)
+ return -EDEADLOCK;
+
+ /* check arguments */
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, true);
+ if (ret)
+ return ret;
+
+ dma_data = kmemdup(buf, size, GFP_KERNEL);
+ if (!dma_data)
+ return -ENOMEM;
+
+ ret = hid_ops->hid_hw_output_report(ctx->hid, dma_data, size, (u64)(long)ctx, true);
+
+ kfree(dma_data);
+ return ret;
+}
+
+static int
+__hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
+ size_t size, bool lock_already_taken)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ int ret;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+ if (ctx_kern->from_bpf)
+ return -EDEADLOCK;
+
+ /* check arguments */
+ ret = __hid_bpf_hw_check_params(ctx, buf, &size, type, false);
+ if (ret)
+ return ret;
+
+ return hid_ops->hid_input_report(ctx->hid, type, buf, size, size, 0, (u64)(long)ctx, true,
+ lock_already_taken);
+}
+
+/**
+ * hid_bpf_try_input_report - Inject a HID report in the kernel from a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * Returns %0 on success, a negative error code otherwise. This function will immediately
+ * fail if the device is not available, thus can be safely used in IRQ context.
+ */
+__bpf_kfunc int
+hid_bpf_try_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
+ const size_t buf__sz)
+{
+ struct hid_bpf_ctx_kern *ctx_kern;
+ bool from_hid_event_hook;
+
+ ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
+ from_hid_event_hook = ctx_kern->data && ctx_kern->data == ctx->hid->bpf.device_data;
+
+ return __hid_bpf_input_report(ctx, type, buf, buf__sz, from_hid_event_hook);
+}
+
+/**
+ * hid_bpf_input_report - Inject a HID report in the kernel from a HID device
+ *
+ * @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
+ * @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
+ * @buf: a %PTR_TO_MEM buffer
+ * @buf__sz: the size of the data to transfer
+ *
+ * Returns %0 on success, a negative error code otherwise. This function will wait for the
+ * device to be available before injecting the event, thus needs to be called in sleepable
+ * context.
+ */
+__bpf_kfunc int
+hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
+ const size_t buf__sz)
+{
+ int ret;
+
+ ret = down_interruptible(&ctx->hid->driver_input_lock);
+ if (ret)
+ return ret;
+
+ /* check arguments */
+ ret = __hid_bpf_input_report(ctx, type, buf, buf__sz, true /* lock_already_taken */);
+
+ up(&ctx->hid->driver_input_lock);
+
+ return ret;
+}
+__bpf_kfunc_end_defs();
+
+/*
+ * The following set contains all functions we agree BPF programs
+ * can use.
+ */
+BTF_KFUNCS_START(hid_bpf_kfunc_ids)
+BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
+BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_hw_output_report, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_input_report, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_try_input_report)
+BTF_KFUNCS_END(hid_bpf_kfunc_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_kfunc_ids,
+};
+
+/* for syscall HID-BPF */
+BTF_KFUNCS_START(hid_bpf_syscall_kfunc_ids)
+BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_hw_output_report, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, hid_bpf_input_report, KF_SLEEPABLE)
+BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
+
+static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &hid_bpf_syscall_kfunc_ids,
+};
+
+int hid_bpf_connect_device(struct hid_device *hdev)
+{
+ bool need_to_allocate = false;
+ struct hid_bpf_ops *e;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) {
+ if (e->hid_device_event) {
+ need_to_allocate = true;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ /* only allocate BPF data if there are programs attached */
+ if (!need_to_allocate)
+ return 0;
+
+ return hid_bpf_allocate_event_data(hdev);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_connect_device);
+
+void hid_bpf_disconnect_device(struct hid_device *hdev)
+{
+ kfree(hdev->bpf.device_data);
+ hdev->bpf.device_data = NULL;
+ hdev->bpf.allocated_data = 0;
+}
+EXPORT_SYMBOL_GPL(hid_bpf_disconnect_device);
+
+void hid_bpf_destroy_device(struct hid_device *hdev)
+{
+ if (!hdev)
+ return;
+
+ /* mark the device as destroyed in bpf so we don't reattach it */
+ hdev->bpf.destroyed = true;
+
+ __hid_bpf_ops_destroy_device(hdev);
+
+ synchronize_srcu(&hdev->bpf.srcu);
+ cleanup_srcu_struct(&hdev->bpf.srcu);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
+
+int hid_bpf_device_init(struct hid_device *hdev)
+{
+ INIT_LIST_HEAD(&hdev->bpf.prog_list);
+ mutex_init(&hdev->bpf.prog_list_lock);
+ return init_srcu_struct(&hdev->bpf.srcu);
+}
+EXPORT_SYMBOL_GPL(hid_bpf_device_init);
+
+static int __init hid_bpf_init(void)
+{
+ int err;
+
+ /* Note: if we exit with an error any time here, we would entirely break HID, which
+ * is probably not something we want. So we log an error and return success.
+ *
+ * This is not a big deal: nobody will be able to use the functionality.
+ */
+
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &hid_bpf_kfunc_set);
+ if (err) {
+ pr_warn("error while setting HID BPF tracing kfuncs: %d", err);
+ return 0;
+ }
+
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &hid_bpf_syscall_kfunc_set);
+ if (err) {
+ pr_warn("error while setting HID BPF syscall kfuncs: %d", err);
+ return 0;
+ }
+
+ return 0;
+}
+
+late_initcall(hid_bpf_init);
+MODULE_AUTHOR("Benjamin Tissoires");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/bpf/hid_bpf_dispatch.h b/drivers/hid/bpf/hid_bpf_dispatch.h
new file mode 100644
index 000000000..44c6ea222
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_dispatch.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _BPF_HID_BPF_DISPATCH_H
+#define _BPF_HID_BPF_DISPATCH_H
+
+#include <linux/hid.h>
+
+struct hid_bpf_ctx_kern {
+ struct hid_bpf_ctx ctx;
+ u8 *data;
+ bool from_bpf;
+};
+
+struct hid_device *hid_get_device(unsigned int hid_id);
+void hid_put_device(struct hid_device *hid);
+int hid_bpf_allocate_event_data(struct hid_device *hdev);
+void __hid_bpf_ops_destroy_device(struct hid_device *hdev);
+int hid_bpf_reconnect(struct hid_device *hdev);
+
+struct bpf_prog;
+
+#endif
diff --git a/drivers/hid/bpf/hid_bpf_struct_ops.c b/drivers/hid/bpf/hid_bpf_struct_ops.c
new file mode 100644
index 000000000..c90b68956
--- /dev/null
+++ b/drivers/hid/bpf/hid_bpf_struct_ops.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * HID-BPF support for Linux
+ *
+ * Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#include <linux/bitops.h>
+#include <linux/bpf_verifier.h>
+#include <linux/bpf.h>
+#include <linux/btf.h>
+#include <linux/btf_ids.h>
+#include <linux/filter.h>
+#include <linux/hid.h>
+#include <linux/hid_bpf.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/workqueue.h>
+#include "hid_bpf_dispatch.h"
+
+static struct btf *hid_bpf_ops_btf;
+
+static int hid_bpf_ops_init(struct btf *btf)
+{
+ hid_bpf_ops_btf = btf;
+ return 0;
+}
+
+static bool hid_bpf_ops_is_valid_access(int off, int size,
+ enum bpf_access_type type,
+ const struct bpf_prog *prog,
+ struct bpf_insn_access_aux *info)
+{
+ return bpf_tracing_btf_ctx_access(off, size, type, prog, info);
+}
+
+static int hid_bpf_ops_check_member(const struct btf_type *t,
+ const struct btf_member *member,
+ const struct bpf_prog *prog)
+{
+ u32 moff = __btf_member_bit_offset(t, member) / 8;
+
+ switch (moff) {
+ case offsetof(struct hid_bpf_ops, hid_rdesc_fixup):
+ case offsetof(struct hid_bpf_ops, hid_hw_request):
+ case offsetof(struct hid_bpf_ops, hid_hw_output_report):
+ break;
+ default:
+ if (prog->sleepable)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct hid_bpf_offset_write_range {
+ const char *struct_name;
+ u32 struct_length;
+ u32 start;
+ u32 end;
+};
+
+struct hid_bpf_ctx__safe_trusted {
+ struct hid_device *hid;
+};
+
+static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log,
+ const struct bpf_reg_state *reg,
+ int off, int size)
+{
+#define WRITE_RANGE(_name, _field, _is_string) \
+ { \
+ .struct_name = #_name, \
+ .struct_length = sizeof(struct _name), \
+ .start = offsetof(struct _name, _field), \
+ .end = offsetofend(struct _name, _field) - !!(_is_string), \
+ }
+
+ const struct hid_bpf_offset_write_range write_ranges[] = {
+ WRITE_RANGE(hid_bpf_ctx, retval, false),
+ WRITE_RANGE(hid_device, name, true),
+ WRITE_RANGE(hid_device, uniq, true),
+ WRITE_RANGE(hid_device, phys, true),
+ };
+#undef WRITE_RANGE
+ const struct btf_type *state = NULL;
+ const struct btf_type *t;
+ const char *cur = NULL;
+ int i;
+
+ BTF_TYPE_EMIT(struct hid_bpf_ctx__safe_trusted);
+
+ t = btf_type_by_id(reg->btf, reg->btf_id);
+
+ for (i = 0; i < ARRAY_SIZE(write_ranges); i++) {
+ const struct hid_bpf_offset_write_range *write_range = &write_ranges[i];
+ s32 type_id;
+
+ /* we already found a writeable struct, but there is a
+ * new one, let's break the loop.
+ */
+ if (t == state && write_range->struct_name != cur)
+ break;
+
+ /* new struct to look for */
+ if (write_range->struct_name != cur) {
+ type_id = btf_find_by_name_kind(reg->btf, write_range->struct_name,
+ BTF_KIND_STRUCT);
+ if (type_id < 0)
+ return -EINVAL;
+
+ state = btf_type_by_id(reg->btf, type_id);
+ }
+
+ /* this is not the struct we are looking for */
+ if (t != state) {
+ cur = write_range->struct_name;
+ continue;
+ }
+
+ /* first time we see this struct, check for out of bounds */
+ if (cur != write_range->struct_name &&
+ off + size > write_range->struct_length) {
+ bpf_log(log, "write access for struct %s at off %d with size %d\n",
+ write_range->struct_name, off, size);
+ return -EACCES;
+ }
+
+ /* now check if we are in our boundaries */
+ if (off >= write_range->start && off + size <= write_range->end)
+ return NOT_INIT;
+
+ cur = write_range->struct_name;
+ }
+
+
+ if (t != state)
+ bpf_log(log, "write access to this struct is not supported\n");
+ else
+ bpf_log(log,
+ "write access at off %d with size %d on read-only part of %s\n",
+ off, size, cur);
+
+ return -EACCES;
+}
+
+static const struct bpf_verifier_ops hid_bpf_verifier_ops = {
+ .get_func_proto = bpf_base_func_proto,
+ .is_valid_access = hid_bpf_ops_is_valid_access,
+ .btf_struct_access = hid_bpf_ops_btf_struct_access,
+};
+
+static int hid_bpf_ops_init_member(const struct btf_type *t,
+ const struct btf_member *member,
+ void *kdata, const void *udata)
+{
+ const struct hid_bpf_ops *uhid_bpf_ops;
+ struct hid_bpf_ops *khid_bpf_ops;
+ u32 moff;
+
+ uhid_bpf_ops = (const struct hid_bpf_ops *)udata;
+ khid_bpf_ops = (struct hid_bpf_ops *)kdata;
+
+ moff = __btf_member_bit_offset(t, member) / 8;
+
+ switch (moff) {
+ case offsetof(struct hid_bpf_ops, hid_id):
+ /* For hid_id and flags fields, this function has to copy it
+ * and return 1 to indicate that the data has been handled by
+ * the struct_ops type, or the verifier will reject the map if
+ * the value of those fields is not zero.
+ */
+ khid_bpf_ops->hid_id = uhid_bpf_ops->hid_id;
+ return 1;
+ case offsetof(struct hid_bpf_ops, flags):
+ if (uhid_bpf_ops->flags & ~BPF_F_BEFORE)
+ return -EINVAL;
+ khid_bpf_ops->flags = uhid_bpf_ops->flags;
+ return 1;
+ }
+ return 0;
+}
+
+static int hid_bpf_reg(void *kdata, struct bpf_link *link)
+{
+ struct hid_bpf_ops *ops = kdata;
+ struct hid_device *hdev;
+ int count, err = 0;
+
+ /* prevent multiple attach of the same struct_ops */
+ if (ops->hdev)
+ return -EINVAL;
+
+ hdev = hid_get_device(ops->hid_id);
+ if (IS_ERR(hdev))
+ return PTR_ERR(hdev);
+
+ ops->hdev = hdev;
+
+ mutex_lock(&hdev->bpf.prog_list_lock);
+
+ count = list_count_nodes(&hdev->bpf.prog_list);
+ if (count >= HID_BPF_MAX_PROGS_PER_DEV) {
+ err = -E2BIG;
+ goto out_unlock;
+ }
+
+ if (ops->hid_rdesc_fixup) {
+ if (hdev->bpf.rdesc_ops) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+
+ hdev->bpf.rdesc_ops = ops;
+ }
+
+ if (ops->hid_device_event) {
+ err = hid_bpf_allocate_event_data(hdev);
+ if (err)
+ goto out_unlock;
+ }
+
+ if (ops->flags & BPF_F_BEFORE)
+ list_add_rcu(&ops->list, &hdev->bpf.prog_list);
+ else
+ list_add_tail_rcu(&ops->list, &hdev->bpf.prog_list);
+ synchronize_srcu(&hdev->bpf.srcu);
+
+out_unlock:
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+
+ if (err) {
+ if (hdev->bpf.rdesc_ops == ops)
+ hdev->bpf.rdesc_ops = NULL;
+ hid_put_device(hdev);
+ } else if (ops->hid_rdesc_fixup) {
+ hid_bpf_reconnect(hdev);
+ }
+
+ return err;
+}
+
+static void hid_bpf_unreg(void *kdata, struct bpf_link *link)
+{
+ struct hid_bpf_ops *ops = kdata;
+ struct hid_device *hdev;
+ bool reconnect = false;
+
+ hdev = ops->hdev;
+
+ /* check if __hid_bpf_ops_destroy_device() has been called */
+ if (!hdev)
+ return;
+
+ mutex_lock(&hdev->bpf.prog_list_lock);
+
+ if (!ops->hdev) {
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+ return;
+ }
+
+ list_del_rcu(&ops->list);
+ synchronize_srcu(&hdev->bpf.srcu);
+ ops->hdev = NULL;
+
+ reconnect = hdev->bpf.rdesc_ops == ops;
+ if (reconnect)
+ hdev->bpf.rdesc_ops = NULL;
+
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+
+ if (reconnect)
+ hid_bpf_reconnect(hdev);
+
+ hid_put_device(hdev);
+}
+
+static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type, u64 source)
+{
+ return 0;
+}
+
+static int __hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx)
+{
+ return 0;
+}
+
+static int __hid_bpf_hw_request(struct hid_bpf_ctx *ctx, unsigned char reportnum,
+ enum hid_report_type rtype, enum hid_class_request reqtype,
+ u64 source)
+{
+ return 0;
+}
+
+static int __hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, u64 source)
+{
+ return 0;
+}
+
+static struct hid_bpf_ops __bpf_hid_bpf_ops = {
+ .hid_device_event = __hid_bpf_device_event,
+ .hid_rdesc_fixup = __hid_bpf_rdesc_fixup,
+ .hid_hw_request = __hid_bpf_hw_request,
+ .hid_hw_output_report = __hid_bpf_hw_output_report,
+};
+
+static struct bpf_struct_ops bpf_hid_bpf_ops = {
+ .verifier_ops = &hid_bpf_verifier_ops,
+ .init = hid_bpf_ops_init,
+ .check_member = hid_bpf_ops_check_member,
+ .init_member = hid_bpf_ops_init_member,
+ .reg = hid_bpf_reg,
+ .unreg = hid_bpf_unreg,
+ .name = "hid_bpf_ops",
+ .cfi_stubs = &__bpf_hid_bpf_ops,
+ .owner = THIS_MODULE,
+};
+
+void __hid_bpf_ops_destroy_device(struct hid_device *hdev)
+{
+ struct hid_bpf_ops *e;
+ int count = 0;
+
+ mutex_lock(&hdev->bpf.prog_list_lock);
+ list_for_each_entry(e, &hdev->bpf.prog_list, list) {
+ e->hdev = NULL;
+ count++;
+ }
+ mutex_unlock(&hdev->bpf.prog_list_lock);
+
+ while (count--)
+ hid_put_device(hdev);
+}
+
+static int __init hid_bpf_struct_ops_init(void)
+{
+ return register_bpf_struct_ops(&bpf_hid_bpf_ops, hid_bpf_ops);
+}
+late_initcall(hid_bpf_struct_ops_init);
diff --git a/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c
new file mode 100644
index 000000000..caec91391
--- /dev/null
+++ b/drivers/hid/bpf/progs/FR-TEC__Raptor-Mach-2.bpf.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_BETOP_2185PC 0x11C0
+#define PID_RAPTOR_MACH_2 0x5606
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_BETOP_2185PC, PID_RAPTOR_MACH_2),
+);
+
+/*
+ * For reference, this is the fixed report descriptor
+ *
+ * static const __u8 fixed_rdesc[] = {
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * 0x09, 0x04, // Usage (Joystick) 2
+ * 0xa1, 0x01, // Collection (Application) 4
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 6
+ * 0x85, 0x01, // Report ID (1) 8
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 10
+ * 0x09, 0x30, // Usage (X) 12
+ * 0x75, 0x10, // Report Size (16) 14
+ * 0x95, 0x01, // Report Count (1) 16
+ * 0x15, 0x00, // Logical Minimum (0) 18
+ * 0x26, 0xff, 0x07, // Logical Maximum (2047) 20
+ * 0x46, 0xff, 0x07, // Physical Maximum (2047) 23
+ * 0x81, 0x02, // Input (Data,Var,Abs) 26
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 28
+ * 0x09, 0x31, // Usage (Y) 30
+ * 0x75, 0x10, // Report Size (16) 32
+ * 0x95, 0x01, // Report Count (1) 34
+ * 0x15, 0x00, // Logical Minimum (0) 36
+ * 0x26, 0xff, 0x07, // Logical Maximum (2047) 38
+ * 0x46, 0xff, 0x07, // Physical Maximum (2047) 41
+ * 0x81, 0x02, // Input (Data,Var,Abs) 44
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 46
+ * 0x09, 0x33, // Usage (Rx) 48
+ * 0x75, 0x10, // Report Size (16) 50
+ * 0x95, 0x01, // Report Count (1) 52
+ * 0x15, 0x00, // Logical Minimum (0) 54
+ * 0x26, 0xff, 0x03, // Logical Maximum (1023) 56
+ * 0x46, 0xff, 0x03, // Physical Maximum (1023) 59
+ * 0x81, 0x02, // Input (Data,Var,Abs) 62
+ * 0x05, 0x00, // Usage Page (Undefined) 64
+ * 0x09, 0x00, // Usage (Undefined) 66
+ * 0x75, 0x10, // Report Size (16) 68
+ * 0x95, 0x01, // Report Count (1) 70
+ * 0x15, 0x00, // Logical Minimum (0) 72
+ * 0x26, 0xff, 0x03, // Logical Maximum (1023) 74
+ * 0x46, 0xff, 0x03, // Physical Maximum (1023) 77
+ * 0x81, 0x02, // Input (Data,Var,Abs) 80
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 82
+ * 0x09, 0x32, // Usage (Z) 84
+ * 0x75, 0x10, // Report Size (16) 86
+ * 0x95, 0x01, // Report Count (1) 88
+ * 0x15, 0x00, // Logical Minimum (0) 90
+ * 0x26, 0xff, 0x03, // Logical Maximum (1023) 92
+ * 0x46, 0xff, 0x03, // Physical Maximum (1023) 95
+ * 0x81, 0x02, // Input (Data,Var,Abs) 98
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 100
+ * 0x09, 0x35, // Usage (Rz) 102
+ * 0x75, 0x10, // Report Size (16) 104
+ * 0x95, 0x01, // Report Count (1) 106
+ * 0x15, 0x00, // Logical Minimum (0) 108
+ * 0x26, 0xff, 0x03, // Logical Maximum (1023) 110
+ * 0x46, 0xff, 0x03, // Physical Maximum (1023) 113
+ * 0x81, 0x02, // Input (Data,Var,Abs) 116
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 118
+ * 0x09, 0x34, // Usage (Ry) 120
+ * 0x75, 0x10, // Report Size (16) 122
+ * 0x95, 0x01, // Report Count (1) 124
+ * 0x15, 0x00, // Logical Minimum (0) 126
+ * 0x26, 0xff, 0x07, // Logical Maximum (2047) 128
+ * 0x46, 0xff, 0x07, // Physical Maximum (2047) 131
+ * 0x81, 0x02, // Input (Data,Var,Abs) 134
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 136
+ * 0x09, 0x36, // Usage (Slider) 138
+ * 0x75, 0x10, // Report Size (16) 140
+ * 0x95, 0x01, // Report Count (1) 142
+ * 0x15, 0x00, // Logical Minimum (0) 144
+ * 0x26, 0xff, 0x03, // Logical Maximum (1023) 146
+ * 0x46, 0xff, 0x03, // Physical Maximum (1023) 149
+ * 0x81, 0x02, // Input (Data,Var,Abs) 152
+ * 0x05, 0x09, // Usage Page (Button) 154
+ * 0x19, 0x01, // Usage Minimum (1) 156
+ * 0x2a, 0x1d, 0x00, // Usage Maximum (29) 158
+ * 0x15, 0x00, // Logical Minimum (0) 161
+ * 0x25, 0x01, // Logical Maximum (1) 163
+ * 0x75, 0x01, // Report Size (1) 165
+ * 0x96, 0x80, 0x00, // Report Count (128) 167
+ * 0x81, 0x02, // Input (Data,Var,Abs) 170
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 172
+ * 0x09, 0x39, // Usage (Hat switch) 174
+ * 0x26, 0x07, 0x00, // Logical Maximum (7) 176 // changed (was 239)
+ * 0x46, 0x68, 0x01, // Physical Maximum (360) 179
+ * 0x65, 0x14, // Unit (EnglishRotation: deg) 182
+ * 0x75, 0x10, // Report Size (16) 184
+ * 0x95, 0x01, // Report Count (1) 186
+ * 0x81, 0x42, // Input (Data,Var,Abs,Null) 188
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 190
+ * 0x09, 0x00, // Usage (Undefined) 192
+ * 0x75, 0x08, // Report Size (8) 194
+ * 0x95, 0x1d, // Report Count (29) 196
+ * 0x81, 0x01, // Input (Cnst,Arr,Abs) 198
+ * 0x15, 0x00, // Logical Minimum (0) 200
+ * 0x26, 0xef, 0x00, // Logical Maximum (239) 202
+ * 0x85, 0x58, // Report ID (88) 205
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 207
+ * 0x46, 0xff, 0x00, // Physical Maximum (255) 210
+ * 0x75, 0x08, // Report Size (8) 213
+ * 0x95, 0x3f, // Report Count (63) 215
+ * 0x09, 0x00, // Usage (Undefined) 217
+ * 0x91, 0x02, // Output (Data,Var,Abs) 219
+ * 0x85, 0x59, // Report ID (89) 221
+ * 0x75, 0x08, // Report Size (8) 223
+ * 0x95, 0x80, // Report Count (128) 225
+ * 0x09, 0x00, // Usage (Undefined) 227
+ * 0xb1, 0x02, // Feature (Data,Var,Abs) 229
+ * 0xc0, // End Collection 231
+ * };
+ */
+
+/*
+ * We need to amend the report descriptor for the following:
+ * - the joystick sends its hat_switch data between 0 and 239 but
+ * the kernel expects the logical max to stick into a signed 8 bits
+ * integer. We thus divide it by 30 to match what other joysticks are
+ * doing
+ */
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_raptor_mach_2, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ data[177] = 0x07;
+
+ return 0;
+}
+
+/*
+ * The hat_switch value at offsets 33 and 34 (16 bits) needs
+ * to be reduced to a single 8 bit signed integer. So we
+ * divide it by 30.
+ * Byte 34 is always null, so it is ignored.
+ */
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(raptor_mach_2_fix_hat_switch, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 64 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[0] != 0x01) /* not the joystick report ID */
+ return 0;
+
+ data[33] /= 30;
+
+ return 0;
+}
+
+HID_BPF_OPS(raptor_mach_2) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_raptor_mach_2,
+ .hid_device_event = (void *)raptor_mach_2_fix_hat_switch,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != 232;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ /* ensure the kernel isn't fixed already */
+ if (ctx->rdesc[177] != 0xef) /* Logical Max of 239 */
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Generic__touchpad.bpf.c b/drivers/hid/bpf/progs/Generic__touchpad.bpf.c
new file mode 100644
index 000000000..b9f2cac91
--- /dev/null
+++ b/drivers/hid/bpf/progs/Generic__touchpad.bpf.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include "hid_report_helpers.h"
+#include "hid_usages.h"
+#include <bpf/bpf_tracing.h>
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8, HID_VID_ANY, HID_PID_ANY),
+);
+
+EXPORT_UDEV_PROP(HID_DIGITIZER_PAD_TYPE, 32);
+
+__u8 hw_req_buf[1024];
+
+/* to be filled by udev-hid-bpf */
+struct hid_rdesc_descriptor HID_REPORT_DESCRIPTOR;
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ struct hid_rdesc_report *pad_type_feature = NULL;
+ struct hid_rdesc_field *pad_type = NULL;
+ struct hid_rdesc_report *feature;
+ struct hid_bpf_ctx *hid_ctx;
+ char *pad_type_str = "";
+ int ret;
+
+ hid_bpf_for_each_feature_report(&HID_REPORT_DESCRIPTOR, feature) {
+ struct hid_rdesc_field *field;
+
+ hid_bpf_for_each_field(feature, field) {
+ if (field->usage_page == HidUsagePage_Digitizers &&
+ field->usage_id == HidUsage_Dig_PadType) {
+ pad_type = field;
+ pad_type_feature = feature;
+ break;
+ }
+ }
+ if (pad_type)
+ break;
+ }
+
+ if (!pad_type || !pad_type_feature) {
+ ctx->retval = -EINVAL;
+ return 0;
+ }
+
+ hid_ctx = hid_bpf_allocate_context(ctx->hid);
+
+ if (!hid_ctx)
+ return -1; /* EPERM check */
+
+ hw_req_buf[0] = pad_type_feature->report_id;
+
+ ret = hid_bpf_hw_request(hid_ctx, hw_req_buf, sizeof(hw_req_buf),
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ hid_bpf_release_context(hid_ctx);
+
+ if (ret < 0) {
+ ctx->retval = ret;
+ return 0;
+ }
+
+ ctx->retval = 0;
+
+ switch (EXTRACT_BITS(hw_req_buf, pad_type)) {
+ case 0:
+ pad_type_str = "Clickpad";
+ break;
+ case 1:
+ pad_type_str = "Pressurepad";
+ break;
+ case 2:
+ pad_type_str = "Discrete";
+ break;
+ default:
+ pad_type_str = "Unknown";
+ }
+
+ UDEV_PROP_SPRINTF(HID_DIGITIZER_PAD_TYPE, "%s", pad_type_str);
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c
new file mode 100644
index 000000000..c2413fa80
--- /dev/null
+++ b/drivers/hid/bpf/progs/HP__Elite-Presenter.bpf.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2023 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_HP 0x03F0
+#define PID_ELITE_PRESENTER 0x464A
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HP, PID_ELITE_PRESENTER)
+);
+
+/*
+ * Already fixed as of commit 0db117359e47 ("HID: add quirk for 03f0:464a
+ * HP Elite Presenter Mouse") in the kernel, but this is a slightly better
+ * fix.
+ *
+ * The HP Elite Presenter Mouse HID Record Descriptor shows
+ * two mice (Report ID 0x1 and 0x2), one keypad (Report ID 0x5),
+ * two Consumer Controls (Report IDs 0x6 and 0x3).
+ * Prior to these fixes it registers one mouse, one keypad
+ * and one Consumer Control, and it was usable only as a
+ * digital laser pointer (one of the two mouses).
+ * We replace the second mouse collection with a pointer collection,
+ * allowing to use the device both as a mouse and a digital laser
+ * pointer.
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* replace application mouse by application pointer on the second collection */
+ if (data[79] == 0x02)
+ data[79] = 0x01;
+
+ return 0;
+}
+
+HID_BPF_OPS(hp_elite_presenter) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != 264;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c b/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c
new file mode 100644
index 000000000..9670e5ef8
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Dial-2.bpf.c
@@ -0,0 +1,636 @@
+// 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 VID_HUION 0x256C
+#define PID_DIAL_2 0x0060
+
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_DIAL_2),
+);
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+/* The prefix of the firmware ID we expect for this device. The full firmware
+ * string has a date suffix, e.g. HUION_T21j_221221
+ */
+char EXPECTED_FIRMWARE_ID[] = "HUION_T216_";
+
+/* How this BPF program works: the tablet has two modes, firmware mode and
+ * tablet mode. In firmware mode (out of the box) the tablet sends button events
+ * and the dial as keyboard combinations. In tablet mode it uses a vendor specific
+ * hid report to report everything instead.
+ * Depending on the mode some hid reports are never sent and the corresponding
+ * devices are mute.
+ *
+ * To switch the tablet use e.g. https://github.com/whot/huion-switcher
+ * or one of the tools from the digimend project
+ *
+ * This BPF works for both modes. The huion-switcher tool sets the
+ * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
+ * pad and pen reports (by making them vendor collections that are ignored).
+ * If that property is not set we fix all hidraw nodes so the tablet works in
+ * either mode though the drawback is that the device will show up twice if
+ * you bind it to all event nodes
+ *
+ * Default report descriptor for the first exposed hidraw node:
+ *
+ * # HUION Huion Tablet_Q630M
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x58, // Report Size (88) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 13
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
+ *
+ * This rdesc does nothing until the tablet is switched to raw mode, see
+ * https://github.com/whot/huion-switcher
+ *
+ *
+ * Second hidraw node is the Pen. This one sends events until the tablet is
+ * switched to raw mode, then it's mute.
+ *
+ * # Report descriptor length: 93 bytes
+ * # HUION Huion Tablet_Q630M
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x0a, // Report ID (10) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x01, // Collection (Application) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x45, // Usage (Eraser) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18
+ * # 0x15, 0x00, // Logical Minimum (0) 20
+ * # 0x25, 0x01, // Logical Maximum (1) 22
+ * # 0x75, 0x01, // Report Size (1) 24
+ * # 0x95, 0x06, // Report Count (6) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x09, 0x32, // Usage (In Range) 30
+ * # 0x75, 0x01, // Report Size (1) 32
+ * # 0x95, 0x01, // Report Count (1) 34
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 40
+ * # 0x09, 0x30, // Usage (X) 42
+ * # 0x09, 0x31, // Usage (Y) 44
+ * # 0x55, 0x0d, // Unit Exponent (-3) 46
+ * # 0x65, 0x33, // Unit (EnglishLinear: in³) 48
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 50
+ * # 0x35, 0x00, // Physical Minimum (0) 53
+ * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 55
+ * # 0x75, 0x10, // Report Size (16) 58
+ * # 0x95, 0x02, // Report Count (2) 60
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 62
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 64
+ * # 0x09, 0x30, // Usage (Tip Pressure) 66
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 68
+ * # 0x75, 0x10, // Report Size (16) 71
+ * # 0x95, 0x01, // Report Count (1) 73
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 75
+ * # 0x09, 0x3d, // Usage (X Tilt) 77
+ * # 0x09, 0x3e, // Usage (Y Tilt) 79
+ * # 0x15, 0x81, // Logical Minimum (-127) 81
+ * # 0x25, 0x7f, // Logical Maximum (127) 83
+ * # 0x75, 0x08, // Report Size (8) 85
+ * # 0x95, 0x02, // Report Count (2) 87
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 89
+ * # 0xc0, // End Collection 91
+ * # 0xc0, // End Collection 92
+ * R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d 09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0
+ *
+ * Third hidraw node is the pad which sends a combination of keyboard shortcuts until
+ * the tablet is switched to raw mode, then it's mute:
+ *
+ * # Report descriptor length: 148 bytes
+ * # HUION Huion Tablet_Q630M
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x11, // Report ID (17) 6
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 8
+ * # 0x09, 0x21, // Usage (Puck) 10
+ * # 0xa1, 0x02, // Collection (Logical) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x01, // Report Count (1) 20
+ * # 0xa1, 0x00, // Collection (Physical) 22
+ * # 0x05, 0x09, // Usage Page (Button) 24
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 30
+ * # 0x09, 0x33, // Usage (Touch) 32
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 34
+ * # 0x95, 0x06, // Report Count (6) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0xa1, 0x02, // Collection (Logical) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x37, // Usage (Dial) 44
+ * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49
+ * # 0x75, 0x10, // Report Size (16) 52
+ * # 0x95, 0x01, // Report Count (1) 54
+ * # 0x81, 0x06, // Input (Data,Var,Rel) 56
+ * # 0x35, 0x00, // Physical Minimum (0) 58
+ * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60
+ * # 0x15, 0x00, // Logical Minimum (0) 63
+ * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65
+ * # 0x09, 0x48, // Usage (Resolution Multiplier) 68
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 70
+ * # 0x45, 0x00, // Physical Maximum (0) 72
+ * # 0xc0, // End Collection 74
+ * # 0x75, 0x08, // Report Size (8) 75
+ * # 0x95, 0x01, // Report Count (1) 77
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 79
+ * # 0x75, 0x08, // Report Size (8) 81
+ * # 0x95, 0x01, // Report Count (1) 83
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x01, // Report Count (1) 89
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 91
+ * # 0x75, 0x08, // Report Size (8) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97
+ * # 0x75, 0x08, // Report Size (8) 99
+ * # 0x95, 0x01, // Report Count (1) 101
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 103
+ * # 0xc0, // End Collection 105
+ * # 0xc0, // End Collection 106
+ * # 0xc0, // End Collection 107
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 108
+ * # 0x09, 0x06, // Usage (Keyboard) 110
+ * # 0xa1, 0x01, // Collection (Application) 112
+ * # 0x85, 0x03, // Report ID (3) 114
+ * # 0x05, 0x07, // Usage Page (Keyboard) 116
+ * # 0x19, 0xe0, // Usage Minimum (224) 118
+ * # 0x29, 0xe7, // Usage Maximum (231) 120
+ * # 0x15, 0x00, // Logical Minimum (0) 122
+ * # 0x25, 0x01, // Logical Maximum (1) 124
+ * # 0x75, 0x01, // Report Size (1) 126
+ * # 0x95, 0x08, // Report Count (8) 128
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 130
+ * # 0x05, 0x07, // Usage Page (Keyboard) 132
+ * # 0x19, 0x00, // Usage Minimum (0) 134
+ * # 0x29, 0xff, // Usage Maximum (255) 136
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 138
+ * # 0x75, 0x08, // Report Size (8) 141
+ * # 0x95, 0x06, // Report Count (6) 143
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 145
+ * # 0xc0, // End Collection 147
+ * R: 148 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0
+ */
+
+#define PAD_REPORT_DESCRIPTOR_LENGTH 148
+#define PEN_REPORT_DESCRIPTOR_LENGTH 93
+#define VENDOR_REPORT_DESCRIPTOR_LENGTH 18
+#define PAD_REPORT_ID 3
+#define DIAL_REPORT_ID 17
+#define PEN_REPORT_ID 10
+#define VENDOR_REPORT_ID 8
+#define PAD_REPORT_LENGTH 9
+#define PEN_REPORT_LENGTH 10
+#define VENDOR_REPORT_LENGTH 12
+
+
+__u8 last_button_state;
+
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PAD_REPORT_ID)
+ LogicalMaximum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 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 2/3 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 4 in report is the dial
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ // Byte 5 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x01)
+ UsageMaximum_i8(0x08)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(7)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(1) // padding
+ Input(Const)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+ )
+};
+
+static const __u8 fixed_rdesc_pen[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PEN_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // -- Byte 1 in report
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(266)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_X
+ Input(Var|Abs) // Bytes 2+3
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(166)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_Y
+ Input(Var|Abs) // Bytes 4+5
+ )
+ UsagePage_Digitizers
+ Usage_Dig_TipPressure
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8191)
+ Input(Var|Abs) // Byte 6+7
+ ReportSize(8)
+ ReportCount(2)
+ LogicalMinimum_i8(-60)
+ LogicalMaximum_i8(60)
+ Usage_Dig_XTilt
+ Usage_Dig_YTilt
+ Input(Var|Abs) // Byte 8+9
+ )
+ )
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // Byte 0
+ // We leave the pen on the vendor report ID
+ ReportId(VENDOR_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ // Note: reported logical range differs
+ // from the pen report ID for x and y
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(53340)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(266)
+ // Bytes 2/3 in report
+ Usage_GD_X
+ Input(Var|Abs)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(33340)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(166)
+ // Bytes 4/5 in report
+ Usage_GD_Y
+ Input(Var|Abs)
+ )
+ // Bytes 6/7 in report
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8191)
+ Usage_Dig_TipPressure
+ Input(Var|Abs)
+ // Bytes 8/9 in report
+ ReportCount(1) // Padding
+ Input(Const)
+ LogicalMinimum_i8(-60)
+ LogicalMaximum_i8(60)
+ // Byte 10 in report
+ Usage_Dig_XTilt
+ // Byte 11 in report
+ Usage_Dig_YTilt
+ ReportSize(8)
+ ReportCount(2)
+ Input(Var|Abs)
+ )
+ )
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ ReportId(PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Byte 4 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x1)
+ UsageMaximum_i8(0x8)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(8)
+ ReportSize(1)
+ Input(Var|Abs)
+ // Byte 5 is the top dial
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ // Byte 6 is the bottom dial
+ UsagePage_Consumer
+ Usage_Con_ACPan
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+static const __u8 disabled_rdesc_pen[] = {
+ FixedSizeVendorReport(PEN_REPORT_LENGTH)
+};
+
+static const __u8 disabled_rdesc_pad[] = {
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(dial_2_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;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* If we have a firmware ID and it matches our expected prefix, we
+ * disable the default pad/pen nodes. They won't send events
+ * but cause duplicate devices.
+ */
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+ if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
+ return sizeof(disabled_rdesc_pad);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ }
+ if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
+ return sizeof(disabled_rdesc_pen);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
+ return sizeof(fixed_rdesc_pen);
+ }
+ /* Always fix the vendor mode so the tablet will work even if nothing sets
+ * the udev property (e.g. huion-switcher run manually)
+ */
+ if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+
+ }
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(dial_2_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 16 /* size */);
+ static __u8 button;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Only sent if tablet is in default mode */
+ if (data[0] == PAD_REPORT_ID) {
+ /* Nicely enough, this device only supports one button down at a time so
+ * the reports are easy to match. Buttons numbered from the top
+ * Button released: 03 00 00 00 00 00 00 00
+ * Button 1: 03 00 05 00 00 00 00 00 -> b
+ * Button 2: 03 00 08 00 00 00 00 00 -> e
+ * Button 3: 03 00 0c 00 00 00 00 00 -> i
+ * Button 4: 03 00 e0 16 00 00 00 00 -> Ctrl S
+ * Button 5: 03 00 2c 00 00 00 00 00 -> space
+ * Button 6: 03 00 e0 e2 1d 00 00 00 -> Ctrl Alt Z
+ */
+ button &= 0xc0;
+
+ switch ((data[2] << 16) | (data[3] << 8) | data[4]) {
+ case 0x000000:
+ break;
+ case 0x050000:
+ button |= BIT(0);
+ break;
+ case 0x080000:
+ button |= BIT(1);
+ break;
+ case 0x0c0000:
+ button |= BIT(2);
+ break;
+ case 0xe01600:
+ button |= BIT(3);
+ break;
+ case 0x2c0000:
+ button |= BIT(4);
+ break;
+ case 0xe0e21d:
+ button |= BIT(5);
+ break;
+ }
+
+ __u8 report[8] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, 0x00, button};
+
+ __builtin_memcpy(data, report, sizeof(report));
+ return sizeof(report);
+ }
+
+ /* Only sent if tablet is in default mode */
+ if (data[0] == DIAL_REPORT_ID) {
+ /*
+ * In default mode, both dials are merged together:
+ *
+ * Dial down: 11 00 ff ff 00 00 00 00 00 -> Dial -1
+ * Dial up: 11 00 01 00 00 00 00 00 00 -> Dial 1
+ */
+ __u16 dial = data[3] << 8 | data[2];
+
+ button &= 0x3f;
+ button |= !!data[1] << 6;
+
+ __u8 report[] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, dial, button};
+
+ __builtin_memcpy(data, report, sizeof(report));
+ return sizeof(report);
+ }
+
+ /* Nothing to do for the PEN_REPORT_ID, it's already mapped */
+
+ /* Only sent if tablet is in raw mode */
+ if (data[0] == VENDOR_REPORT_ID) {
+ /* Pad reports */
+ if (data[1] & 0x20) {
+ /* See fixed_rdesc_pad */
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus;
+ __u8 x;
+ __u8 y;
+ __u8 buttons;
+ __u8 dial_1;
+ __u8 dial_2;
+ } __attribute__((packed)) *pad_report;
+ __u8 dial_1 = 0, dial_2 = 0;
+
+ /* Dial report */
+ if (data[1] == 0xf1) {
+ __u8 d = 0;
+
+ if (data[5] == 2)
+ d = 0xff;
+ else
+ d = data[5];
+
+ if (data[3] == 1)
+ dial_1 = d;
+ else
+ dial_2 = d;
+ } else {
+ /* data[4] are the buttons, mapped correctly */
+ last_button_state = data[4];
+ dial_1 = 0; // dial
+ dial_2 = 0;
+ }
+
+ pad_report = (struct pad_report *)data;
+
+ pad_report->report_id = PAD_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->dial_1 = dial_1;
+ pad_report->dial_2 = dial_2;
+
+ return sizeof(struct pad_report);
+ }
+
+ /* Pen reports need nothing done */
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(inspiroy_dial2) = {
+ .hid_device_event = (void *)dial_2_fix_events,
+ .hid_rdesc_fixup = (void *)dial_2_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ case PEN_REPORT_DESCRIPTOR_LENGTH:
+ case VENDOR_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Inspiroy-2-M.bpf.c b/drivers/hid/bpf/progs/Huion__Inspiroy-2-M.bpf.c
new file mode 100644
index 000000000..183d408d8
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Inspiroy-2-M.bpf.c
@@ -0,0 +1,563 @@
+// 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 VID_HUION 0x256C
+#define PID_INSPIROY_2_M 0x0067
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_2_M),
+);
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+/* The prefix of the firmware ID we expect for this device. The full firmware
+ * string has a date suffix, e.g. HUION_T21j_221221
+ */
+char EXPECTED_FIRMWARE_ID[] = "HUION_T21k_";
+
+/* How this BPF program works: the tablet has two modes, firmware mode and
+ * tablet mode. In firmware mode (out of the box) the tablet sends button events
+ * and the dial as keyboard combinations. In tablet mode it uses a vendor specific
+ * hid report to report everything instead.
+ * Depending on the mode some hid reports are never sent and the corresponding
+ * devices are mute.
+ *
+ * To switch the tablet use e.g. https://github.com/whot/huion-switcher
+ * or one of the tools from the digimend project
+ *
+ * This BPF works for both modes. The huion-switcher tool sets the
+ * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
+ * pad and pen reports (by making them vendor collections that are ignored).
+ * If that property is not set we fix all hidraw nodes so the tablet works in
+ * either mode though the drawback is that the device will show up twice if
+ * you bind it to all event nodes
+ *
+ * Default report descriptor for the first exposed hidraw node:
+ *
+ * # HUION Huion Tablet_H641P
+ * # Report descriptor length: 18 bytes
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x58, // Report Size (88) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
+ *
+ * This rdesc does nothing until the tablet is switched to raw mode, see
+ * https://github.com/whot/huion-switcher
+ *
+ *
+ * Second hidraw node is the Pen. This one sends events until the tablet is
+ * switched to raw mode, then it's mute.
+ *
+ * # Report descriptor length: 93 bytes
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x0a, // Report ID (10) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x01, // Collection (Application) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x45, // Usage (Eraser) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18 <-- has no Invert eraser
+ * # 0x15, 0x00, // Logical Minimum (0) 20
+ * # 0x25, 0x01, // Logical Maximum (1) 22
+ * # 0x75, 0x01, // Report Size (1) 24
+ * # 0x95, 0x06, // Report Count (6) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x09, 0x32, // Usage (In Range) 30
+ * # 0x75, 0x01, // Report Size (1) 32
+ * # 0x95, 0x01, // Report Count (1) 34
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 40
+ * # 0x09, 0x30, // Usage (X) 42
+ * # 0x09, 0x31, // Usage (Y) 44
+ * # 0x55, 0x0d, // Unit Exponent (-3) 46 <-- change to -2
+ * # 0x65, 0x33, // Unit (EnglishLinear: in³) 48 <-- change in³ to in
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 50
+ * # 0x35, 0x00, // Physical Minimum (0) 53
+ * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 55 <-- invalid size
+ * # 0x75, 0x10, // Report Size (16) 58
+ * # 0x95, 0x02, // Report Count (2) 60
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 62
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 64
+ * # 0x09, 0x30, // Usage (Tip Pressure) 66
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 68
+ * # 0x75, 0x10, // Report Size (16) 71
+ * # 0x95, 0x01, // Report Count (1) 73
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 75
+ * # 0x09, 0x3d, // Usage (X Tilt) 77 <-- No tilt reported
+ * # 0x09, 0x3e, // Usage (Y Tilt) 79
+ * # 0x15, 0x81, // Logical Minimum (-127) 81
+ * # 0x25, 0x7f, // Logical Maximum (127) 83
+ * # 0x75, 0x08, // Report Size (8) 85
+ * # 0x95, 0x02, // Report Count (2) 87
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 89
+ * # 0xc0, // End Collection 91
+ * # 0xc0, // End Collection 92
+ * R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 7501 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0
+ *
+ * Third hidraw node is the pad which sends a combination of keyboard shortcuts until
+ * the tablet is switched to raw mode, then it's mute:
+ *
+ * # Report descriptor length: 65 bytes
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x06, // Usage (Keyboard) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x03, // Report ID (3) 6
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8
+ * # 0x19, 0xe0, // UsageMinimum (224) 10
+ * # 0x29, 0xe7, // UsageMaximum (231) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x08, // Report Count (8) 20
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 22
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24
+ * # 0x19, 0x00, // UsageMinimum (0) 26
+ * # 0x29, 0xff, // UsageMaximum (255) 28
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 30
+ * # 0x75, 0x08, // Report Size (8) 33
+ * # 0x95, 0x06, // Report Count (6) 35
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 37
+ * # 0xc0, // End Collection 39
+ * # 0x05, 0x0c, // Usage Page (Consumer) 40
+ * # 0x09, 0x01, // Usage (Consumer Control) 42
+ * # 0xa1, 0x01, // Collection (Application) 44
+ * # 0x85, 0x04, // Report ID (4) 46
+ * # 0x19, 0x00, // UsageMinimum (0) 48
+ * # 0x2a, 0x3c, 0x02, // UsageMaximum (572) 50
+ * # 0x15, 0x00, // Logical Minimum (0) 53
+ * # 0x26, 0x3c, 0x02, // Logical Maximum (572) 55
+ * # 0x95, 0x01, // Report Count (1) 58
+ * # 0x75, 0x10, // Report Size (16) 60
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 62
+ * # 0xc0, // End Collection 64
+ * R: 65 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 0507 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 00 2a 3c02 15 00 26 3c 02 95 01 75 10 81 00 c0
+ * N: HUION Huion Tablet_H641P
+ */
+
+#define PAD_REPORT_DESCRIPTOR_LENGTH 133
+#define PEN_REPORT_DESCRIPTOR_LENGTH 93
+#define VENDOR_REPORT_DESCRIPTOR_LENGTH 36
+#define PAD_REPORT_ID 3
+#define PEN_REPORT_ID 10
+#define VENDOR_REPORT_ID 8
+#define PAD_REPORT_LENGTH 8
+#define PEN_REPORT_LENGTH 10
+#define VENDOR_REPORT_LENGTH 12
+
+
+__u16 last_button_state;
+
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 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 2/3 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 4 in report is the wheel
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ // Byte 5 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x1)
+ UsageMaximum_i8(0x8)
+ LogicalMinimum_i8(0x1)
+ LogicalMaximum_i8(0x8)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Arr|Abs)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+ )
+};
+
+static const __u8 fixed_rdesc_pen[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PEN_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // -- Byte 1 in report
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(160)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_X
+ Input(Var|Abs) // Bytes 2+3
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(100)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_Y
+ Input(Var|Abs) // Bytes 4+5
+ )
+ UsagePage_Digitizers
+ Usage_Dig_TipPressure
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8191)
+ Input(Var|Abs) // Byte 6+7
+ // Two bytes padding so we don't need to change the report at all
+ ReportSize(8)
+ ReportCount(2)
+ Input(Const) // Byte 6+7
+ )
+ )
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // Byte 0
+ // We leave the pen on the vendor report ID
+ ReportId(VENDOR_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ // Note: reported logical range differs
+ // from the pen report ID for x and y
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32000)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(160)
+ // Bytes 2/3 in report
+ Usage_GD_X
+ Input(Var|Abs)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(20000)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(100)
+ // Bytes 4/5 in report
+ Usage_GD_Y
+ Input(Var|Abs)
+ )
+ // Bytes 6/7 in report
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8192)
+ Usage_Dig_TipPressure
+ Input(Var|Abs)
+ )
+ )
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ ReportId(PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Bytes 4 and 5 are the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x1)
+ UsageMaximum_i8(0xa)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(10)
+ ReportSize(1)
+ Input(Var|Abs)
+ Usage_i8(0x31) // maps to BTN_SOUTH
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportCount(5)
+ Input(Const)
+ // Byte 6 is the wheel
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+static const __u8 disabled_rdesc_pen[] = {
+ FixedSizeVendorReport(PEN_REPORT_LENGTH)
+};
+
+static const __u8 disabled_rdesc_pad[] = {
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_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;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* If we have a firmware ID and it matches our expected prefix, we
+ * disable the default pad/pen nodes. They won't send events
+ * but cause duplicate devices.
+ */
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+ if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
+ return sizeof(disabled_rdesc_pad);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ }
+ if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
+ return sizeof(disabled_rdesc_pen);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
+ return sizeof(fixed_rdesc_pen);
+ }
+ /* Always fix the vendor mode so the tablet will work even if nothing sets
+ * the udev property (e.g. huion-switcher run manually)
+ */
+ if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+ }
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Only sent if tablet is in default mode */
+ if (data[0] == PAD_REPORT_ID) {
+ /* Nicely enough, this device only supports one button down at a time so
+ * the reports are easy to match. Buttons numbered from the top
+ * Button released: 03 00 00 00 00 00 00 00
+ * Button 1: 03 00 05 00 00 00 00 00 -> b
+ * Button 2: 03 07 11 00 00 00 00 00 -> Ctrl Shift N
+ * Button 3: 03 00 08 00 00 00 00 00 -> e
+ * Button 4: 03 00 0c 00 00 00 00 00 -> i
+ * Button 5: 03 00 2c 00 00 00 00 00 -> space
+ * Button 6: 03 01 08 00 00 00 00 00 -> Ctrl E
+ * Button 7: 03 01 16 00 00 00 00 00 -> Ctrl S
+ * Button 8: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z
+ *
+ * Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl -
+ * Wheel up: 03 01 2e 00 00 00 00 00 -> Ctrl =
+ */
+ __u8 button = 0;
+ __u8 wheel = 0;
+
+ switch (data[1] << 8 | data[2]) {
+ case 0x0000:
+ break;
+ case 0x0005:
+ button = 1;
+ break;
+ case 0x0711:
+ button = 2;
+ break;
+ case 0x0008:
+ button = 3;
+ break;
+ case 0x000c:
+ button = 4;
+ break;
+ case 0x002c:
+ button = 5;
+ break;
+ case 0x0108:
+ button = 6;
+ break;
+ case 0x0116:
+ button = 7;
+ break;
+ case 0x051d:
+ button = 8;
+ break;
+ case 0x012d:
+ wheel = -1;
+ break;
+ case 0x012e:
+ wheel = 1;
+ break;
+ }
+
+ __u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button};
+
+ __builtin_memcpy(data, report, sizeof(report));
+ return sizeof(report);
+ }
+
+ /* Nothing to do for the PEN_REPORT_ID, it's already mapped */
+
+ /* Only sent if tablet is in raw mode */
+ if (data[0] == VENDOR_REPORT_ID) {
+ /* Pad reports */
+ if (data[1] & 0x20) {
+ /* See fixed_rdesc_pad */
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus;
+ __u8 x;
+ __u8 y;
+ __u16 buttons;
+ __u8 wheel;
+ } __attribute__((packed)) *pad_report;
+ __u8 wheel = 0;
+
+ /* Wheel report */
+ if (data[1] == 0xf1) {
+ if (data[5] == 2)
+ wheel = 0xff;
+ else
+ wheel = data[5];
+ } else {
+ /* data[4] and data[5] are the buttons, mapped correctly */
+ last_button_state = data[4] | (data[5] << 8);
+ wheel = 0; // wheel
+ }
+
+ pad_report = (struct pad_report *)data;
+
+ pad_report->report_id = PAD_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->wheel = wheel;
+
+ return sizeof(struct pad_report);
+ }
+
+ /* Pen reports need nothing done */
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(inspiroy_2) = {
+ .hid_device_event = (void *)inspiroy_2_fix_events,
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ case PEN_REPORT_DESCRIPTOR_LENGTH:
+ case VENDOR_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c b/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c
new file mode 100644
index 000000000..79453362b
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Inspiroy-2-S.bpf.c
@@ -0,0 +1,579 @@
+// 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 VID_HUION 0x256C
+#define PID_INSPIROY_2_S 0x0066
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_2_S),
+);
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+/* The prefix of the firmware ID we expect for this device. The full firmware
+ * string has a date suffix, e.g. HUION_T21j_221221
+ */
+char EXPECTED_FIRMWARE_ID[] = "HUION_T21j_";
+
+/* How this BPF program works: the tablet has two modes, firmware mode and
+ * tablet mode. In firmware mode (out of the box) the tablet sends button events
+ * and the dial as keyboard combinations. In tablet mode it uses a vendor specific
+ * hid report to report everything instead.
+ * Depending on the mode some hid reports are never sent and the corresponding
+ * devices are mute.
+ *
+ * To switch the tablet use e.g. https://github.com/whot/huion-switcher
+ * or one of the tools from the digimend project
+ *
+ * This BPF works for both modes. The huion-switcher tool sets the
+ * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
+ * pad and pen reports (by making them vendor collections that are ignored).
+ * If that property is not set we fix all hidraw nodes so the tablet works in
+ * either mode though the drawback is that the device will show up twice if
+ * you bind it to all event nodes
+ *
+ * Default report descriptor for the first exposed hidraw node:
+ *
+ * # HUION Huion Tablet_H641P
+ * # Report descriptor length: 18 bytes
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x58, // Report Size (88) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
+ *
+ * This rdesc does nothing until the tablet is switched to raw mode, see
+ * https://github.com/whot/huion-switcher
+ *
+ *
+ * Second hidraw node is the Pen. This one sends events until the tablet is
+ * switched to raw mode, then it's mute.
+ *
+ * # Report descriptor length: 93 bytes
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x0a, // Report ID (10) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x01, // Collection (Application) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x45, // Usage (Eraser) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18 <-- has no Invert eraser
+ * # 0x15, 0x00, // Logical Minimum (0) 20
+ * # 0x25, 0x01, // Logical Maximum (1) 22
+ * # 0x75, 0x01, // Report Size (1) 24
+ * # 0x95, 0x06, // Report Count (6) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x09, 0x32, // Usage (In Range) 30
+ * # 0x75, 0x01, // Report Size (1) 32
+ * # 0x95, 0x01, // Report Count (1) 34
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 40
+ * # 0x09, 0x30, // Usage (X) 42
+ * # 0x09, 0x31, // Usage (Y) 44
+ * # 0x55, 0x0d, // Unit Exponent (-3) 46 <-- change to -2
+ * # 0x65, 0x33, // Unit (EnglishLinear: in³) 48 <-- change in³ to in
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 50
+ * # 0x35, 0x00, // Physical Minimum (0) 53
+ * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 55 <-- invalid size
+ * # 0x75, 0x10, // Report Size (16) 58
+ * # 0x95, 0x02, // Report Count (2) 60
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 62
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 64
+ * # 0x09, 0x30, // Usage (Tip Pressure) 66
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 68
+ * # 0x75, 0x10, // Report Size (16) 71
+ * # 0x95, 0x01, // Report Count (1) 73
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 75
+ * # 0x09, 0x3d, // Usage (X Tilt) 77 <-- No tilt reported
+ * # 0x09, 0x3e, // Usage (Y Tilt) 79
+ * # 0x15, 0x81, // Logical Minimum (-127) 81
+ * # 0x25, 0x7f, // Logical Maximum (127) 83
+ * # 0x75, 0x08, // Report Size (8) 85
+ * # 0x95, 0x02, // Report Count (2) 87
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 89
+ * # 0xc0, // End Collection 91
+ * # 0xc0, // End Collection 92
+ * R: 93 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 45 09 3c 15 00 25 01 7501 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 09 3d09 3e 15 81 25 7f 75 08 95 02 81 02 c0 c0
+ *
+ * Third hidraw node is the pad which sends a combination of keyboard shortcuts until
+ * the tablet is switched to raw mode, then it's mute:
+ *
+ * # Report descriptor length: 65 bytes
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x06, // Usage (Keyboard) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x03, // Report ID (3) 6
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8
+ * # 0x19, 0xe0, // UsageMinimum (224) 10
+ * # 0x29, 0xe7, // UsageMaximum (231) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x08, // Report Count (8) 20
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 22
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24
+ * # 0x19, 0x00, // UsageMinimum (0) 26
+ * # 0x29, 0xff, // UsageMaximum (255) 28
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 30
+ * # 0x75, 0x08, // Report Size (8) 33
+ * # 0x95, 0x06, // Report Count (6) 35
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 37
+ * # 0xc0, // End Collection 39
+ * # 0x05, 0x0c, // Usage Page (Consumer) 40
+ * # 0x09, 0x01, // Usage (Consumer Control) 42
+ * # 0xa1, 0x01, // Collection (Application) 44
+ * # 0x85, 0x04, // Report ID (4) 46
+ * # 0x19, 0x00, // UsageMinimum (0) 48
+ * # 0x2a, 0x3c, 0x02, // UsageMaximum (572) 50
+ * # 0x15, 0x00, // Logical Minimum (0) 53
+ * # 0x26, 0x3c, 0x02, // Logical Maximum (572) 55
+ * # 0x95, 0x01, // Report Count (1) 58
+ * # 0x75, 0x10, // Report Size (16) 60
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 62
+ * # 0xc0, // End Collection 64
+ * R: 65 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 0507 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 00 2a 3c02 15 00 26 3c 02 95 01 75 10 81 00 c0
+ * N: HUION Huion Tablet_H641P
+ */
+
+#define PAD_REPORT_DESCRIPTOR_LENGTH 65
+#define PEN_REPORT_DESCRIPTOR_LENGTH 93
+#define VENDOR_REPORT_DESCRIPTOR_LENGTH 18
+#define PAD_REPORT_ID 3
+#define PEN_REPORT_ID 10
+#define VENDOR_REPORT_ID 8
+#define PAD_REPORT_LENGTH 8
+#define PEN_REPORT_LENGTH 10
+#define VENDOR_REPORT_LENGTH 12
+
+
+__u8 last_button_state;
+__u8 last_tip_state;
+__u8 last_sec_barrel_state;
+__u8 force_tip_down_count;
+
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 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 2/3 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 4 in report is the wheel
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ // Byte 5 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x1)
+ UsageMaximum_i8(0x6)
+ LogicalMinimum_i8(0x1)
+ LogicalMaximum_i8(0x6)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Arr|Abs)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+ )
+};
+
+static const __u8 fixed_rdesc_pen[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // -- Byte 0 in report
+ ReportId(PEN_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // -- Byte 1 in report
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch // maps eraser to BTN_STYLUS2
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(160)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_X
+ Input(Var|Abs) // Bytes 2+3
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(100)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32767)
+ Usage_GD_Y
+ Input(Var|Abs) // Bytes 4+5
+ )
+ UsagePage_Digitizers
+ Usage_Dig_TipPressure
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8191)
+ Input(Var|Abs) // Byte 6+7
+ // Two bytes padding so we don't need to change the report at all
+ ReportSize(8)
+ ReportCount(2)
+ Input(Const) // Byte 6+7
+ )
+ )
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ // Byte 0
+ // We leave the pen on the vendor report ID
+ ReportId(VENDOR_REPORT_ID)
+ Usage_Dig_Pen
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch
+ ReportCount(3)
+ Input(Var|Abs)
+ ReportCount(4) // Padding
+ Input(Const)
+ Usage_Dig_InRange
+ ReportCount(1)
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-1)
+ // Note: reported logical range differs
+ // from the pen report ID for x and y
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(32000)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(160)
+ // Bytes 2/3 in report
+ Usage_GD_X
+ Input(Var|Abs)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(20000)
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(100)
+ // Bytes 4/5 in report
+ Usage_GD_Y
+ Input(Var|Abs)
+ )
+ // Bytes 6/7 in report
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8192)
+ Usage_Dig_TipPressure
+ Input(Var|Abs)
+ )
+ )
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ ReportId(PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 are the buttons
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Byte 4 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x1)
+ UsageMaximum_i8(0x6)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(6)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(2)
+ Input(Const)
+ // Byte 5 is the wheel
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+static const __u8 disabled_rdesc_pen[] = {
+ FixedSizeVendorReport(PEN_REPORT_LENGTH)
+};
+
+static const __u8 disabled_rdesc_pad[] = {
+ FixedSizeVendorReport(PAD_REPORT_LENGTH)
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_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;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* If we have a firmware ID and it matches our expected prefix, we
+ * disable the default pad/pen nodes. They won't send events
+ * but cause duplicate devices.
+ */
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+ if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
+ return sizeof(disabled_rdesc_pad);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ }
+ if (rdesc_size == PEN_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pen, sizeof(disabled_rdesc_pen));
+ return sizeof(disabled_rdesc_pen);
+ }
+
+ __builtin_memcpy(data, fixed_rdesc_pen, sizeof(fixed_rdesc_pen));
+ return sizeof(fixed_rdesc_pen);
+ }
+ /* Always fix the vendor mode so the tablet will work even if nothing sets
+ * the udev property (e.g. huion-switcher run manually)
+ */
+ if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+
+ }
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(inspiroy_2_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Only sent if tablet is in default mode */
+ if (data[0] == PAD_REPORT_ID) {
+ /* Nicely enough, this device only supports one button down at a time so
+ * the reports are easy to match. Buttons numbered from the top
+ * Button released: 03 00 00 00 00 00 00 00
+ * Button 1: 03 00 05 00 00 00 00 00 -> b
+ * Button 2: 03 00 0c 00 00 00 00 00 -> i
+ * Button 3: 03 00 08 00 00 00 00 00 -> e
+ * Button 4: 03 01 16 00 00 00 00 00 -> Ctrl S
+ * Button 5: 03 00 2c 00 00 00 00 00 -> space
+ * Button 6: 03 05 1d 00 00 00 00 00 -> Ctrl Alt Z
+ *
+ * Wheel down: 03 01 2d 00 00 00 00 00 -> Ctrl -
+ * Wheel up: 03 01 2e 00 00 00 00 00 -> Ctrl =
+ */
+ __u8 button = 0;
+ __u8 wheel = 0;
+
+ switch (data[1] << 8 | data[2]) {
+ case 0x0000:
+ break;
+ case 0x0005:
+ button = 1;
+ break;
+ case 0x000c:
+ button = 2;
+ break;
+ case 0x0008:
+ button = 3;
+ break;
+ case 0x0116:
+ button = 4;
+ break;
+ case 0x002c:
+ button = 5;
+ break;
+ case 0x051d:
+ button = 6;
+ break;
+ case 0x012d:
+ wheel = -1;
+ break;
+ case 0x012e:
+ wheel = 1;
+ break;
+
+ }
+
+ __u8 report[6] = {PAD_REPORT_ID, 0x0, 0x0, 0x0, wheel, button};
+
+ __builtin_memcpy(data, report, sizeof(report));
+ return sizeof(report);
+ }
+
+ /* Nothing to do for the PEN_REPORT_ID, it's already mapped */
+
+ /* Only sent if tablet is in raw mode */
+ if (data[0] == VENDOR_REPORT_ID) {
+ /* Pad reports */
+ if (data[1] & 0x20) {
+ /* See fixed_rdesc_pad */
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus;
+ __u8 x;
+ __u8 y;
+ __u8 buttons;
+ __u8 wheel;
+ } __attribute__((packed)) *pad_report;
+ __u8 wheel = 0;
+
+ /* Wheel report */
+ if (data[1] == 0xf1) {
+ if (data[5] == 2)
+ wheel = 0xff;
+ else
+ wheel = data[5];
+ } else {
+ /* data[4] are the buttons, mapped correctly */
+ last_button_state = data[4];
+ wheel = 0; // wheel
+ }
+
+ pad_report = (struct pad_report *)data;
+
+ pad_report->report_id = PAD_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->wheel = wheel;
+
+ return sizeof(struct pad_report);
+ } else if (data[1] & 0x80) { /* Pen reports with InRange 1 */
+ __u8 tip_state = data[1] & 0x1;
+ __u8 sec_barrel_state = data[1] & 0x4;
+
+ if (force_tip_down_count > 0) {
+ data[1] |= 0x1;
+ --force_tip_down_count;
+ if (tip_state)
+ force_tip_down_count = 0;
+ }
+
+ /* Tip was down and we just pressed or released the
+ * secondary barrel switch (the physical eraser
+ * button). The device will send up to 4
+ * reports with Tip Switch 0 and sometimes
+ * this report has Tip Switch 0.
+ */
+ if (last_tip_state &&
+ last_sec_barrel_state != sec_barrel_state) {
+ force_tip_down_count = 4;
+ data[1] |= 0x1;
+ }
+ last_tip_state = tip_state;
+ last_sec_barrel_state = sec_barrel_state;
+ }
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(inspiroy_2) = {
+ .hid_device_event = (void *)inspiroy_2_fix_events,
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ case PEN_REPORT_DESCRIPTOR_LENGTH:
+ case VENDOR_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c b/drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c
new file mode 100644
index 000000000..e6ba2295d
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Inspiroy-Frego-M.bpf.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+/*
+ * Huion Inspiroy Frego M Pen Tablet
+ * Model L610
+ * 256c:8251 (Bluetooth)
+ * 256c:2012 (USB)
+ */
+#define VID_HUION 0x256C
+#define PID_INSPIROY_FREGO_M 0x8251
+#define PID_L610 0x2012
+
+#define PEN_RDESC_SIZE 125
+#define SECONDARY_SWITCH_OFFSET 17
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HUION, PID_INSPIROY_FREGO_M),
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_L610)
+);
+
+/*
+ * The pen descriptor reports the second side button as Secondary Tip Switch
+ * instead of Secondary Barrel Switch.
+ *
+ * Relevant part of the original pen report descriptor:
+ *
+ * 0x09, 0x42, // Usage (Tip Switch) 12
+ * 0x09, 0x44, // Usage (Barrel Switch) 14
+ * 0x09, 0x43, // Usage (Secondary Tip Switch) 16 <- change to 0x5a
+ * 0x09, 0x3c, // Usage (Invert) 18
+ * 0x09, 0x45, // Usage (Eraser) 20
+ * 0x15, 0x00, // Logical Minimum (0) 22
+ * 0x25, 0x01, // Logical Maximum (1) 24
+ */
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(fix_secondary_barrel_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (hctx->size != PEN_RDESC_SIZE)
+ return 0;
+
+ if (data[0] != 0x05 || data[1] != 0x0d || /* Usage Page (Digitizers) */
+ data[2] != 0x09 || data[3] != 0x02 || /* Usage (Pen) */
+ data[16] != 0x09 ||
+ data[SECONDARY_SWITCH_OFFSET] != 0x43) /* Secondary Tip Switch */
+ return 0;
+
+ data[SECONDARY_SWITCH_OFFSET] = 0x5a;
+
+ return 0;
+}
+
+HID_BPF_OPS(fix_secondary_barrel) = {
+ .hid_rdesc_fixup = (void *)fix_secondary_barrel_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != PEN_RDESC_SIZE;
+ if (ctx->retval) {
+ ctx->retval = -EINVAL;
+ return 0;
+ }
+
+ if (ctx->rdesc[0] != 0x05 || ctx->rdesc[1] != 0x0d || /* Usage Page (Digitizers) */
+ ctx->rdesc[2] != 0x09 || ctx->rdesc[3] != 0x02 || /* Usage (Pen) */
+ ctx->rdesc[16] != 0x09 ||
+ ctx->rdesc[SECONDARY_SWITCH_OFFSET] != 0x43) { /* Secondary Tip Switch */
+ ctx->retval = -EINVAL;
+ return 0;
+ }
+
+ ctx->retval = 0;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
new file mode 100644
index 000000000..5f43e4071
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Kamvas-Pro-19.bpf.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_HUION 0x256C
+#define PID_KAMVAS_PRO_19 0x006B
+#define PID_KAMVAS_PRO_27 0x006c
+#define NAME_KAMVAS_PRO_19 "HUION Huion Tablet_GT1902"
+#define NAME_KAMVAS_PRO_27 "HUION Huion Tablet_GT2701"
+
+#define TEST_PREFIX "uhid test "
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_19),
+ HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, VID_HUION, PID_KAMVAS_PRO_27),
+);
+
+bool prev_was_out_of_range;
+bool in_eraser_mode;
+
+/*
+ * We need to amend the report descriptor for the following:
+ * - the second button is reported through Secondary Tip Switch instead of Secondary Barrel Switch
+ * - the third button is reported through Invert, and we need some room to report it.
+ *
+ */
+static const __u8 fixed_rdesc[] = {
+ 0x05, 0x0d, // Usage Page (Digitizers) 0
+ 0x09, 0x02, // Usage (Pen) 2
+ 0xa1, 0x01, // Collection (Application) 4
+ 0x85, 0x0a, // Report ID (10) 6
+ 0x09, 0x20, // Usage (Stylus) 8
+ 0xa1, 0x01, // Collection (Application) 10
+ 0x09, 0x42, // Usage (Tip Switch) 12
+ 0x09, 0x44, // Usage (Barrel Switch) 14
+ 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from Secondary Tip Switch */
+ 0x09, 0x3c, // Usage (Invert) 18
+ 0x09, 0x45, // Usage (Eraser) 20
+ 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 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 */
+ 0x95, 0x01, // Report Count (1) /* inserted */
+ 0x81, 0x02, // Input (Data,Var,Abs) /* inserted */
+ 0x05, 0x0d, // Usage Page (Digitizers) /* inserted */
+ 0x09, 0x32, // Usage (In Range) 32
+ 0x75, 0x01, // Report Size (1) 34
+ 0x95, 0x01, // Report Count (1) 36
+ 0x81, 0x02, // Input (Data,Var,Abs) 38
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 40
+ 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ 0x09, 0x30, // Usage (X) 44
+ 0x09, 0x31, // Usage (Y) 46
+ 0x55, 0x0d, // Unit Exponent (-3) 48
+ 0x65, 0x33, // Unit (EnglishLinear: in³) 50
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52
+ 0x35, 0x00, // Physical Minimum (0) 55
+ 0x46, 0x00, 0x08, // Physical Maximum (2048) 57
+ 0x75, 0x10, // Report Size (16) 60
+ 0x95, 0x02, // Report Count (2) 62
+ 0x81, 0x02, // Input (Data,Var,Abs) 64
+ 0x05, 0x0d, // Usage Page (Digitizers) 66
+ 0x09, 0x30, // Usage (Tip Pressure) 68
+ 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70
+ 0x75, 0x10, // Report Size (16) 73
+ 0x95, 0x01, // Report Count (1) 75
+ 0x81, 0x02, // Input (Data,Var,Abs) 77
+ 0x09, 0x3d, // Usage (X Tilt) 79
+ 0x09, 0x3e, // Usage (Y Tilt) 81
+ 0x15, 0xa6, // Logical Minimum (-90) 83
+ 0x25, 0x5a, // Logical Maximum (90) 85
+ 0x75, 0x08, // Report Size (8) 87
+ 0x95, 0x02, // Report Count (2) 89
+ 0x81, 0x02, // Input (Data,Var,Abs) 91
+ 0xc0, // End Collection 93
+ 0xc0, // End Collection 94
+ 0x05, 0x0d, // Usage Page (Digitizers) 95
+ 0x09, 0x04, // Usage (Touch Screen) 97
+ 0xa1, 0x01, // Collection (Application) 99
+ 0x85, 0x04, // Report ID (4) 101
+ 0x09, 0x22, // Usage (Finger) 103
+ 0xa1, 0x02, // Collection (Logical) 105
+ 0x05, 0x0d, // Usage Page (Digitizers) 107
+ 0x95, 0x01, // Report Count (1) 109
+ 0x75, 0x06, // Report Size (6) 111
+ 0x09, 0x51, // Usage (Contact Id) 113
+ 0x15, 0x00, // Logical Minimum (0) 115
+ 0x25, 0x3f, // Logical Maximum (63) 117
+ 0x81, 0x02, // Input (Data,Var,Abs) 119
+ 0x09, 0x42, // Usage (Tip Switch) 121
+ 0x25, 0x01, // Logical Maximum (1) 123
+ 0x75, 0x01, // Report Size (1) 125
+ 0x95, 0x01, // Report Count (1) 127
+ 0x81, 0x02, // Input (Data,Var,Abs) 129
+ 0x75, 0x01, // Report Size (1) 131
+ 0x95, 0x01, // Report Count (1) 133
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 135
+ 0x05, 0x01, // Usage Page (Generic Desktop) 137
+ 0x75, 0x10, // Report Size (16) 139
+ 0x55, 0x0e, // Unit Exponent (-2) 141
+ 0x65, 0x11, // Unit (SILinear: cm) 143
+ 0x09, 0x30, // Usage (X) 145
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147
+ 0x35, 0x00, // Physical Minimum (0) 150
+ 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 155
+ 0x09, 0x31, // Usage (Y) 157
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159
+ 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 165
+ 0x05, 0x0d, // Usage Page (Digitizers) 167
+ 0x09, 0x30, // Usage (Tip Pressure) 169
+ 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171
+ 0x75, 0x10, // Report Size (16) 174
+ 0x95, 0x01, // Report Count (1) 176
+ 0x81, 0x02, // Input (Data,Var,Abs) 178
+ 0xc0, // End Collection 180
+ 0x05, 0x0d, // Usage Page (Digitizers) 181
+ 0x09, 0x22, // Usage (Finger) 183
+ 0xa1, 0x02, // Collection (Logical) 185
+ 0x05, 0x0d, // Usage Page (Digitizers) 187
+ 0x95, 0x01, // Report Count (1) 189
+ 0x75, 0x06, // Report Size (6) 191
+ 0x09, 0x51, // Usage (Contact Id) 193
+ 0x15, 0x00, // Logical Minimum (0) 195
+ 0x25, 0x3f, // Logical Maximum (63) 197
+ 0x81, 0x02, // Input (Data,Var,Abs) 199
+ 0x09, 0x42, // Usage (Tip Switch) 201
+ 0x25, 0x01, // Logical Maximum (1) 203
+ 0x75, 0x01, // Report Size (1) 205
+ 0x95, 0x01, // Report Count (1) 207
+ 0x81, 0x02, // Input (Data,Var,Abs) 209
+ 0x75, 0x01, // Report Size (1) 211
+ 0x95, 0x01, // Report Count (1) 213
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 215
+ 0x05, 0x01, // Usage Page (Generic Desktop) 217
+ 0x75, 0x10, // Report Size (16) 219
+ 0x55, 0x0e, // Unit Exponent (-2) 221
+ 0x65, 0x11, // Unit (SILinear: cm) 223
+ 0x09, 0x30, // Usage (X) 225
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227
+ 0x35, 0x00, // Physical Minimum (0) 230
+ 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 235
+ 0x09, 0x31, // Usage (Y) 237
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239
+ 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 245
+ 0x05, 0x0d, // Usage Page (Digitizers) 247
+ 0x09, 0x30, // Usage (Tip Pressure) 249
+ 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251
+ 0x75, 0x10, // Report Size (16) 254
+ 0x95, 0x01, // Report Count (1) 256
+ 0x81, 0x02, // Input (Data,Var,Abs) 258
+ 0xc0, // End Collection 260
+ 0x05, 0x0d, // Usage Page (Digitizers) 261
+ 0x09, 0x56, // Usage (Scan Time) 263
+ 0x55, 0x00, // Unit Exponent (0) 265
+ 0x65, 0x00, // Unit (None) 267
+ 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269
+ 0x95, 0x01, // Report Count (1) 274
+ 0x75, 0x20, // Report Size (32) 276
+ 0x81, 0x02, // Input (Data,Var,Abs) 278
+ 0x09, 0x54, // Usage (Contact Count) 280
+ 0x25, 0x7f, // Logical Maximum (127) 282
+ 0x95, 0x01, // Report Count (1) 284
+ 0x75, 0x08, // Report Size (8) 286
+ 0x81, 0x02, // Input (Data,Var,Abs) 288
+ 0x75, 0x08, // Report Size (8) 290
+ 0x95, 0x08, // Report Count (8) 292
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 294
+ 0x85, 0x05, // Report ID (5) 296
+ 0x09, 0x55, // Usage (Contact Max) 298
+ 0x25, 0x0a, // Logical Maximum (10) 300
+ 0x75, 0x08, // Report Size (8) 302
+ 0x95, 0x01, // Report Count (1) 304
+ 0xb1, 0x02, // Feature (Data,Var,Abs) 306
+ 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308
+ 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311
+ 0x85, 0x06, // Report ID (6) 313
+ 0x15, 0x00, // Logical Minimum (0) 315
+ 0x26, 0xff, 0x00, // Logical Maximum (255) 317
+ 0x75, 0x08, // Report Size (8) 320
+ 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)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ 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.
+ * Fortunately, before entering eraser mode, (so Invert = 1),
+ * the tablet always sends an out-of-proximity event.
+ * So we can detect that single event and:
+ * - if there was none but the invert bit was toggled: this is the
+ * third button
+ * - if there was this out-of-proximity event, we are entering
+ * eraser mode, and we will until the next out-of-proximity.
+ */
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(kamvas_pro_19_fix_3rd_button, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[0] != 0x0a) /* not the pen report ID */
+ return 0;
+
+ /* stylus is out of range */
+ if (!(data[1] & 0x40)) {
+ prev_was_out_of_range = true;
+ in_eraser_mode = false;
+ return 0;
+ }
+
+ /* going into eraser mode (Invert = 1) only happens after an
+ * out of range event
+ */
+ if (prev_was_out_of_range && (data[1] & 0x18))
+ in_eraser_mode = true;
+
+ /* eraser mode works fine */
+ if (in_eraser_mode)
+ return 0;
+
+ /* copy the Invert bit reported for the 3rd button in bit 7 */
+ if (data[1] & 0x08)
+ data[1] |= 0x20;
+
+ /* clear Invert bit now that it was copied */
+ data[1] &= 0xf7;
+
+ prev_was_out_of_range = false;
+
+ return 0;
+}
+
+HID_BPF_OPS(huion_Kamvas_pro_19) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas_pro_19,
+ .hid_device_event = (void *)kamvas_pro_19_fix_3rd_button,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+
+ ctx->retval = !((ctx->rdesc_size == PRE_240524_RDESC_SIZE) ||
+ (ctx->rdesc_size == FW_240524_RDESC_SIZE));
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ /* ensure the kernel isn't fixed already */
+ if (ctx->rdesc[17] != 0x43) /* Secondary Tip Switch */
+ ctx->retval = -EINVAL;
+
+ struct hid_bpf_ctx *hctx = hid_bpf_allocate_context(ctx->hid);
+
+ if (!hctx) {
+ return ctx->retval = -EINVAL;
+ return 0;
+ }
+
+ const char *name = hctx->hid->name;
+
+ /* strip out TEST_PREFIX */
+ if (!__builtin_memcmp(name, TEST_PREFIX, sizeof(TEST_PREFIX) - 1))
+ name += sizeof(TEST_PREFIX) - 1;
+
+ if (__builtin_memcmp(name, NAME_KAMVAS_PRO_19, sizeof(NAME_KAMVAS_PRO_19)) &&
+ __builtin_memcmp(name, NAME_KAMVAS_PRO_27, sizeof(NAME_KAMVAS_PRO_27)))
+ ctx->retval = -EINVAL;
+
+ hid_bpf_release_context(hctx);
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Kamvas13Gen3.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas13Gen3.bpf.c
new file mode 100644
index 000000000..b63f9a48e
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Kamvas13Gen3.bpf.c
@@ -0,0 +1,1395 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Nicholas LaPointe
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include "hid_report_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_HUION 0x256c
+#define PID_KAMVAS13_GEN3 0x2008
+
+#define VENDOR_DESCRIPTOR_LENGTH 36
+#define TABLET_DESCRIPTOR_LENGTH 368
+#define WHEEL_DESCRIPTOR_LENGTH 108
+
+#define VENDOR_REPORT_ID 8
+#define VENDOR_REPORT_LENGTH 14
+
+#define VENDOR_REPORT_SUBTYPE_PEN 0x08
+#define VENDOR_REPORT_SUBTYPE_PEN_OUT 0x00
+#define VENDOR_REPORT_SUBTYPE_BUTTONS 0x0e
+#define VENDOR_REPORT_SUBTYPE_WHEELS 0x0f
+
+/* For the reports that we create ourselves */
+#define CUSTOM_PAD_REPORT_ID 9
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_HUION, PID_KAMVAS13_GEN3),
+);
+
+
+/*
+ * This tablet can send reports using one of two different data formats,
+ * depending on what "mode" the tablet is in.
+ *
+ * By default, the tablet will send reports that can be decoded using its
+ * included HID descriptors (descriptors 1 and 2, shown below).
+ * This mode will be called "firmware mode" throughout this file.
+ *
+ * The HID descriptor that describes pen events in firmware mode (descriptor 1)
+ * has multiple bugs:
+ * * "Secondary Tip Switch" instead of "Secondary Barrel Switch"
+ * * "Invert" instead of (or potentially shared with) third barrel button
+ * * Specified tablet area of 2048 in³ instead of 293.8 x 165.2mm
+ * * Specified tilt range of -90 to +90 instead of -60 to +60
+ *
+ * While these can be easily patched up by editing the descriptor, a larger
+ * problem with the firmware mode exists: it is impossible to tell which of the
+ * two wheels are being rotated (or having their central button pressed).
+ *
+ *
+ * By using a tool such as huion-switcher (https://github.com/whot/huion-switcher),
+ * the tablet can be made to send reports using a proprietary format that is not
+ * adequately described by its relevant descriptor (descriptor 0, shown below).
+ * This mode will be called "vendor mode" throughout this file.
+ *
+ * The reports sent while in vendor mode allow for proper decoding of the wheels.
+ *
+ * For simplicity and maximum functionality, this BPF focuses strictly on
+ * enabling one to make use of the vendor mode.
+ */
+
+/*
+ * DESCRIPTORS
+ * DESCRIPTOR 0
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # ┅ 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x68, // Report Size (104) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 18
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 21
+ * # 0xa1, 0x01, // Collection (Application) 23
+ * # ┅ 0x85, 0x16, // Report ID (22) 25
+ * # 0x75, 0x08, // Report Size (8) 27
+ * # 0x95, 0x07, // Report Count (7) 29
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 31
+ * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 33
+ * # 0xc0, // End Collection 35
+ * R: 36 06 00 ff 09 01 a1 01 85 08 75 68 95 01 09 01 81 02 c0 06 00 ff 09 01 a1 01 85 16 75 08 95 07 09 01 b1 02 c0
+ * N: HUION Huion Tablet_GS1333
+ * I: 3 256c 2008
+ *
+ * DESCRIPTOR 1
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # ┅ 0x85, 0x0a, // Report ID (10) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x01, // Collection (Application) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x43, // Usage (Secondary Tip Switch) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18
+ * # 0x09, 0x45, // Usage (Eraser) 20
+ * # 0x15, 0x00, // Logical Minimum (0) 22
+ * # 0x25, 0x01, // Logical Maximum (1) 24
+ * # 0x75, 0x01, // Report Size (1) 26
+ * # 0x95, 0x06, // Report Count (6) 28
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 30
+ * # 0x09, 0x32, // Usage (In Range) 32
+ * # 0x75, 0x01, // Report Size (1) 34
+ * # 0x95, 0x01, // Report Count (1) 36
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 38
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x30, // Usage (X) 44
+ * # 0x09, 0x31, // Usage (Y) 46
+ * # 0x55, 0x0d, // Unit Exponent (-3) 48
+ * # 0x65, 0x33, // Unit (EnglishLinear: in³) 50
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52
+ * # 0x35, 0x00, // Physical Minimum (0) 55
+ * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 57
+ * # 0x75, 0x10, // Report Size (16) 60
+ * # 0x95, 0x02, // Report Count (2) 62
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 64
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 66
+ * # 0x09, 0x30, // Usage (Tip Pressure) 68
+ * # 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70
+ * # 0x75, 0x10, // Report Size (16) 73
+ * # 0x95, 0x01, // Report Count (1) 75
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 77
+ * # 0x09, 0x3d, // Usage (X Tilt) 79
+ * # 0x09, 0x3e, // Usage (Y Tilt) 81
+ * # 0x15, 0xa6, // Logical Minimum (-90) 83
+ * # 0x25, 0x5a, // Logical Maximum (90) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x02, // Report Count (2) 89
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 91
+ * # 0xc0, // End Collection 93
+ * # 0xc0, // End Collection 94
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 95
+ * # 0x09, 0x04, // Usage (Touch Screen) 97
+ * # 0xa1, 0x01, // Collection (Application) 99
+ * # ┅ 0x85, 0x04, // Report ID (4) 101
+ * # 0x09, 0x22, // Usage (Finger) 103
+ * # 0xa1, 0x02, // Collection (Logical) 105
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 107
+ * # 0x95, 0x01, // Report Count (1) 109
+ * # 0x75, 0x06, // Report Size (6) 111
+ * # 0x09, 0x51, // Usage (Contact Identifier) 113
+ * # 0x15, 0x00, // Logical Minimum (0) 115
+ * # 0x25, 0x3f, // Logical Maximum (63) 117
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 119
+ * # 0x09, 0x42, // Usage (Tip Switch) 121
+ * # 0x25, 0x01, // Logical Maximum (1) 123
+ * # 0x75, 0x01, // Report Size (1) 125
+ * # 0x95, 0x01, // Report Count (1) 127
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 129
+ * # 0x75, 0x01, // Report Size (1) 131
+ * # 0x95, 0x01, // Report Count (1) 133
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 135
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 137
+ * # 0x75, 0x10, // Report Size (16) 139
+ * # 0x55, 0x0e, // Unit Exponent (-2) 141
+ * # 0x65, 0x11, // Unit (SILinear: cm) 143
+ * # 0x09, 0x30, // Usage (X) 145
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147
+ * # 0x35, 0x00, // Physical Minimum (0) 150
+ * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152
+ * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 155
+ * # 0x09, 0x31, // Usage (Y) 157
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159
+ * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162
+ * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 165
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 167
+ * # 0x09, 0x30, // Usage (Tip Pressure) 169
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171
+ * # 0x75, 0x10, // Report Size (16) 174
+ * # 0x95, 0x01, // Report Count (1) 176
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 178
+ * # 0xc0, // End Collection 180
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 181
+ * # 0x09, 0x22, // Usage (Finger) 183
+ * # 0xa1, 0x02, // Collection (Logical) 185
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 187
+ * # 0x95, 0x01, // Report Count (1) 189
+ * # 0x75, 0x06, // Report Size (6) 191
+ * # 0x09, 0x51, // Usage (Contact Identifier) 193
+ * # 0x15, 0x00, // Logical Minimum (0) 195
+ * # 0x25, 0x3f, // Logical Maximum (63) 197
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 199
+ * # 0x09, 0x42, // Usage (Tip Switch) 201
+ * # 0x25, 0x01, // Logical Maximum (1) 203
+ * # 0x75, 0x01, // Report Size (1) 205
+ * # 0x95, 0x01, // Report Count (1) 207
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 209
+ * # 0x75, 0x01, // Report Size (1) 211
+ * # 0x95, 0x01, // Report Count (1) 213
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 215
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 217
+ * # 0x75, 0x10, // Report Size (16) 219
+ * # 0x55, 0x0e, // Unit Exponent (-2) 221
+ * # 0x65, 0x11, // Unit (SILinear: cm) 223
+ * # 0x09, 0x30, // Usage (X) 225
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227
+ * # 0x35, 0x00, // Physical Minimum (0) 230
+ * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232
+ * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 235
+ * # 0x09, 0x31, // Usage (Y) 237
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239
+ * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242
+ * # ┇ 0x81, 0x42, // Input (Data,Var,Abs,Null) 245
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 247
+ * # 0x09, 0x30, // Usage (Tip Pressure) 249
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251
+ * # 0x75, 0x10, // Report Size (16) 254
+ * # 0x95, 0x01, // Report Count (1) 256
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 258
+ * # 0xc0, // End Collection 260
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 261
+ * # 0x09, 0x56, // Usage (Scan Time) 263
+ * # 0x55, 0x00, // Unit Exponent (0) 265
+ * # 0x65, 0x00, // Unit (None) 267
+ * # 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269
+ * # 0x95, 0x01, // Report Count (1) 274
+ * # 0x75, 0x20, // Report Size (32) 276
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 278
+ * # 0x09, 0x54, // Usage (Contact Count) 280
+ * # 0x25, 0x7f, // Logical Maximum (127) 282
+ * # 0x95, 0x01, // Report Count (1) 284
+ * # 0x75, 0x08, // Report Size (8) 286
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 288
+ * # 0x75, 0x08, // Report Size (8) 290
+ * # 0x95, 0x08, // Report Count (8) 292
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 294
+ * # ┅ 0x85, 0x05, // Report ID (5) 296
+ * # 0x09, 0x55, // Usage (Contact Count Maximum) 298
+ * # 0x25, 0x0a, // Logical Maximum (10) 300
+ * # 0x75, 0x08, // Report Size (8) 302
+ * # 0x95, 0x01, // Report Count (1) 304
+ * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 306
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page FF00) 308
+ * # 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311
+ * # ┅ 0x85, 0x06, // Report ID (6) 313
+ * # 0x15, 0x00, // Logical Minimum (0) 315
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 317
+ * # 0x75, 0x08, // Report Size (8) 320
+ * # 0x96, 0x00, 0x01, // Report Count (256) 322
+ * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 325
+ * # 0xc0, // End Collection 327
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 328
+ * # 0x09, 0x06, // Usage (Keyboard) 330
+ * # 0xa1, 0x01, // Collection (Application) 332
+ * # ┅ 0x85, 0x03, // Report ID (3) 334
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 336
+ * # 0x19, 0xe0, // UsageMinimum (224) 338
+ * # 0x29, 0xe7, // UsageMaximum (231) 340
+ * # 0x15, 0x00, // Logical Minimum (0) 342
+ * # 0x25, 0x01, // Logical Maximum (1) 344
+ * # 0x75, 0x01, // Report Size (1) 346
+ * # 0x95, 0x08, // Report Count (8) 348
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 350
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 352
+ * # 0x19, 0x00, // UsageMinimum (0) 354
+ * # 0x29, 0xff, // UsageMaximum (255) 356
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 358
+ * # 0x75, 0x08, // Report Size (8) 361
+ * # 0x95, 0x06, // Report Count (6) 363
+ * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 365
+ * # 0xc0, // End Collection 367
+ * R: 368 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0
+ * N: HUION Huion Tablet_GS1333
+ * I: 3 256c 2008
+ *
+ * DESCRIPTOR 2
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # ┅ 0x85, 0x11, // Report ID (17) 6
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 8
+ * # 0x09, 0x21, // Usage (Puck) 10
+ * # 0xa1, 0x02, // Collection (Logical) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x01, // Report Count (1) 20
+ * # 0xa1, 0x00, // Collection (Physical) 22
+ * # 0x05, 0x09, // Usage Page (Button) 24
+ * # 0x09, 0x01, // Usage (Button 1) 26
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 30
+ * # 0x09, 0x33, // Usage (Touch) 32
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 34
+ * # 0x95, 0x06, // Report Count (6) 36
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0xa1, 0x02, // Collection (Logical) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x37, // Usage (Dial) 44
+ * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49
+ * # 0x75, 0x10, // Report Size (16) 52
+ * # 0x95, 0x01, // Report Count (1) 54
+ * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 56
+ * # 0x35, 0x00, // Physical Minimum (0) 58
+ * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60
+ * # 0x15, 0x00, // Logical Minimum (0) 63
+ * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65
+ * # 0x09, 0x48, // Usage (Resolution Multiplier) 68
+ * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 70
+ * # 0x45, 0x00, // Physical Maximum (0) 72
+ * # 0xc0, // End Collection 74
+ * # 0x75, 0x08, // Report Size (8) 75
+ * # 0x95, 0x01, // Report Count (1) 77
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 79
+ * # 0x75, 0x08, // Report Size (8) 81
+ * # 0x95, 0x01, // Report Count (1) 83
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x01, // Report Count (1) 89
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 91
+ * # 0x75, 0x08, // Report Size (8) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 97
+ * # 0x75, 0x08, // Report Size (8) 99
+ * # 0x95, 0x01, // Report Count (1) 101
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 103
+ * # 0xc0, // End Collection 105
+ * # 0xc0, // End Collection 106
+ * # 0xc0, // End Collection 107
+ * R: 108 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0
+ * N: HUION Huion Tablet_GS1333
+ * I: 3 256c 2008
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * VENDOR MODE
+ * HUION_FIRMWARE_ID="HUION_M22c_240606"
+ * HUION_MAGIC_BYTES="140388e500108100ff3fd8130307008008004010"
+ *
+ * MAGIC BYTES
+ * [LogicalMaximum, X] [LogicalMaximum, Y] [LogicalMaximum, Pressure] [ LPI]
+ * 14 03 [ 88 e5] 00 [ 10 81] 00 [ ff 3f] [d8 13] 03 07 00 80 08 00 40 10
+ *
+ *
+ * HIDRAW 0
+ * DESCRIPTIONS
+ * report_subtype = (data[1] >> 4) & 0x0f
+ *
+ * REPORT SUBTYPES
+ * 0x0e Buttons
+ * (data[4] & 0x01) button 1
+ * (data[4] & 0x02) button 2
+ * (data[4] & 0x04) button 3
+ * (data[4] & 0x08) button 4
+ * (data[4] & 0x10) button 5
+ * (data[4] & 0x20) button 6 (top wheel button)
+ * (data[4] & 0x40) button 7 (bottom wheel button)
+ *
+ * All tablet buttons release with the same report:
+ * 08 e0 01 01 00 00 00 00 00 00 00 00 00 00
+ *
+ * Despite data[4] looking like a bit field, only one button
+ * can be unambiguously tracked at a time.
+ * (See NOTES ON SIMULTANEOUS BUTTON HOLDS at the end of this
+ * comment for examples of the confusion this can create.)
+ *
+ * All buttons, with the exceptions of 6 and 7, will repeatedly
+ * report a press event approximately every 225ms while held.
+ *
+ * 0x0f Wheels
+ * data[3] == 1: top wheel
+ * data[3] == 2: bottom wheel
+ * data[5] == 1: clockwise
+ * data[5] == 2: counter-clockwise
+ *
+ * 0x08/0x00 Pen
+ * report_subtype == 0x08: in-range
+ * report_subtype == 0x00: out-of-range
+ * For clarity, this is also equivalent to:
+ * (data[1] & 0x80) in-range
+ *
+ * Switches
+ * (data[1] & 0x01) tip switch
+ * (data[1] & 0x02) barrel switch
+ * (data[1] & 0x04) secondary barrel switch
+ * (data[1] & 0x08) third barrel switch
+ *
+ * Unfortunately, I don't have a pen with an eraser, so I can't
+ * confirm where the invert and eraser bits reside.
+ * If we guess using the definitions from HID descriptor 1,
+ * then they might be...
+ * (data[1] & 0x08) invert (conflicts with third barrel switch)
+ * (data[1] & 0x10) eraser
+ *
+ * data[2], data[3] X (little-endian, maximum 0xe588)
+ *
+ * data[4], data[5] Y (little-endian, maximum 0x8110)
+ *
+ * data[6], data[7] Pressure (little-endian, maximum 0x3fff)
+ *
+ * data[10] X tilt (signed, -60 to +60)
+ * data[11] Y tilt (signed, -60 to +60, inverted)
+ *
+ *
+ * EXAMPLE REPORTS
+ * Top wheel button, press, hold, then release
+ * E: 000000.000040 14 08 e0 01 01 20 00 00 00 00 00 00 00 00 00
+ * E: 000001.531559 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00
+ *
+ * Bottom wheel button, press, hold, then release
+ * E: 000002.787603 14 08 e0 01 01 40 00 00 00 00 00 00 00 00 00
+ * E: 000004.215609 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00
+ *
+ *
+ * Top wheel rotation, one detent CW
+ * E: 000194.003899 14 08 f1 01 01 00 01 00 00 00 00 00 00 00 00
+ *
+ * Top wheel rotation, one detent CCW
+ * E: 000194.997812 14 08 f1 01 01 00 02 00 00 00 00 00 00 00 00
+ *
+ * Bottom wheel rotation, one detent CW
+ * E: 000196.693840 14 08 f1 01 02 00 01 00 00 00 00 00 00 00 00
+ *
+ * Bottom wheel rotation, one detent CCW
+ * E: 000197.757895 14 08 f1 01 02 00 02 00 00 00 00 00 00 00 00
+ *
+ *
+ * Button 1, press, hold, then release
+ * E: 000000.000149 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 < press
+ * E: 000000.447598 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms
+ * E: 000000.673586 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00
+ * E: 000000.900582 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00
+ * E: 000001.126703 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00
+ * E: 000001.347706 14 08 e0 01 01 01 00 00 00 00 00 00 00 00 00
+ * E: 000001.533721 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release
+ *
+ * Button 2, press, hold, then release
+ * E: 000003.304735 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 < press
+ * E: 000003.746743 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms
+ * E: 000003.973741 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00
+ * E: 000004.199832 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00
+ * E: 000004.426732 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00
+ * E: 000004.647738 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00
+ * E: 000004.874733 14 08 e0 01 01 02 00 00 00 00 00 00 00 00 00
+ * E: 000004.930713 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release
+ *
+ * Button 3, press, hold, then release
+ * E: 000006.650346 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 < press
+ * E: 000007.051782 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms
+ * E: 000007.273738 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00
+ * E: 000007.499794 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00
+ * E: 000007.726725 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00
+ * E: 000007.947765 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00
+ * E: 000008.174755 14 08 e0 01 01 04 00 00 00 00 00 00 00 00 00
+ * E: 000008.328786 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release
+ *
+ * Button 4, press, hold, then release
+ * E: 000009.893820 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 < press
+ * E: 000010.274781 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms
+ * E: 000010.500931 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00
+ * E: 000010.722777 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00
+ * E: 000010.948778 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00
+ * E: 000011.175799 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00
+ * E: 000011.401153 14 08 e0 01 01 08 00 00 00 00 00 00 00 00 00
+ * E: 000011.432114 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release
+ *
+ * Button 5, press, hold, then release
+ * E: 000013.007778 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 < press
+ * E: 000013.424741 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00 < starting to auto-repeat, every ~225ms
+ * E: 000013.651715 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00
+ * E: 000013.872763 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00
+ * E: 000014.099789 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00
+ * E: 000014.325734 14 08 e0 01 01 10 00 00 00 00 00 00 00 00 00
+ * E: 000014.438080 14 08 e0 01 01 00 00 00 00 00 00 00 00 00 00 < release
+ *
+ *
+ * Pen: Top-left, then out of range
+ * E: 000368.572184 14 08 80 00 00 00 00 00 00 00 00 fb ed 03 00
+ * E: 000368.573030 14 08 00 00 00 00 00 00 00 00 00 fb ed 03 00
+ *
+ * Pen: Bottom-right, then out of range
+ * E: 000544.433185 14 08 80 88 e5 10 81 00 00 00 00 00 00 03 00
+ * E: 000544.434183 14 08 00 88 e5 10 81 00 00 00 00 00 00 03 00
+ *
+ * Pen: Max Y tilt (tip of pen points down)
+ * E: 000002.231927 14 08 80 f5 5d 6c 36 00 00 00 00 09 3c 03 00
+ *
+ * Pen: Min Y Tilt (tip of pen points up)
+ * E: 000657.593338 14 08 80 5f 69 fa 2c 00 00 00 00 fe c4 03 00
+ *
+ * Pen: Max X tilt (tip of pen points left)
+ * E: 000742.246503 14 08 80 2a 4f c4 38 00 00 00 00 3c ed 03 00
+ *
+ * Pen: Min X Tilt (tip of pen points right)
+ * E: 000776.404446 14 08 00 18 85 7c 3b 00 00 00 00 c4 ed 03 00
+ *
+ * Pen: Tip switch, max pressure, then low pressure
+ * E: 001138.935675 14 08 81 d2 66 04 40 ff 3f 00 00 00 08 03 00
+ *
+ * E: 001142.403715 14 08 81 9d 69 47 3e 82 04 00 00 00 07 03 00
+ *
+ * Pen: Barrel switch
+ * E: 001210.645652 14 08 82 0d 72 ea 2b 00 00 00 00 db c4 03 00
+ *
+ * Pen: Secondary barrel switch
+ * E: 001211.519729 14 08 84 2c 71 51 2b 00 00 00 00 da c4 03 00
+ *
+ * Pen: Third switch
+ * E: 001212.443722 14 08 88 1d 72 df 2b 00 00 00 00 dc c4 03 00
+ *
+ *
+ * HIDRAW 1
+ * No reports
+ *
+ *
+ * HIDRAW 2
+ * No reports
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * FIRMWARE MODE
+ * HIDRAW 0
+ * No reports
+ *
+ *
+ * HIDRAW 1
+ * EXAMPLE REPORTS
+ * Top wheel button, *release*
+ * E: 000067.043739 8 03 00 00 00 00 00 00 00
+ *
+ * Bottom wheel button, *release*
+ * E: 000068.219161 8 03 00 00 00 00 00 00 00
+ *
+ *
+ * Button 1, press, then release
+ * E: 000163.767870 8 03 00 05 00 00 00 00 00
+ * E: 000165.969193 8 03 00 00 00 00 00 00 00
+ *
+ * Button 2, press, then release
+ * E: 000261.728935 8 03 05 11 00 00 00 00 00
+ * E: 000262.956220 8 03 00 00 00 00 00 00 00
+ *
+ * Button 3, press, then release
+ * E: 000289.127881 8 03 01 16 00 00 00 00 00
+ * E: 000290.014594 8 03 00 00 00 00 00 00 00
+ *
+ * Button 4, press, then release
+ * E: 000303.025839 8 03 00 2c 00 00 00 00 00
+ * E: 000303.994479 8 03 00 00 00 00 00 00 00
+ *
+ * Button 5, press, then release
+ * E: 000315.500835 8 03 05 1d 00 00 00 00 00
+ * E: 000316.603274 8 03 00 00 00 00 00 00 00
+ *
+ * BUTTON SUMMARY
+ * 1 E: 000163.767870 8 03 00 05 00 00 00 00 00 Keyboard: B
+ * 2 E: 000261.728935 8 03 05 11 00 00 00 00 00 Keyboard: LCtrl+LAlt N
+ * 3 E: 000289.127881 8 03 01 16 00 00 00 00 00 Keyboard: LCtrl S
+ * 4 E: 000303.025839 8 03 00 2c 00 00 00 00 00 Keyboard: Space
+ * 5 E: 000315.500835 8 03 05 1d 00 00 00 00 00 Keyboard: LCtrl+LAlt
+ *
+ * All buttons (including the wheel buttons) release the same way:
+ * 03 00 00 00 00 00 00 00
+ *
+ *
+ * Pen: Top-left, then out of range
+ * E: 000063.196828 10 0a c0 00 00 00 00 00 00 00 02
+ * E: 000063.197762 10 0a 00 00 00 00 00 00 00 00 02
+ *
+ * Pen: Bottom-right, then out of range
+ * E: 000197.123138 10 0a c0 ff 7f ff 7f 00 00 00 00
+ * E: 000197.124915 10 0a 00 ff 7f ff 7f 00 00 00 00
+ *
+ * Pen: Max Y Tilt (tip of pen points up)
+ * E: 000291.399541 10 0a c0 19 32 0b 58 00 00 00 3c
+ *
+ * Pen: Min Y tilt (tip of pen points down)
+ * E: 000340.888288 10 0a c0 85 40 89 6e 00 00 17 c4
+ *
+ * Pen: Max X tilt (tip of pen points left)
+ * E: 000165.575115 10 0a c0 a7 34 99 42 00 00 3c f4
+ *
+ * Pen: Min X Tilt (tip of pen points right)
+ * E: 000129.507883 10 0a c0 ea 4b 08 40 00 00 c4 1a
+ *
+ * Pen: Tip switch, max pressure, then low pressure
+ * E: 000242.077160 10 0a c1 7e 3c 12 31 ff 3f 03 fd
+ *
+ * E: 000339.139188 10 0a c1 ee 3a 9e 32 b5 00 06 f6
+ *
+ * Pen: Barrel switch
+ * E: 000037.949777 10 0a c2 5c 28 47 2a 00 00 f6 3c
+ *
+ * Pen: Secondary barrel switch
+ * E: 000038.320840 10 0a c4 e4 27 fd 29 00 00 f3 38
+ *
+ * Pen: Third switch
+ * E: 000038.923822 10 0a c8 97 27 5f 29 00 00 f2 33
+ *
+ *
+ * HIDRAW 2
+ * EXAMPLE REPORTS
+ * Either wheel rotation, one detent CW
+ * E: 000097.276573 9 11 00 01 00 00 00 00 00 00
+ *
+ * Either wheel rotation, one detent CCW
+ * E: 000153.416538 9 11 00 ff ff 00 00 00 00 00
+ *
+ * Either wheel rotation, increasing rotation speed CW
+ * (Note that the wheels on my particular tablet may be
+ * damaged, so the false rotation direction changes
+ * that can be observed might not happen on other units.)
+ * E: 000210.514925 9 11 00 01 00 00 00 00 00 00
+ * E: 000210.725718 9 11 00 01 00 00 00 00 00 00
+ * E: 000210.924009 9 11 00 01 00 00 00 00 00 00
+ * E: 000211.205629 9 11 00 01 00 00 00 00 00 00
+ * E: 000211.280521 9 11 00 0b 00 00 00 00 00 00
+ * E: 000211.340121 9 11 00 0e 00 00 00 00 00 00
+ * E: 000211.404018 9 11 00 0d 00 00 00 00 00 00
+ * E: 000211.462060 9 11 00 0e 00 00 00 00 00 00
+ * E: 000211.544886 9 11 00 0a 00 00 00 00 00 00
+ * E: 000211.606130 9 11 00 0d 00 00 00 00 00 00
+ * E: 000211.674560 9 11 00 0c 00 00 00 00 00 00
+ * E: 000211.712039 9 11 00 16 00 00 00 00 00 00
+ * E: 000211.748076 9 11 00 17 00 00 00 00 00 00
+ * E: 000211.786016 9 11 00 17 00 00 00 00 00 00
+ * E: 000211.832960 9 11 00 11 00 00 00 00 00 00
+ * E: 000211.874081 9 11 00 14 00 00 00 00 00 00
+ * E: 000211.925094 9 11 00 10 00 00 00 00 00 00
+ * E: 000211.959048 9 11 00 18 00 00 00 00 00 00
+ * E: 000212.006937 9 11 00 11 00 00 00 00 00 00
+ * E: 000212.050055 9 11 00 13 00 00 00 00 00 00
+ * E: 000212.091947 9 11 00 14 00 00 00 00 00 00
+ * E: 000212.122989 9 11 00 1a 00 00 00 00 00 00
+ * E: 000212.160866 9 11 00 16 00 00 00 00 00 00
+ * E: 000212.194002 9 11 00 19 00 00 00 00 00 00
+ * E: 000212.242249 9 11 00 11 00 00 00 00 00 00
+ * E: 000212.278061 9 11 00 18 00 00 00 00 00 00
+ * E: 000212.328899 9 11 00 10 00 00 00 00 00 00
+ * E: 000212.354005 9 11 00 22 00 00 00 00 00 00
+ * E: 000212.398995 9 11 00 12 00 00 00 00 00 00
+ * E: 000212.432050 9 11 00 19 00 00 00 00 00 00
+ * E: 000212.471164 9 11 00 16 00 00 00 00 00 00
+ * E: 000212.507047 9 11 00 17 00 00 00 00 00 00
+ * E: 000212.540964 9 11 00 19 00 00 00 00 00 00
+ * E: 000212.567942 9 11 00 1f 00 00 00 00 00 00
+ * E: 000212.610007 9 11 00 14 00 00 00 00 00 00
+ * E: 000212.641101 9 11 00 1b 00 00 00 00 00 00
+ * E: 000212.674113 9 11 00 19 00 00 00 00 00 00
+ * E: 000212.674909 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.677062 9 11 00 00 02 00 00 00 00 00
+ * E: 000212.679048 9 11 00 55 01 00 00 00 00 00
+ * E: 000212.682166 9 11 00 55 01 00 00 00 00 00
+ * E: 000212.682788 9 11 00 ff ff 00 00 00 00 00
+ * E: 000212.683899 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.685827 9 11 00 67 fe 00 00 00 00 00
+ * E: 000212.686941 9 11 00 00 08 00 00 00 00 00
+ * E: 000212.727840 9 11 00 14 00 00 00 00 00 00
+ * E: 000212.772884 9 11 00 13 00 00 00 00 00 00
+ * E: 000212.810975 9 11 00 16 00 00 00 00 00 00
+ * E: 000212.811793 9 11 00 00 08 00 00 00 00 00
+ * E: 000212.812683 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.813905 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.814909 9 11 00 00 04 00 00 00 00 00
+ * E: 000212.816942 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.817851 9 11 00 ff ff 00 00 00 00 00
+ * E: 000212.818752 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.819910 9 11 00 56 fd 00 00 00 00 00
+ * E: 000212.820781 9 11 00 ff ff 00 00 00 00 00
+ * E: 000212.821811 9 11 00 00 04 00 00 00 00 00
+ * E: 000212.822920 9 11 00 00 08 00 00 00 00 00
+ * E: 000212.823861 9 11 00 00 02 00 00 00 00 00
+ * E: 000212.828781 9 11 00 ba 00 00 00 00 00 00
+ * E: 000212.874097 9 11 00 12 00 00 00 00 00 00
+ * E: 000212.874872 9 11 00 00 fc 00 00 00 00 00
+ * E: 000212.876136 9 11 00 00 fc 00 00 00 00 00
+ * E: 000212.877036 9 11 00 00 f8 00 00 00 00 00
+ * E: 000212.877993 9 11 00 00 f8 00 00 00 00 00
+ * E: 000212.879748 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.880728 9 11 00 01 00 00 00 00 00 00
+ * E: 000212.881956 9 11 00 00 04 00 00 00 00 00
+ * E: 000212.885065 9 11 00 ff ff 00 00 00 00 00
+ * E: 000212.917060 9 11 00 1a 00 00 00 00 00 00
+ * E: 000212.936458 9 11 00 2d 00 00 00 00 00 00
+ * E: 000212.957860 9 11 00 25 00 00 00 00 00 00
+ * E: 000212.984019 9 11 00 20 00 00 00 00 00 00
+ * E: 000213.017915 9 11 00 19 00 00 00 00 00 00
+ * E: 000213.039973 9 11 00 27 00 00 00 00 00 00
+ * E: 000213.065933 9 11 00 21 00 00 00 00 00 00
+ * E: 000213.085807 9 11 00 28 00 00 00 00 00 00
+ * E: 000213.108888 9 11 00 25 00 00 00 00 00 00
+ * E: 000213.129726 9 11 00 29 00 00 00 00 00 00
+ * E: 000213.172043 9 11 00 14 00 00 00 00 00 00
+ * E: 000213.195873 9 11 00 23 00 00 00 00 00 00
+ * E: 000213.222884 9 11 00 20 00 00 00 00 00 00
+ * E: 000213.243220 9 11 00 2a 00 00 00 00 00 00
+ * E: 000213.266778 9 11 00 24 00 00 00 00 00 00
+ * E: 000213.285951 9 11 00 2b 00 00 00 00 00 00
+ * E: 000213.306045 9 11 00 2a 00 00 00 00 00 00
+ * E: 000213.306796 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.307755 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.308820 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.309971 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.310980 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.311853 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.312861 9 11 00 aa 02 00 00 00 00 00
+ * E: 000213.313884 9 11 00 00 f8 00 00 00 00 00
+ * E: 000213.315111 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.315992 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.316955 9 11 00 00 08 00 00 00 00 00
+ * E: 000213.346065 9 11 00 1d 00 00 00 00 00 00
+ * E: 000213.346963 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.347874 9 11 00 00 08 00 00 00 00 00
+ * E: 000213.348736 9 11 00 00 08 00 00 00 00 00
+ * E: 000213.349795 9 11 00 00 04 00 00 00 00 00
+ * E: 000213.350791 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.351791 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.352729 9 11 00 00 f8 00 00 00 00 00
+ * E: 000213.353811 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.354755 9 11 00 00 f8 00 00 00 00 00
+ * E: 000213.355795 9 11 00 00 f8 00 00 00 00 00
+ * E: 000213.356813 9 11 00 01 00 00 00 00 00 00
+ * E: 000213.357817 9 11 00 00 04 00 00 00 00 00
+ * E: 000213.393838 9 11 00 17 00 00 00 00 00 00
+ * E: 000213.394719 9 11 00 00 04 00 00 00 00 00
+ * E: 000213.395682 9 11 00 00 08 00 00 00 00 00
+ * E: 000213.396679 9 11 00 00 04 00 00 00 00 00
+ * E: 000213.397651 9 11 00 00 fc 00 00 00 00 00
+ * E: 000213.398661 9 11 00 ff ff 00 00 00 00 00
+ * E: 000213.400308 9 11 00 56 fd 00 00 00 00 00
+ * E: 000213.400909 9 11 00 00 f8 00 00 00 00 00
+ * E: 000213.401837 9 11 00 01 00 00 00 00 00 00
+ *
+ * Either wheel rotation, increasing rotation speed CCW
+ * (Note that the wheels on my particular tablet may be
+ * damaged, so the false rotation direction changes
+ * that can be observed might not happen on other units.)
+ * E: 000040.527820 9 11 00 ff ff 00 00 00 00 00
+ * E: 000040.816644 9 11 00 ff ff 00 00 00 00 00
+ * E: 000040.880423 9 11 00 f3 ff 00 00 00 00 00
+ * E: 000040.882570 9 11 00 ff ff 00 00 00 00 00
+ * E: 000040.883381 9 11 00 ff ff 00 00 00 00 00
+ * E: 000040.885463 9 11 00 aa 02 00 00 00 00 00
+ * E: 000040.924106 9 11 00 ea ff 00 00 00 00 00
+ * E: 000041.006155 9 11 00 f6 ff 00 00 00 00 00
+ * E: 000041.085799 9 11 00 f6 ff 00 00 00 00 00
+ * E: 000041.168492 9 11 00 f6 ff 00 00 00 00 00
+ * E: 000041.233453 9 11 00 f3 ff 00 00 00 00 00
+ * E: 000041.296641 9 11 00 f3 ff 00 00 00 00 00
+ * E: 000041.370302 9 11 00 f5 ff 00 00 00 00 00
+ * E: 000041.437410 9 11 00 f4 ff 00 00 00 00 00
+ * E: 000041.474514 9 11 00 e9 ff 00 00 00 00 00
+ * E: 000041.522171 9 11 00 ef ff 00 00 00 00 00
+ * E: 000041.568160 9 11 00 ee ff 00 00 00 00 00
+ * E: 000041.608146 9 11 00 ec ff 00 00 00 00 00
+ * E: 000041.627132 9 11 00 d3 ff 00 00 00 00 00
+ * E: 000041.656151 9 11 00 e3 ff 00 00 00 00 00
+ * E: 000041.682264 9 11 00 e0 ff 00 00 00 00 00
+ * E: 000041.714186 9 11 00 e6 ff 00 00 00 00 00
+ * E: 000041.740339 9 11 00 e0 ff 00 00 00 00 00
+ * E: 000041.772087 9 11 00 e5 ff 00 00 00 00 00
+ * E: 000041.801093 9 11 00 e3 ff 00 00 00 00 00
+ * E: 000041.834051 9 11 00 e7 ff 00 00 00 00 00
+ * E: 000041.863094 9 11 00 e3 ff 00 00 00 00 00
+ * E: 000041.901016 9 11 00 ea ff 00 00 00 00 00
+ * E: 000041.901956 9 11 00 00 04 00 00 00 00 00
+ * E: 000041.902837 9 11 00 00 fe 00 00 00 00 00
+ * E: 000041.903927 9 11 00 01 00 00 00 00 00 00
+ * E: 000041.905066 9 11 00 01 00 00 00 00 00 00
+ * E: 000041.907214 9 11 00 00 fe 00 00 00 00 00
+ * E: 000041.909011 9 11 00 01 00 00 00 00 00 00
+ * E: 000041.909953 9 11 00 01 00 00 00 00 00 00
+ * E: 000041.910917 9 11 00 00 08 00 00 00 00 00
+ * E: 000041.913280 9 11 00 00 fe 00 00 00 00 00
+ * E: 000041.914121 9 11 00 56 fd 00 00 00 00 00
+ * E: 000041.915346 9 11 00 ff ff 00 00 00 00 00
+ * E: 000041.962101 9 11 00 ee ff 00 00 00 00 00
+ * E: 000041.964062 9 11 00 56 fd 00 00 00 00 00
+ * E: 000041.964978 9 11 00 00 fc 00 00 00 00 00
+ * E: 000041.968058 9 11 00 24 01 00 00 00 00 00
+ * E: 000041.968880 9 11 00 56 fd 00 00 00 00 00
+ * E: 000041.970977 9 11 00 aa 02 00 00 00 00 00
+ * E: 000041.971932 9 11 00 ff ff 00 00 00 00 00
+ * E: 000041.972943 9 11 00 01 00 00 00 00 00 00
+ * E: 000041.975291 9 11 00 ff ff 00 00 00 00 00
+ * E: 000041.978274 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.035079 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.041283 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.042057 9 11 00 00 04 00 00 00 00 00
+ * E: 000042.045169 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.051242 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.056099 9 11 00 63 ff 00 00 00 00 00
+ * E: 000042.106329 9 11 00 ef ff 00 00 00 00 00
+ * E: 000042.108601 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.116259 9 11 00 6b 00 00 00 00 00 00
+ * E: 000042.119140 9 11 00 55 01 00 00 00 00 00
+ * E: 000042.126101 9 11 00 88 ff 00 00 00 00 00
+ * E: 000042.158009 9 11 00 e6 ff 00 00 00 00 00
+ * E: 000042.172108 9 11 00 be ff 00 00 00 00 00
+ * E: 000042.207417 9 11 00 e8 ff 00 00 00 00 00
+ * E: 000042.223155 9 11 00 cc ff 00 00 00 00 00
+ * E: 000042.255185 9 11 00 e6 ff 00 00 00 00 00
+ * E: 000042.276280 9 11 00 d7 ff 00 00 00 00 00
+ * E: 000042.302128 9 11 00 e0 ff 00 00 00 00 00
+ * E: 000042.317423 9 11 00 c8 ff 00 00 00 00 00
+ * E: 000042.345226 9 11 00 e1 ff 00 00 00 00 00
+ * E: 000042.357243 9 11 00 bc ff 00 00 00 00 00
+ * E: 000042.381308 9 11 00 dc ff 00 00 00 00 00
+ * E: 000042.383180 9 11 00 dc fe 00 00 00 00 00
+ * E: 000042.412288 9 11 00 e3 ff 00 00 00 00 00
+ * E: 000042.451216 9 11 00 eb ff 00 00 00 00 00
+ * E: 000042.478372 9 11 00 e0 ff 00 00 00 00 00
+ * E: 000042.502116 9 11 00 dd ff 00 00 00 00 00
+ * E: 000042.520105 9 11 00 d3 ff 00 00 00 00 00
+ * E: 000042.540345 9 11 00 d6 ff 00 00 00 00 00
+ * E: 000042.541021 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.542009 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.543045 9 11 00 00 04 00 00 00 00 00
+ * E: 000042.544279 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.545097 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.546074 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.547237 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.548029 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.549304 9 11 00 00 f8 00 00 00 00 00
+ * E: 000042.553123 9 11 00 00 ff 00 00 00 00 00
+ * E: 000042.581186 9 11 00 e1 ff 00 00 00 00 00
+ * E: 000042.582238 9 11 00 00 f8 00 00 00 00 00
+ * E: 000042.583150 9 11 00 00 fc 00 00 00 00 00
+ * E: 000042.584273 9 11 00 00 f8 00 00 00 00 00
+ * E: 000042.585019 9 11 00 00 fc 00 00 00 00 00
+ * E: 000042.586059 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.589012 9 11 00 67 fe 00 00 00 00 00
+ * E: 000042.590066 9 11 00 00 fc 00 00 00 00 00
+ * E: 000042.592916 9 11 00 dc fe 00 00 00 00 00
+ * E: 000042.621124 9 11 00 e1 ff 00 00 00 00 00
+ * E: 000042.622092 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.623069 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.624030 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.625006 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.626068 9 11 00 00 04 00 00 00 00 00
+ * E: 000042.626876 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.628392 9 11 00 00 08 00 00 00 00 00
+ * E: 000042.628918 9 11 00 01 00 00 00 00 00 00
+ * E: 000042.630009 9 11 00 ff ff 00 00 00 00 00
+ * E: 000042.631934 9 11 00 00 fe 00 00 00 00 00
+ * E: 000042.656285 9 11 00 dd ff 00 00 00 00 00
+ * E: 000042.659870 9 11 00 cc 00 00 00 00 00 00
+ * E: 000042.666128 9 11 00 9d 00 00 00 00 00 00
+ * E: 000042.672458 9 11 00 80 ff 00 00 00 00 00
+ * E: 000042.696106 9 11 00 dc ff 00 00 00 00 00
+ * E: 000042.705129 9 11 00 61 00 00 00 00 00 00
+ * E: 000042.731303 9 11 00 e0 ff 00 00 00 00 00
+ * E: 000042.741278 9 11 00 ab ff 00 00 00 00 00
+ * E: 000042.788181 9 11 00 ee ff 00 00 00 00 00
+ * E: 000042.810441 9 11 00 db ff 00 00 00 00 00
+ * E: 000042.838073 9 11 00 e1 ff 00 00 00 00 00
+ * E: 000042.852235 9 11 00 c4 ff 00 00 00 00 00
+ * E: 000042.882290 9 11 00 e4 ff 00 00 00 00 00
+ *
+ * Either wheel button, press, hold, then release
+ * E: 000202.084982 9 11 02 00 00 00 00 00 00 00
+ * E: 000202.090172 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.094139 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.099172 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.105055 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.109132 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.114185 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.119212 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.124264 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.130147 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.135138 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.140072 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.145146 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.150157 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.155339 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.160064 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.165026 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.170037 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.175154 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.180044 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.186280 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.191281 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.196106 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.201083 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.206166 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.211084 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.216175 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.221036 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.226271 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.231150 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.235924 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.242046 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.247164 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.252359 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.257295 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.262167 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.267081 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.272175 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.277085 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.282596 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.287078 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.292191 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.298196 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.303004 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.308113 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.313079 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.318243 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.323309 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.328190 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.333050 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.338162 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.343022 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.348113 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.354133 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.359132 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.364053 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.369034 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.374144 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.379027 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.384238 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.389249 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.394049 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.398949 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.404203 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.410098 9 11 03 00 00 00 00 00 00 00
+ * E: 000202.415237 9 11 00 00 00 00 00 00 00 00
+ *
+ *
+ * Top wheel button press and release while holding bottom wheel button
+ * (The reverse action (a bottom wheel button press while holding the top wheel button) is invisible.)
+ * E: 000071.126966 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.133117 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.137481 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.142036 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.147027 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.151988 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.157945 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.163657 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.168240 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.173109 9 11 02 00 00 00 00 00 00 00 < top wheel button press?
+ * E: 000071.178119 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.183046 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.187983 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.192996 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.198341 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.203122 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.208998 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.214037 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.218945 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.223835 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.228987 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.234082 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.239028 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.244307 9 11 00 00 00 00 00 00 00 00 < top wheel button release?
+ * E: 000071.245867 9 11 03 00 00 00 00 00 00 00 < continued hold of bottom button
+ * E: 000071.249959 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.255032 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.259972 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.265409 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.270156 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.275530 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.279975 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.285046 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.290906 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.296146 9 11 03 00 00 00 00 00 00 00
+ * E: 000071.301288 9 11 03 00 00 00 00 00 00 00
+ *
+ * Top wheel button hold while top wheel rotate CCW
+ * (I did not test the other combinations of this)
+ * E: 000022.253144 9 11 03 00 00 00 00 00 00 00
+ * E: 000022.258157 9 11 03 00 00 00 00 00 00 00
+ * E: 000022.262011 9 11 00 ff ff 00 00 00 00 00
+ * E: 000022.264015 9 11 03 00 00 00 00 00 00 00
+ * E: 000022.268976 9 11 03 00 00 00 00 00 00 00
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * NOTES ON SIMULTANEOUS BUTTON HOLDS
+ * (applies to vendor mode only)
+ * Value replacements for ease of reading:
+ * .7 = 0x40 (button 7, a wheel button)
+ * .1 = 0x01 (button 1, a pad button)
+ * rr = 0x00 (no buttons pressed)
+ *
+ * Press 7
+ * Press 1
+ * Release 7
+ * Release 1
+ * B: 000000.000152 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00
+ * B: 000000.781784 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000000.869845 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000001.095688 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000001.322635 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000001.543643 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000001.770652 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000001.885659 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 7
+ * B: 000001.993620 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000002.220671 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000002.446589 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000002.672559 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000002.765183 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1
+ *
+ * Press 7
+ * Press 1
+ * Release 1
+ * Release 7
+ * B: 000017.071517 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00
+ * B: 000018.270461 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000018.419486 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000018.646438 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000018.872493 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000019.094422 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000019.320488 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000020.360505 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 is not reported until 7 is released, then both are rapidly reported
+ * B: 000020.361091 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00
+ *
+ * Press 1
+ * Press 7
+ * Release 7
+ * Release 1
+ * B: 000031.516315 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000031.922299 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000032.144165 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000032.370262 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000032.396242 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00
+ * B: 000032.597270 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000032.818187 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000033.045143 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000033.267535 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 7
+ * B: 000033.272602 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000033.494246 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000033.721266 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000033.947237 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000034.169294 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000034.183585 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1
+ *
+ * Press 1
+ * Press 7
+ * Release 1
+ * Release 7
+ * B: 000056.628429 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000057.046348 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000057.272044 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000057.494434 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000057.601224 42 08 e0 01 01 .7 00 00 00 00 00 00 00 00 00
+ * B: 000057.719262 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000057.946941 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000058.172346 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000058.393994 42 08 e0 01 01 .1 00 00 00 00 00 00 00 00 00
+ * B: 000059.434576 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00 release of 1 is not reported until 7 is released, then both are rapidly reported
+ * B: 000059.435857 42 08 e0 01 01 rr 00 00 00 00 00 00 00 00 00
+ */
+
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+char EXPECTED_FIRMWARE_ID[] = "HUION_M22c_";
+
+__u8 last_button_state;
+
+static const __u8 disabled_rdesc_tablet[] = {
+ FixedSizeVendorReport(28) /* Input report 4 */
+};
+
+static const __u8 disabled_rdesc_wheel[] = {
+ FixedSizeVendorReport(9) /* Input report 17 */
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ ReportId(VENDOR_REPORT_ID)
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionPhysical(
+ /*
+ * I have only examined the tablet's behavior while using
+ * the PW600L pen, which does not have an eraser.
+ * Because of this, I don't know where the Eraser and Invert
+ * bits will go, or if they work as one would expect.
+ *
+ * For the time being, there is no expectation that a pen
+ * with an eraser will work without modifications here.
+ */
+ ReportSize(1)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportCount(3)
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch
+ Input(Var|Abs)
+ PushPop(
+ ReportCount(1)
+ UsagePage_Button
+ Usage_i8(0x4a) /* (BTN_STYLUS3 + 1) & 0xff */
+ Input(Var|Abs)
+ )
+ ReportCount(3)
+ Input(Const)
+ ReportCount(1)
+ Usage_Dig_InRange
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-2)
+ LogicalMinimum_i16(0)
+ PhysicalMinimum_i16(0)
+ /*
+ * The tablet has a logical maximum of 58760 x 33040
+ * and a claimed resolution of 5080 LPI (200 L/mm)
+ * This works out to a physical maximum of
+ * 293.8 x 165.2mm, which matches Huion's advertised
+ * active area dimensions from
+ * https://www.huion.com/products/pen_display/Kamvas/kamvas-13-gen-3.html
+ */
+ LogicalMaximum_i16(58760)
+ PhysicalMaximum_i16(2938)
+ Usage_GD_X
+ Input(Var|Abs)
+ LogicalMaximum_i16(33040)
+ PhysicalMaximum_i16(1652)
+ Usage_GD_Y
+ Input(Var|Abs)
+ )
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(16383)
+ Usage_Dig_TipPressure
+ Input(Var|Abs)
+ ReportCount(1)
+ Input(Const)
+ ReportSize(8)
+ ReportCount(2)
+ PushPop(
+ Unit(deg)
+ UnitExponent(0)
+ LogicalMinimum_i8(-60)
+ PhysicalMinimum_i8(-60)
+ LogicalMaximum_i8(60)
+ PhysicalMaximum_i8(60)
+ Usage_Dig_XTilt
+ Usage_Dig_YTilt
+ Input(Var|Abs)
+ )
+ )
+ )
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ ReportId(CUSTOM_PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ /*
+ * The first 3 bytes are somewhat vestigial and will
+ * always be set to zero. Their presence here is needed
+ * to ensure that this device will be detected as a
+ * tablet pad by software that otherwise wouldn't know
+ * any better.
+ */
+ /* (data[1] & 0x01) barrel switch */
+ ReportSize(1)
+ ReportCount(1)
+ Usage_Dig_BarrelSwitch
+ Input(Var|Abs)
+ ReportCount(7)
+ Input(Const)
+ /* data[2] X */
+ /* data[3] Y */
+ ReportSize(8)
+ ReportCount(2)
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ Input(Var|Abs)
+ /*
+ * (data[4] & 0x01) button 1
+ * (data[4] & 0x02) button 2
+ * (data[4] & 0x04) button 3
+ * (data[4] & 0x08) button 4
+ * (data[4] & 0x10) button 5
+ * (data[4] & 0x20) button 6 (top wheel button)
+ * (data[4] & 0x40) button 7 (bottom wheel button)
+ */
+ ReportSize(1)
+ ReportCount(7)
+ UsagePage_Button
+ UsageMinimum_i8(1)
+ UsageMaximum_i8(7)
+ Input(Var|Abs)
+ ReportCount(1)
+ Input(Const)
+ /* data[5] top wheel (signed, positive clockwise) */
+ ReportSize(8)
+ ReportCount(1)
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ Input(Var|Rel)
+ /* data[6] bottom wheel (signed, positive clockwise) */
+ UsagePage_Consumer
+ Usage_Con_ACPan
+ Input(Var|Rel)
+ )
+ /*
+ * The kernel will drop reports that are bigger than the
+ * largest report specified in the HID descriptor.
+ * Therefore, our modified descriptor needs to have at least one
+ * HID report that is as long as, or longer than, the largest
+ * report in the original descriptor.
+ *
+ * This macro expands to a no-op report that is padded to the
+ * provided length.
+ */
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_huion_kamvas13_gen3, struct hid_bpf_ctx *hid_ctx)
+{
+ __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+ __s32 rdesc_size = hid_ctx->size;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+
+ if (have_fw_id) {
+ /*
+ * Tablet should be in vendor mode.
+ * Disable the unused devices
+ */
+ if (rdesc_size == TABLET_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, disabled_rdesc_tablet,
+ sizeof(disabled_rdesc_tablet));
+ return sizeof(disabled_rdesc_tablet);
+ }
+
+ if (rdesc_size == WHEEL_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, disabled_rdesc_wheel,
+ sizeof(disabled_rdesc_wheel));
+ return sizeof(disabled_rdesc_wheel);
+ }
+ }
+
+ /*
+ * Regardless of which mode the tablet is in, always fix the vendor
+ * descriptor in case the udev property just happened to not be set
+ */
+ if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(hid_fix_event_huion_kamvas13_gen3, struct hid_bpf_ctx *hid_ctx)
+{
+ __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, VENDOR_REPORT_LENGTH /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Handle vendor reports only */
+ if (hid_ctx->size != VENDOR_REPORT_LENGTH)
+ return 0;
+ if (data[0] != VENDOR_REPORT_ID)
+ return 0;
+
+ __u8 report_subtype = (data[1] >> 4) & 0x0f;
+
+ if (report_subtype == VENDOR_REPORT_SUBTYPE_PEN ||
+ report_subtype == VENDOR_REPORT_SUBTYPE_PEN_OUT) {
+ /* Invert Y tilt */
+ data[11] = -data[11];
+
+ } else if (report_subtype == VENDOR_REPORT_SUBTYPE_BUTTONS ||
+ report_subtype == VENDOR_REPORT_SUBTYPE_WHEELS) {
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus:1;
+ __u8 padding:7;
+ __u8 x;
+ __u8 y;
+ __u8 buttons;
+ __s8 top_wheel;
+ __s8 bottom_wheel;
+ } __attribute__((packed)) *pad_report;
+
+ __s8 top_wheel = 0;
+ __s8 bottom_wheel = 0;
+
+ switch (report_subtype) {
+ case VENDOR_REPORT_SUBTYPE_WHEELS:
+ /*
+ * The wheel direction byte is 1 for clockwise rotation
+ * and 2 for counter-clockwise.
+ * Change it to 1 and -1, respectively.
+ */
+ switch (data[3]) {
+ case 1:
+ top_wheel = (data[5] == 1) ? 1 : -1;
+ break;
+ case 2:
+ bottom_wheel = (data[5] == 1) ? 1 : -1;
+ break;
+ }
+ break;
+
+ case VENDOR_REPORT_SUBTYPE_BUTTONS:
+ /*
+ * If a button is already being held, ignore any new
+ * button event unless it's a release.
+ *
+ * The tablet only cleanly handles one button being held
+ * at a time, and trying to hold multiple buttons
+ * (particularly wheel+pad buttons) can result in sequences
+ * of reports that look like imaginary presses and releases.
+ *
+ * This is an imperfect way to filter out some of these
+ * reports.
+ */
+ if (last_button_state != 0x00 && data[4] != 0x00)
+ break;
+
+ last_button_state = data[4];
+ break;
+ }
+
+
+ pad_report = (struct pad_report *)data;
+
+ pad_report->report_id = CUSTOM_PAD_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->top_wheel = top_wheel;
+ pad_report->bottom_wheel = bottom_wheel;
+
+ return sizeof(struct pad_report);
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(huion_kamvas13_gen3) = {
+ .hid_device_event = (void *)hid_fix_event_huion_kamvas13_gen3,
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas13_gen3,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case VENDOR_DESCRIPTOR_LENGTH:
+ case TABLET_DESCRIPTOR_LENGTH:
+ case WHEEL_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c b/drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c
new file mode 100644
index 000000000..ac66c6e65
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__Kamvas16Gen3.bpf.c
@@ -0,0 +1,724 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Nicholas LaPointe
+ * Copyright (c) 2025 Higgins Dragon
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include "hid_report_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_HUION 0x256c
+#define PID_KAMVAS16_GEN3 0x2009
+
+#define VENDOR_DESCRIPTOR_LENGTH 36
+#define TABLET_DESCRIPTOR_LENGTH 328
+#define WHEEL_DESCRIPTOR_LENGTH 200
+
+#define VENDOR_REPORT_ID 8
+#define VENDOR_REPORT_LENGTH 14
+
+#define VENDOR_REPORT_SUBTYPE_PEN 0x08
+#define VENDOR_REPORT_SUBTYPE_PEN_OUT 0x00
+#define VENDOR_REPORT_SUBTYPE_BUTTONS 0x0e
+#define VENDOR_REPORT_SUBTYPE_WHEELS 0x0f
+
+/* For the reports that we create ourselves */
+#define CUSTOM_PAD_REPORT_ID 9
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_HUION, PID_KAMVAS16_GEN3),
+);
+
+/*
+ * This tablet can send reports using one of two different data formats,
+ * depending on what "mode" the tablet is in.
+ *
+ * By default, the tablet will send reports that can be decoded using its
+ * included HID descriptors (descriptors 1 and 2, shown below).
+ * This mode will be called "firmware mode" throughout this file.
+ *
+ * The HID descriptor that describes pen events in firmware mode (descriptor 1)
+ * has multiple bugs:
+ * * "Secondary Tip Switch" instead of "Secondary Barrel Switch"
+ * * "Invert" instead of (or potentially shared with) third barrel button
+ * * Specified tablet area of 2048 in³ instead of 293.8 x 165.2mm
+ * * Specified tilt range of -90 to +90 instead of -60 to +60
+ *
+ * While these can be easily patched up by editing the descriptor, a larger
+ * problem with the firmware mode exists: it is impossible to tell which of the
+ * two wheels are being rotated (or having their central button pressed).
+ *
+ *
+ * By using a tool such as huion-switcher (https://github.com/whot/huion-switcher),
+ * the tablet can be made to send reports using a proprietary format that is not
+ * adequately described by its relevant descriptor (descriptor 0, shown below).
+ * This mode will be called "vendor mode" throughout this file.
+ *
+ * The reports sent while in vendor mode allow for proper decoding of the wheels.
+ *
+ * For simplicity and maximum functionality, this BPF focuses strictly on
+ * enabling one to make use of the vendor mode.
+ */
+
+/*
+ * DESCRIPTORS
+ * DESCRIPTOR 0
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x68, // Report Size (104) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 13
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 18
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 21
+ * # 0xa1, 0x01, // Collection (Application) 23
+ * # 0x85, 0x16, // Report ID (22) 25
+ * # 0x75, 0x08, // Report Size (8) 27
+ * # 0x95, 0x07, // Report Count (7) 29
+ * # 0x09, 0x01, // Usage (Vendor Usage 1) 31
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 33
+ * # 0xc0, // End Collection 35
+ * #
+ * R: 36 06 00 ff 09 01 a1 01 85 08 75 68 95 01 09 01 81 02 c0 06 00 ff 09 01 a1 01 85 16 75 08 95 07 09 01 b1 02 c0
+ * N: HUION Huion Tablet_GS1563
+ * I: 3 256c 2009
+ *
+ *
+ * DESCRIPTOR 1
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x0a, // Report ID (10) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x01, // Collection (Application) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x43, // Usage (Secondary Tip Switch) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18
+ * # 0x09, 0x45, // Usage (Eraser) 20
+ * # 0x15, 0x00, // Logical Minimum (0) 22
+ * # 0x25, 0x01, // Logical Maximum (1) 24
+ * # 0x75, 0x01, // Report Size (1) 26
+ * # 0x95, 0x06, // Report Count (6) 28
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 30
+ * # 0x09, 0x32, // Usage (In Range) 32
+ * # 0x75, 0x01, // Report Size (1) 34
+ * # 0x95, 0x01, // Report Count (1) 36
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 38
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x30, // Usage (X) 44
+ * # 0x09, 0x31, // Usage (Y) 46
+ * # 0x55, 0x0d, // Unit Exponent (-3) 48
+ * # 0x65, 0x33, // Unit (EnglishLinear: in³) 50
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 52
+ * # 0x35, 0x00, // Physical Minimum (0) 55
+ * # 0x46, 0x00, 0x08, // Physical Maximum (2048) 57
+ * # 0x75, 0x10, // Report Size (16) 60
+ * # 0x95, 0x02, // Report Count (2) 62
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 64
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 66
+ * # 0x09, 0x30, // Usage (Tip Pressure) 68
+ * # 0x26, 0xff, 0x3f, // Logical Maximum (16383) 70
+ * # 0x75, 0x10, // Report Size (16) 73
+ * # 0x95, 0x01, // Report Count (1) 75
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 77
+ * # 0x09, 0x3d, // Usage (X Tilt) 79
+ * # 0x09, 0x3e, // Usage (Y Tilt) 81
+ * # 0x15, 0xa6, // Logical Minimum (-90) 83
+ * # 0x25, 0x5a, // Logical Maximum (90) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x02, // Report Count (2) 89
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 91
+ * # 0xc0, // End Collection 93
+ * # 0xc0, // End Collection 94
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 95
+ * # 0x09, 0x04, // Usage (Touch Screen) 97
+ * # 0xa1, 0x01, // Collection (Application) 99
+ * # 0x85, 0x04, // Report ID (4) 101
+ * # 0x09, 0x22, // Usage (Finger) 103
+ * # 0xa1, 0x02, // Collection (Logical) 105
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 107
+ * # 0x95, 0x01, // Report Count (1) 109
+ * # 0x75, 0x06, // Report Size (6) 111
+ * # 0x09, 0x51, // Usage (Contact Id) 113
+ * # 0x15, 0x00, // Logical Minimum (0) 115
+ * # 0x25, 0x3f, // Logical Maximum (63) 117
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 119
+ * # 0x09, 0x42, // Usage (Tip Switch) 121
+ * # 0x25, 0x01, // Logical Maximum (1) 123
+ * # 0x75, 0x01, // Report Size (1) 125
+ * # 0x95, 0x01, // Report Count (1) 127
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 129
+ * # 0x75, 0x01, // Report Size (1) 131
+ * # 0x95, 0x01, // Report Count (1) 133
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 135
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 137
+ * # 0x75, 0x10, // Report Size (16) 139
+ * # 0x55, 0x0e, // Unit Exponent (-2) 141
+ * # 0x65, 0x11, // Unit (SILinear: cm) 143
+ * # 0x09, 0x30, // Usage (X) 145
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 147
+ * # 0x35, 0x00, // Physical Minimum (0) 150
+ * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 152
+ * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 155
+ * # 0x09, 0x31, // Usage (Y) 157
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 159
+ * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 162
+ * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 165
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 167
+ * # 0x09, 0x30, // Usage (Tip Pressure) 169
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 171
+ * # 0x75, 0x10, // Report Size (16) 174
+ * # 0x95, 0x01, // Report Count (1) 176
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 178
+ * # 0xc0, // End Collection 180
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 181
+ * # 0x09, 0x22, // Usage (Finger) 183
+ * # 0xa1, 0x02, // Collection (Logical) 185
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 187
+ * # 0x95, 0x01, // Report Count (1) 189
+ * # 0x75, 0x06, // Report Size (6) 191
+ * # 0x09, 0x51, // Usage (Contact Id) 193
+ * # 0x15, 0x00, // Logical Minimum (0) 195
+ * # 0x25, 0x3f, // Logical Maximum (63) 197
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 199
+ * # 0x09, 0x42, // Usage (Tip Switch) 201
+ * # 0x25, 0x01, // Logical Maximum (1) 203
+ * # 0x75, 0x01, // Report Size (1) 205
+ * # 0x95, 0x01, // Report Count (1) 207
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 209
+ * # 0x75, 0x01, // Report Size (1) 211
+ * # 0x95, 0x01, // Report Count (1) 213
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 215
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 217
+ * # 0x75, 0x10, // Report Size (16) 219
+ * # 0x55, 0x0e, // Unit Exponent (-2) 221
+ * # 0x65, 0x11, // Unit (SILinear: cm) 223
+ * # 0x09, 0x30, // Usage (X) 225
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 227
+ * # 0x35, 0x00, // Physical Minimum (0) 230
+ * # 0x46, 0x15, 0x0c, // Physical Maximum (3093) 232
+ * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 235
+ * # 0x09, 0x31, // Usage (Y) 237
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 239
+ * # 0x46, 0xcb, 0x06, // Physical Maximum (1739) 242
+ * # 0x81, 0x42, // Input (Data,Var,Abs,Null) 245
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 247
+ * # 0x09, 0x30, // Usage (Tip Pressure) 249
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 251
+ * # 0x75, 0x10, // Report Size (16) 254
+ * # 0x95, 0x01, // Report Count (1) 256
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 258
+ * # 0xc0, // End Collection 260
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 261
+ * # 0x09, 0x56, // Usage (Scan Time) 263
+ * # 0x55, 0x00, // Unit Exponent (0) 265
+ * # 0x65, 0x00, // Unit (None) 267
+ * # 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 269
+ * # 0x95, 0x01, // Report Count (1) 274
+ * # 0x75, 0x20, // Report Size (32) 276
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 278
+ * # 0x09, 0x54, // Usage (Contact Count) 280
+ * # 0x25, 0x7f, // Logical Maximum (127) 282
+ * # 0x95, 0x01, // Report Count (1) 284
+ * # 0x75, 0x08, // Report Size (8) 286
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 288
+ * # 0x75, 0x08, // Report Size (8) 290
+ * # 0x95, 0x08, // Report Count (8) 292
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 294
+ * # 0x85, 0x05, // Report ID (5) 296
+ * # 0x09, 0x55, // Usage (Contact Max) 298
+ * # 0x25, 0x0a, // Logical Maximum (10) 300
+ * # 0x75, 0x08, // Report Size (8) 302
+ * # 0x95, 0x01, // Report Count (1) 304
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 306
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 308
+ * # 0x09, 0xc5, // Usage (Vendor Usage 0xc5) 311
+ * # 0x85, 0x06, // Report ID (6) 313
+ * # 0x15, 0x00, // Logical Minimum (0) 315
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 317
+ * # 0x75, 0x08, // Report Size (8) 320
+ * # 0x96, 0x00, 0x01, // Report Count (256) 322
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 325
+ * # 0xc0, // End Collection 327
+ * #
+ * R: 328 05 0d 09 02 a1 01 85 0a 09 20 a1 01 09 42 09 44 09 43 09 3c 09 45 15 00 25 01 75 01 95 06 81 02 09 32 75 01 95 01 81 02 81 03 05 01 09 30 09 31 55 0d 65 33 26 ff 7f 35 00 46 00 08 75 10 95 02 81 02 05 0d 09 30 26 ff 3f 75 10 95 01 81 02 09 3d 09 3e 15 a6 25 5a 75 08 95 02 81 02 c0 c0 05 0d 09 04 a1 01 85 04 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 22 a1 02 05 0d 95 01 75 06 09 51 15 00 25 3f 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0e 65 11 09 30 26 ff 7f 35 00 46 15 0c 81 42 09 31 26 ff 7f 46 cb 06 81 42 05 0d 09 30 26 ff 1f 75 10 95 01 81 02 c0 05 0d 09 56 55 00 65 00 27 ff ff ff 7f 95 01 75 20 81 02 09 54 25 7f 95 01 75 08 81 02 75 08 95 08 81 03 85 05 09 55 25 0a 75 08 95 01 b1 02 06 00 ff 09 c5 85 06 15 00 26 ff 00 75 08 96 00 01 b1 02 c0
+ * N: HUION Huion Tablet_GS1563
+ * I: 3 256c 2009
+ *
+ * DESCRIPTOR 2
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x11, // Report ID (17) 6
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 8
+ * # 0x09, 0x21, // Usage (Puck) 10
+ * # 0xa1, 0x02, // Collection (Logical) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x01, // Report Count (1) 20
+ * # 0xa1, 0x00, // Collection (Physical) 22
+ * # 0x05, 0x09, // Usage Page (Button) 24
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 30
+ * # 0x09, 0x33, // Usage (Touch) 32
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 34
+ * # 0x95, 0x06, // Report Count (6) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0xa1, 0x02, // Collection (Logical) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x37, // Usage (Dial) 44
+ * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49
+ * # 0x75, 0x10, // Report Size (16) 52
+ * # 0x95, 0x01, // Report Count (1) 54
+ * # 0x81, 0x06, // Input (Data,Var,Rel) 56
+ * # 0x35, 0x00, // Physical Minimum (0) 58
+ * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60
+ * # 0x15, 0x00, // Logical Minimum (0) 63
+ * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65
+ * # 0x09, 0x48, // Usage (Resolution Multiplier) 68
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 70
+ * # 0x45, 0x00, // Physical Maximum (0) 72
+ * # 0xc0, // End Collection 74
+ * # 0x75, 0x08, // Report Size (8) 75
+ * # 0x95, 0x01, // Report Count (1) 77
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 79
+ * # 0x75, 0x08, // Report Size (8) 81
+ * # 0x95, 0x01, // Report Count (1) 83
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x01, // Report Count (1) 89
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 91
+ * # 0x75, 0x08, // Report Size (8) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97
+ * # 0x75, 0x08, // Report Size (8) 99
+ * # 0x95, 0x01, // Report Count (1) 101
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 103
+ * # 0xc0, // End Collection 105
+ * # 0xc0, // End Collection 106
+ * # 0xc0, // End Collection 107
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 108
+ * # 0x09, 0x06, // Usage (Keyboard) 110
+ * # 0xa1, 0x01, // Collection (Application) 112
+ * # 0x85, 0x03, // Report ID (3) 114
+ * # 0x05, 0x07, // Usage Page (Keyboard) 116
+ * # 0x19, 0xe0, // Usage Minimum (224) 118
+ * # 0x29, 0xe7, // Usage Maximum (231) 120
+ * # 0x15, 0x00, // Logical Minimum (0) 122
+ * # 0x25, 0x01, // Logical Maximum (1) 124
+ * # 0x75, 0x01, // Report Size (1) 126
+ * # 0x95, 0x08, // Report Count (8) 128
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 130
+ * # 0x05, 0x07, // Usage Page (Keyboard) 132
+ * # 0x19, 0x00, // Usage Minimum (0) 134
+ * # 0x29, 0xff, // Usage Maximum (255) 136
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 138
+ * # 0x75, 0x08, // Report Size (8) 141
+ * # 0x95, 0x06, // Report Count (6) 143
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 145
+ * # 0xc0, // End Collection 147
+ * # 0x05, 0x0c, // Usage Page (Consumer Devices) 148
+ * # 0x09, 0x01, // Usage (Consumer Control) 150
+ * # 0xa1, 0x01, // Collection (Application) 152
+ * # 0x85, 0x04, // Report ID (4) 154
+ * # 0x19, 0x01, // Usage Minimum (1) 156
+ * # 0x2a, 0x9c, 0x02, // Usage Maximum (668) 158
+ * # 0x15, 0x01, // Logical Minimum (1) 161
+ * # 0x26, 0x9c, 0x02, // Logical Maximum (668) 163
+ * # 0x95, 0x01, // Report Count (1) 166
+ * # 0x75, 0x10, // Report Size (16) 168
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 170
+ * # 0xc0, // End Collection 172
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 173
+ * # 0x09, 0x80, // Usage (System Control) 175
+ * # 0xa1, 0x01, // Collection (Application) 177
+ * # 0x85, 0x05, // Report ID (5) 179
+ * # 0x19, 0x81, // Usage Minimum (129) 181
+ * # 0x29, 0x83, // Usage Maximum (131) 183
+ * # 0x15, 0x00, // Logical Minimum (0) 185
+ * # 0x25, 0x01, // Logical Maximum (1) 187
+ * # 0x75, 0x01, // Report Size (1) 189
+ * # 0x95, 0x03, // Report Count (3) 191
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 193
+ * # 0x95, 0x05, // Report Count (5) 195
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 197
+ * # 0xc0, // End Collection 199
+ * #
+ * R: 200 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 19 01 2a 9c 02 15 01 26 9c 02 95 01 75 10 81 00 c0 05 01 09 80 a1 01 85 05 19 81 29 83 15 00 25 01 75 01 95 03 81 02 95 05 81 01 c0
+ * N: HUION Huion Tablet_GS1563
+ * I: 3 256c 2009
+ *
+ *
+ *
+ * VENDOR MODE
+ * HUION_FIRMWARE_ID="HUION_M22d_241101"
+ * HUION_MAGIC_BYTES="1403201101ac9900ff3fd81305080080083c4010"
+ *
+ * MAGIC BYTES
+ * [LogicalMaximum, X ] [LogicalMaximum, Y ] [LogicalMaximum, Pressure] [ LPI]
+ * 14 03 [ 20 11 01] [ ac 99 00] [ ff 3f] [d8 13] 05 08 00 80 08 3c 40 10
+ *
+ * See Huion__Kamvas13Gen3.bpf.c for more details on detailed button/dial reports and caveats. It's very
+ * similar to the Kamvas 16 Gen 3.
+ */
+
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+char EXPECTED_FIRMWARE_ID[] = "HUION_M22d_";
+
+__u8 last_button_state;
+
+static const __u8 disabled_rdesc_tablet[] = {
+ FixedSizeVendorReport(28) /* Input report 4 */
+};
+
+static const __u8 disabled_rdesc_wheel[] = {
+ FixedSizeVendorReport(9) /* Input report 17 */
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ ReportId(VENDOR_REPORT_ID)
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionPhysical(
+ /*
+ * I have only examined the tablet's behavior while using
+ * the PW600L pen, which does not have an eraser.
+ * Because of this, I don't know where the Eraser and Invert
+ * bits will go, or if they work as one would expect.
+ *
+ * For the time being, there is no expectation that a pen
+ * with an eraser will work without modifications here.
+ */
+ ReportSize(1)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportCount(3)
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_SecondaryBarrelSwitch
+ Input(Var|Abs)
+ PushPop(
+ ReportCount(1)
+ UsagePage_Button
+ Usage_i8(0x4a) /* (BTN_STYLUS3 + 1) & 0xff */
+ Input(Var|Abs)
+ )
+ ReportCount(3)
+ Input(Const)
+ ReportCount(1)
+ Usage_Dig_InRange
+ Input(Var|Abs)
+ ReportSize(16)
+ ReportCount(1)
+ PushPop(
+ UsagePage_GenericDesktop
+ Unit(cm)
+ UnitExponent(-2)
+ LogicalMinimum_i16(0)
+ PhysicalMinimum_i16(0)
+ /*
+ * The tablet has a logical maximum of 69920 x 39340
+ * and a claimed resolution of 5080 LPI (200 L/mm)
+ * This works out to a physical maximum of
+ * 349.6 x 196.7mm, which matches Huion's advertised
+ * (rounded) active area dimensions from
+ * https://www.huion.com/products/pen_display/Kamvas/kamvas-16-gen-3.html
+ *
+ * The Kamvas uses data[8] for the 3rd byte of the X-axis, and adding
+ * that after data[2] and data[3] makes a contiguous little-endian
+ * 24-bit value. (See BPF_PROG below)
+ */
+ ReportSize(24)
+ LogicalMaximum_i32(69920)
+ PhysicalMaximum_i16(3496)
+ Usage_GD_X
+ Input(Var|Abs)
+ ReportSize(16)
+ LogicalMaximum_i16(39340)
+ PhysicalMaximum_i16(1967)
+ Usage_GD_Y
+ Input(Var|Abs)
+ )
+ ReportSize(16)
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(16383)
+ Usage_Dig_TipPressure
+ Input(Var|Abs)
+ ReportSize(8)
+ ReportCount(1)
+ Input(Const)
+ ReportCount(2)
+ PushPop(
+ Unit(deg)
+ UnitExponent(0)
+ LogicalMinimum_i8(-60)
+ PhysicalMinimum_i8(-60)
+ LogicalMaximum_i8(60)
+ PhysicalMaximum_i8(60)
+ Usage_Dig_XTilt
+ Usage_Dig_YTilt
+ Input(Var|Abs)
+ )
+ )
+ )
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ ReportId(CUSTOM_PAD_REPORT_ID)
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ /*
+ * The first 3 bytes are somewhat vestigial and will
+ * always be set to zero. Their presence here is needed
+ * to ensure that this device will be detected as a
+ * tablet pad by software that otherwise wouldn't know
+ * any better.
+ */
+ /* (data[1] & 0x01) barrel switch */
+ ReportSize(1)
+ ReportCount(1)
+ Usage_Dig_BarrelSwitch
+ Input(Var|Abs)
+ ReportCount(7)
+ Input(Const)
+ /* data[2] X */
+ /* data[3] Y */
+ ReportSize(8)
+ ReportCount(2)
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ Input(Var|Abs)
+ /*
+ * (data[4] & 0x01) button 1
+ * (data[4] & 0x02) button 2
+ * (data[4] & 0x04) button 3
+ * (data[4] & 0x08) button 4
+ * (data[4] & 0x10) button 5
+ * (data[4] & 0x20) button 6
+ * (data[4] & 0x40) button 7 (top wheel button)
+ * (data[4] & 0x80) button 8 (bottom wheel button)
+ */
+ ReportSize(1)
+ ReportCount(8)
+ UsagePage_Button
+ UsageMinimum_i8(1)
+ UsageMaximum_i8(8)
+ Input(Var|Abs)
+ /* data[5] top wheel (signed, positive clockwise) */
+ ReportSize(8)
+ ReportCount(1)
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ Input(Var|Rel)
+ /* data[6] bottom wheel (signed, positive clockwise) */
+ UsagePage_Consumer
+ Usage_Con_ACPan
+ Input(Var|Rel)
+ )
+ /*
+ * The kernel will drop reports that are bigger than the
+ * largest report specified in the HID descriptor.
+ * Therefore, our modified descriptor needs to have at least one
+ * HID report that is as long as, or longer than, the largest
+ * report in the original descriptor.
+ *
+ * This macro expands to a no-op report that is padded to the
+ * provided length.
+ */
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx)
+{
+ __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+ __s32 rdesc_size = hid_ctx->size;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+
+ if (have_fw_id) {
+ /*
+ * Tablet should be in vendor mode.
+ * Disable the unused devices
+ */
+ if (rdesc_size == TABLET_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, disabled_rdesc_tablet,
+ sizeof(disabled_rdesc_tablet));
+ return sizeof(disabled_rdesc_tablet);
+ }
+
+ if (rdesc_size == WHEEL_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, disabled_rdesc_wheel,
+ sizeof(disabled_rdesc_wheel));
+ return sizeof(disabled_rdesc_wheel);
+ }
+ }
+
+ /*
+ * Regardless of which mode the tablet is in, always fix the vendor
+ * descriptor in case the udev property just happened to not be set
+ */
+ if (rdesc_size == VENDOR_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(hid_fix_event_huion_kamvas16_gen3, struct hid_bpf_ctx *hid_ctx)
+{
+ __u8 *data = hid_bpf_get_data(hid_ctx, 0 /* offset */, VENDOR_REPORT_LENGTH /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Handle vendor reports only */
+ if (hid_ctx->size != VENDOR_REPORT_LENGTH)
+ return 0;
+ if (data[0] != VENDOR_REPORT_ID)
+ return 0;
+
+ __u8 report_subtype = (data[1] >> 4) & 0x0f;
+
+ if (report_subtype == VENDOR_REPORT_SUBTYPE_PEN ||
+ report_subtype == VENDOR_REPORT_SUBTYPE_PEN_OUT) {
+ /* Invert Y tilt */
+ data[11] = -data[11];
+
+ /*
+ * Rearrange the bytes of the report so that
+ * [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
+ * will be arranged as
+ * [0, 1, 2, 3, 8, 4, 5, 6, 7, 9, 10, 11, 12, 13]
+ */
+ __u8 x_24 = data[8];
+
+ data[8] = data[7];
+ data[7] = data[6];
+ data[6] = data[5];
+ data[5] = data[4];
+
+ data[4] = x_24;
+
+ } else if (report_subtype == VENDOR_REPORT_SUBTYPE_BUTTONS ||
+ report_subtype == VENDOR_REPORT_SUBTYPE_WHEELS) {
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus:1;
+ __u8 padding:7;
+ __u8 x;
+ __u8 y;
+ __u8 buttons;
+ __s8 top_wheel;
+ __s8 bottom_wheel;
+ } __attribute__((packed)) *pad_report;
+
+ __s8 top_wheel = 0;
+ __s8 bottom_wheel = 0;
+
+ switch (report_subtype) {
+ case VENDOR_REPORT_SUBTYPE_WHEELS:
+ /*
+ * The wheel direction byte is 1 for clockwise rotation
+ * and 2 for counter-clockwise.
+ * Change it to 1 and -1, respectively.
+ */
+ switch (data[3]) {
+ case 1:
+ top_wheel = (data[5] == 1) ? 1 : -1;
+ break;
+ case 2:
+ bottom_wheel = (data[5] == 1) ? 1 : -1;
+ break;
+ }
+ break;
+
+ case VENDOR_REPORT_SUBTYPE_BUTTONS:
+ /*
+ * If a button is already being held, ignore any new
+ * button event unless it's a release.
+ *
+ * The tablet only cleanly handles one button being held
+ * at a time, and trying to hold multiple buttons
+ * (particularly wheel+pad buttons) can result in sequences
+ * of reports that look like imaginary presses and releases.
+ *
+ * This is an imperfect way to filter out some of these
+ * reports.
+ */
+ if (last_button_state != 0x00 && data[4] != 0x00)
+ break;
+
+ last_button_state = data[4];
+ break;
+ }
+
+ pad_report = (struct pad_report *)data;
+
+ pad_report->report_id = CUSTOM_PAD_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->top_wheel = top_wheel;
+ pad_report->bottom_wheel = bottom_wheel;
+
+ return sizeof(struct pad_report);
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(huion_kamvas16_gen3) = {
+ .hid_device_event = (void *)hid_fix_event_huion_kamvas16_gen3,
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_huion_kamvas16_gen3,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case VENDOR_DESCRIPTOR_LENGTH:
+ case TABLET_DESCRIPTOR_LENGTH:
+ case WHEEL_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__KeydialK20-Bluetooth.bpf.c b/drivers/hid/bpf/progs/Huion__KeydialK20-Bluetooth.bpf.c
new file mode 100644
index 000000000..d0769e990
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__KeydialK20-Bluetooth.bpf.c
@@ -0,0 +1,492 @@
+// 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 VID_HUION 0x256C
+#define PID_KEYDIAL_K20_BLUETOOTH 0x8251
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_HUION, PID_KEYDIAL_K20_BLUETOOTH),
+);
+
+/* This is the same device as in 0010-Huion__KeydialK20 but connected via Bluetooth.
+ * It does not need (to support?) switching to a vendor mode so we just modify the
+ * existing mode.
+ *
+ * By default it exports two hidraw nodes, only the second one sends events.
+ *
+ * This is the first hidraw node which we disable:
+ *
+ * # Keydial mini-050
+ * # Report descriptor length: 114 bytes
+ * # Bytes // Field Name Offset
+ * # ----------------------------------------------------------------------------------
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 🭬 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # ┅ 0x85, 0x03, // Report ID (3) 6
+ * # 🮥 0x05, 0x0d, // Usage Page (Digitizers) 8
+ * # 0x75, 0x08, // Report Size (8) 10
+ * # 0x95, 0x01, // Report Count (1) 12
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 14
+ * # 🭬 0x09, 0x21, // Usage (Puck) 16
+ * # 0xa1, 0x02, // Collection (Logical) 18
+ * # 0x15, 0x00, // Logical Minimum (0) 20
+ * # 0x25, 0x01, // Logical Maximum (1) 22
+ * # 0x75, 0x01, // Report Size (1) 24
+ * # 0x95, 0x01, // Report Count (1) 26
+ * # 0xa1, 0x00, // Collection (Physical) 28
+ * # 🮥 0x05, 0x09, // Usage Page (Button) 30
+ * # 🭬 0x09, 0x01, // Usage (Button 1) 32
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 34
+ * # 🮥 0x05, 0x0d, // Usage Page (Digitizers) 36
+ * # 🭬 0x09, 0x33, // Usage (Touch) 38
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 40
+ * # 0x95, 0x06, // Report Count (6) 42
+ * # ┇ 0x81, 0x03, // Input (Cnst,Var,Abs) 44
+ * # 0xa1, 0x02, // Collection (Logical) 46
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 48
+ * # 🭬 0x09, 0x37, // Usage (Dial) 50
+ * # 0x16, 0x00, 0x80, // Logical Minimum (32768) 52
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 55
+ * # 0x75, 0x10, // Report Size (16) 58
+ * # 0x95, 0x01, // Report Count (1) 60
+ * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 62
+ * # 0x35, 0x00, // Physical Minimum (0) 64
+ * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 66
+ * # 0x15, 0x00, // Logical Minimum (0) 69
+ * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 71
+ * # 🭬 0x09, 0x48, // Usage (Resolution Multiplier) 74
+ * # ║ 0xb1, 0x02, // Feature (Data,Var,Abs) 76
+ * # 0x45, 0x00, // Physical Maximum (0) 78
+ * # 0xc0, // End Collection 80
+ * # 0x75, 0x08, // Report Size (8) 81
+ * # 0x95, 0x01, // Report Count (1) 83
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x01, // Report Count (1) 89
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 91
+ * # 0x75, 0x08, // Report Size (8) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 97
+ * # 0x75, 0x08, // Report Size (8) 99
+ * # 0x95, 0x01, // Report Count (1) 101
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 103
+ * # 0x75, 0x08, // Report Size (8) 105
+ * # 0x95, 0x01, // Report Count (1) 107
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 109
+ * # 0xc0, // End Collection 111
+ * # 0xc0, // End Collection 112
+ * # 0xc0, // End Collection 113
+ * R: 114 05 01 09 0e a1 01 85 03 05 0d 75 08 95 01 81 01 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0
+ * N: Keydial mini-050
+ * I: 5 256c 8251
+ *
+ * The second hidraw node is what sends events:
+ *
+ * # Keydial mini-050
+ * # Report descriptor length: 160 bytes
+ * # Bytes // Field Name Offset
+ * # ----------------------------------------------------------------------------------
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 🭬 0x09, 0x06, // Usage (Keyboard) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # ┅ 0x85, 0x01, // Report ID (1) 6
+ * # 🮥 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8
+ * # 🭬 0x19, 0xe0, // Usage Minimum (224) 10
+ * # 🭬 0x29, 0xe7, // Usage Maximum (231) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x08, // Report Count (8) 20
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 22
+ * # 0x95, 0x01, // Report Count (1) 24
+ * # 0x75, 0x08, // Report Size (8) 26
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 28
+ * # 0x95, 0x05, // Report Count (5) 30
+ * # 0x75, 0x01, // Report Size (1) 32
+ * # 🮥 0x05, 0x08, // Usage Page (LED) 34
+ * # 🭬 0x19, 0x01, // Usage Minimum (1) 36
+ * # 🭬 0x29, 0x05, // Usage Maximum (5) 38
+ * # ┊ 0x91, 0x02, // Output (Data,Var,Abs) 40
+ * # 0x95, 0x01, // Report Count (1) 42
+ * # 0x75, 0x03, // Report Size (3) 44
+ * # ┊ 0x91, 0x01, // Output (Cnst,Arr,Abs) 46
+ * # 0x95, 0x06, // Report Count (6) 48
+ * # 0x75, 0x08, // Report Size (8) 50
+ * # 0x15, 0x00, // Logical Minimum (0) 52
+ * # 0x25, 0xf1, // Logical Maximum (241) 54
+ * # 🮥 0x05, 0x07, // Usage Page (Keyboard/Keypad) 56
+ * # 🭬 0x19, 0x00, // Usage Minimum (0) 58
+ * # 🭬 0x29, 0xf1, // Usage Maximum (241) 60
+ * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 62
+ * # 0xc0, // End Collection 64
+ * # 🮥 0x05, 0x0c, // Usage Page (Consumer) 65
+ * # 🭬 0x09, 0x01, // Usage (Consumer Control) 67
+ * # 0xa1, 0x01, // Collection (Application) 69
+ * # ┅ 0x85, 0x02, // Report ID (2) 71
+ * # 🮥 0x05, 0x0c, // Usage Page (Consumer) 73
+ * # 🭬 0x19, 0x00, // Usage Minimum (0) 75
+ * # 🭬 0x2a, 0x80, 0x03, // Usage Maximum (896) 77
+ * # 0x15, 0x00, // Logical Minimum (0) 80
+ * # 0x26, 0x80, 0x03, // Logical Maximum (896) 82
+ * # 0x75, 0x10, // Report Size (16) 85
+ * # 0x95, 0x01, // Report Count (1) 87
+ * # ┇ 0x81, 0x00, // Input (Data,Arr,Abs) 89
+ * # 0xc0, // End Collection 91
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 92
+ * # 🭬 0x09, 0x02, // Usage (Mouse) 94
+ * # 0xa1, 0x01, // Collection (Application) 96
+ * # 🭬 0x09, 0x01, // Usage (Pointer) 98
+ * # ┅ 0x85, 0x05, // Report ID (5) 100
+ * # 0xa1, 0x00, // Collection (Physical) 102
+ * # 🮥 0x05, 0x09, // Usage Page (Button) 104
+ * # 🭬 0x19, 0x01, // Usage Minimum (1) 106
+ * # 🭬 0x29, 0x05, // Usage Maximum (5) 108
+ * # 0x15, 0x00, // Logical Minimum (0) 110
+ * # 0x25, 0x01, // Logical Maximum (1) 112
+ * # 0x95, 0x05, // Report Count (5) 114
+ * # 0x75, 0x01, // Report Size (1) 116
+ * # ┇ 0x81, 0x02, // Input (Data,Var,Abs) 118
+ * # 0x95, 0x01, // Report Count (1) 120
+ * # 0x75, 0x03, // Report Size (3) 122
+ * # ┇ 0x81, 0x01, // Input (Cnst,Arr,Abs) 124
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 126
+ * # 🭬 0x09, 0x30, // Usage (X) 128
+ * # 🭬 0x09, 0x31, // Usage (Y) 130
+ * # 0x16, 0x01, 0x80, // Logical Minimum (32769) 132
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 135
+ * # 0x75, 0x10, // Report Size (16) 138
+ * # 0x95, 0x02, // Report Count (2) 140
+ * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 142
+ * # 🮥 0x05, 0x01, // Usage Page (Generic Desktop) 144
+ * # 🭬 0x09, 0x38, // Usage (Wheel) 146
+ * # 0x15, 0x81, // Logical Minimum (129) 148
+ * # 0x25, 0x7f, // Logical Maximum (127) 150
+ * # 0x95, 0x01, // Report Count (1) 152
+ * # 0x75, 0x08, // Report Size (8) 154
+ * # ┇ 0x81, 0x06, // Input (Data,Var,Rel) 156
+ * # 0xc0, // End Collection 158
+ * # 0xc0, // End Collection 159
+ * R: 160 05 01 09 06 a1 01 85 01 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 95 01 75 08 81 01 95 05 75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08 15 00 25 f1 05 07 19 00 29 f1 81 00 c0 05 0c 09 01 a1 01 85 02 05 0c 19 00 2a 80 03 15 00 26 80 03 75 10 95 01 81 00 c0 05 01 09 02 a1 01 09 01 85 05 a1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 16 01 80 26 ff 7f 75 10 95 02 81 06 05 01 09 38 15 81 25 7f 95 01 75 08 81 06 c0 c0
+ * N: Keydial mini-050
+ * I: 5 256c 8251
+ * # Report descriptor:
+ * # ------- Input Report -------
+ * # ░ Report ID: 1
+ * # ░ | Report size: 72 bits
+ * # ░ Bit: 8 Usage: 0007/00e0: Keyboard/Keypad / Keyboard LeftControl Logical Range: 0..=1
+ * # ░ Bit: 9 Usage: 0007/00e1: Keyboard/Keypad / Keyboard LeftShift Logical Range: 0..=1
+ * # ░ Bit: 10 Usage: 0007/00e2: Keyboard/Keypad / Keyboard LeftAlt Logical Range: 0..=1
+ * # ░ Bit: 11 Usage: 0007/00e3: Keyboard/Keypad / Keyboard Left GUI Logical Range: 0..=1
+ * # ░ Bit: 12 Usage: 0007/00e4: Keyboard/Keypad / Keyboard RightControl Logical Range: 0..=1
+ * # ░ Bit: 13 Usage: 0007/00e5: Keyboard/Keypad / Keyboard RightShift Logical Range: 0..=1
+ * # ░ Bit: 14 Usage: 0007/00e6: Keyboard/Keypad / Keyboard RightAlt Logical Range: 0..=1
+ * # ░ Bit: 15 Usage: 0007/00e7: Keyboard/Keypad / Keyboard Right GUI Logical Range: 0..=1
+ * # ░ Bits: 16..=23 ######### Padding
+ * # ░ Bits: 24..=71 Usages: Logical Range: 0..=241
+ * # ░ 0007/0000: <unknown>
+ * # ░ 0007/0001: Keyboard/Keypad / ErrorRollOver
+ * # ░ 0007/0002: Keyboard/Keypad / POSTFail
+ * # ░ 0007/0003: Keyboard/Keypad / ErrorUndefined
+ * # ░ 0007/0004: Keyboard/Keypad / Keyboard A
+ * # ░ ... use --full to see all usages
+ * # ------- Input Report -------
+ * # ▒ Report ID: 2
+ * # ▒ | Report size: 24 bits
+ * # ▒ Bits: 8..=23 Usages: Logical Range: 0..=896
+ * # ▒ 000c/0000: <unknown>
+ * # ▒ 000c/0001: Consumer / Consumer Control
+ * # ▒ 000c/0002: Consumer / Numeric Key Pad
+ * # ▒ 000c/0003: Consumer / Programmable Buttons
+ * # ▒ 000c/0004: Consumer / Microphone
+ * # ▒ ... use --full to see all usages
+ * # ------- Input Report -------
+ * # ▞ Report ID: 5
+ * # ▞ | Report size: 56 bits
+ * # ▞ Bit: 8 Usage: 0009/0001: Button / Button 1 Logical Range: 0..=1
+ * # ▞ Bit: 9 Usage: 0009/0002: Button / Button 2 Logical Range: 0..=1
+ * # ▞ Bit: 10 Usage: 0009/0003: Button / Button 3 Logical Range: 0..=1
+ * # ▞ Bit: 11 Usage: 0009/0004: Button / Button 4 Logical Range: 0..=1
+ * # ▞ Bit: 12 Usage: 0009/0005: Button / Button 5 Logical Range: 0..=1
+ * # ▞ Bits: 13..=15 ######### Padding
+ * # ▞ Bits: 16..=31 Usage: 0001/0030: Generic Desktop / X Logical Range: 32769..=32767
+ * # ▞ Bits: 32..=47 Usage: 0001/0031: Generic Desktop / Y Logical Range: 32769..=32767
+ * # ▞ Bits: 48..=55 Usage: 0001/0038: Generic Desktop / Wheel Logical Range: 129..=127
+ * # ------- Output Report -------
+ * # ░ Report ID: 1
+ * # ░ | Report size: 16 bits
+ * # ░ Bit: 8 Usage: 0008/0001: LED / Num Lock Logical Range: 0..=1
+ * # ░ Bit: 9 Usage: 0008/0002: LED / Caps Lock Logical Range: 0..=1
+ * # ░ Bit: 10 Usage: 0008/0003: LED / Scroll Lock Logical Range: 0..=1
+ * # ░ Bit: 11 Usage: 0008/0004: LED / Compose Logical Range: 0..=1
+ * # ░ Bit: 12 Usage: 0008/0005: LED / Kana Logical Range: 0..=1
+ * # ░ Bits: 13..=15 ######### Padding
+ * ##############################################################################
+ * # Event nodes:
+ * # - /dev/input/event12: "Keydial mini-050 Keyboard"
+ * # - /dev/input/event14: "Keydial mini-050 Mouse"
+ * ##############################################################################
+ * # Recorded events below in format:
+ * # E: <seconds>.<microseconds> <length-in-bytes> [bytes ...]
+ * #
+ *
+ * - Report ID 1 sends keyboard shortcuts when pressing the buttons, e.g.
+ *
+ * # ░ Report ID: 1 /
+ * # ░ Keyboard LeftControl: 0 |Keyboard LeftShift: 0 |Keyboard LeftAlt: 0 |Keyboard Left GUI: 0 |Keyboard RightControl: 0 |Keyboard RightShift: 0 |Keyboard RightAlt: 0 |Keyboard Right GUI: 0 |<8 bits padding> |0007/0000: 0| Keyboard K: 14| 0007/0000: 0| 0007/0000: 0| 0007/0000: 0| 0007/0000: 0
+ * E: 000000.000292 9 01 00 00 00 0e 00 00 00 00
+ *
+ * - Report ID 2 sends the button inside the wheel/dial thing
+ * # ▒ Report ID: 2 /
+ * # ▒ Play/Pause: 205
+ * E: 000134.347845 3 02 cd 00
+ * # ▒ Report ID: 2 /
+ * # ▒ 000c/0000: 0
+ * E: 000134.444965 3 02 00 00
+ *
+ * - Report ID 5 sends the wheel relative events (always a double-event with the second as zero)
+ * # ▞ Report ID: 5 /
+ * # ▞ Button 1: 0 |Button 2: 0 |Button 3: 0 |Button 4: 0 |Button 5: 0 |<3 bits padding> |X: 0 |Y: 0 |Wheel: 255
+ * E: 000064.859915 7 05 00 00 00 00 00 ff
+ * # ▞ Report ID: 5 /
+ * # ▞ Button 1: 0 |Button 2: 0 |Button 3: 0 |Button 4: 0 |Button 5: 0 |<3 bits padding> |X: 0 |Y: 0 |Wheel: 0
+ * E: 000064.882009 7 05 00 00 00 00 00 00
+ */
+
+#define BT_PAD_REPORT_DESCRIPTOR_LENGTH 160
+#define BT_PUCK_REPORT_DESCRIPTOR_LENGTH 114 // This one doesn't send events
+#define BT_PAD_KBD_REPORT_ID 1
+#define BT_PAD_CC_REPORT_ID 2
+#define BT_PAD_MOUSE_REPORT_ID 5
+#define BT_PAD_KBD_REPORT_LENGTH 9
+#define BT_PAD_CC_REPORT_LENGTH 3
+#define BT_PAD_MOUSE_REPORT_LENGTH 7
+#define OUR_REPORT_ID 11 /* "randomly" picked report ID for our reports */
+
+__u32 last_button_state = 0;
+
+static const __u8 disabled_rdesc_puck[] = {
+ FixedSizeVendorReport(BT_PUCK_REPORT_DESCRIPTOR_LENGTH)
+};
+
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ ReportId(OUR_REPORT_ID)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 is a button so we look like a tablet
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Bytes 4-7 are the button state for 19 buttons + pad out to u32
+ // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9
+ UsagePage_Button
+ UsageMinimum_i8(1)
+ UsageMaximum_i8(10)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(10)
+ ReportSize(1)
+ Input(Var|Abs)
+ // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2
+ UsageMinimum_i8(0x31)
+ UsageMaximum_i8(0x3a)
+ ReportCount(9)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(13)
+ ReportSize(1)
+ Input(Const) // padding
+ // Byte 8 is the wheel
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(BT_PAD_KBD_REPORT_LENGTH)
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(k20_bt_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 == BT_PAD_REPORT_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ }
+ if (rdesc_size == BT_PUCK_REPORT_DESCRIPTOR_LENGTH) {
+ // This hidraw node doesn't send anything and can be ignored
+ __builtin_memcpy(data, disabled_rdesc_puck, sizeof(disabled_rdesc_puck));
+ return sizeof(disabled_rdesc_puck);
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(k20_bt_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 12 /* size */);
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus:1;
+ __u8 pad:7;
+ __u8 x;
+ __u8 y;
+ __u32 buttons;
+ __u8 wheel;
+ } __packed * pad_report = (struct pad_report *)data;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Report ID 1 - Keyboard events (button presses) */
+ if (data[0] == BT_PAD_KBD_REPORT_ID) {
+ const __u8 button_mapping[] = {
+ 0x0e, /* Button 1: K */
+ 0x0a, /* Button 2: G */
+ 0x0f, /* Button 3: L */
+ 0x4c, /* Button 4: Delete */
+ 0x0c, /* Button 5: I */
+ 0x07, /* Button 6: D */
+ 0x05, /* Button 7: B */
+ 0x08, /* Button 8: E */
+ 0x16, /* Button 9: S */
+ 0x1d, /* Button 10: Z */
+ 0x06, /* Button 11: C */
+ 0x19, /* Button 12: V */
+ 0xff, /* Button 13: LeftControl */
+ 0xff, /* Button 14: LeftAlt */
+ 0xff, /* Button 15: LeftShift */
+ 0x28, /* Button 16: Return Enter */
+ 0x2c, /* Button 17: Spacebar */
+ 0x11, /* Button 18: N */
+ };
+
+ __u8 modifiers = data[1];
+ __u32 buttons = 0;
+
+ if (modifiers & 0x01) { /* Control */
+ buttons |= BIT(12);
+ }
+ if (modifiers & 0x02) { /* Shift */
+ buttons |= BIT(14);
+ }
+ if (modifiers & 0x04) { /* Alt */
+ buttons |= BIT(13);
+ }
+
+ for (int i = 4; i < BT_PAD_KBD_REPORT_LENGTH; i++) {
+ if (!data[i])
+ break;
+
+ for (size_t b = 0; b < ARRAY_SIZE(button_mapping); b++) {
+ if (data[i] != 0xff && data[i] == button_mapping[b]) {
+ buttons |= BIT(b);
+ break;
+ }
+ }
+ }
+
+ last_button_state = buttons;
+
+ pad_report->report_id = OUR_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = buttons;
+ pad_report->wheel = 0;
+
+ return sizeof(struct pad_report);
+ }
+
+ /* Report ID 2 - Consumer control events (the button inside the wheel) */
+ if (data[0] == BT_PAD_CC_REPORT_ID) {
+ const __u8 PlayPause = 0xcd;
+
+ if (data[1] == PlayPause)
+ last_button_state |= BIT(18);
+ else
+ last_button_state &= ~BIT(18);
+
+ pad_report->report_id = OUR_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->wheel = 0;
+
+ return sizeof(struct pad_report);
+ }
+
+ /* Report ID 5 - Mouse events (wheel rotation) */
+ if (data[0] == BT_PAD_MOUSE_REPORT_ID) {
+ __u8 wheel_delta = data[6];
+
+ pad_report->report_id = OUR_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->wheel = wheel_delta;
+
+ return sizeof(struct pad_report);
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(keydial_k20_bluetooth) = {
+ .hid_device_event = (void *)k20_bt_fix_events,
+ .hid_rdesc_fixup = (void *)k20_bt_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case BT_PAD_REPORT_DESCRIPTOR_LENGTH:
+ case BT_PUCK_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Huion__KeydialK20.bpf.c b/drivers/hid/bpf/progs/Huion__KeydialK20.bpf.c
new file mode 100644
index 000000000..c562c2d68
--- /dev/null
+++ b/drivers/hid/bpf/progs/Huion__KeydialK20.bpf.c
@@ -0,0 +1,532 @@
+// 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 VID_HUION 0x256C
+#define PID_KEYDIAL_K20 0x0069
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HUION, PID_KEYDIAL_K20),
+);
+
+/* Filled in by udev-hid-bpf */
+char UDEV_PROP_HUION_FIRMWARE_ID[64];
+
+/* The prefix of the firmware ID we expect for this device. The full firmware
+ * string has a date suffix, e.g. HUION_T21h_230511
+ */
+char EXPECTED_FIRMWARE_ID[] = "HUION_T21h_";
+
+/* How this BPF program works: the tablet has two modes, firmware mode and
+ * tablet mode. In firmware mode (out of the box) the tablet sends button events
+ * as keyboard shortcuts and the dial as wheel but it's not forwarded by the kernel.
+ * In tablet mode it uses a vendor specific hid report to report everything instead.
+ * Depending on the mode some hid reports are never sent and the corresponding
+ * devices are mute.
+ *
+ * To switch the tablet use e.g. https://github.com/whot/huion-switcher
+ * or one of the tools from the digimend project
+ *
+ * This BPF currently works for both modes only. The huion-switcher tool sets the
+ * HUION_FIRMWARE_ID udev property - if that is set then we disable the firmware
+ * pad and pen reports (by making them vendor collections that are ignored).
+ * If that property is not set we fix all hidraw nodes so the tablet works in
+ * either mode though the drawback is that the device will show up twice if
+ * you bind it to all event nodes
+ *
+ * Default report descriptor for the first exposed hidraw node:
+ *
+ * # HUION Huion Keydial_K20
+ * # Report descriptor length: 18 bytes
+ * # 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 0xFF00) 0
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 3
+ * # 0xa1, 0x01, // Collection (Application) 5
+ * # 0x85, 0x08, // Report ID (8) 7
+ * # 0x75, 0x58, // Report Size (88) 9
+ * # 0x95, 0x01, // Report Count (1) 11
+ * # 0x09, 0x01, // Usage (Vendor Usage 0x01) 13
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 15
+ * # 0xc0, // End Collection 17
+ * R: 18 06 00 ff 09 01 a1 01 85 08 75 58 95 01 09 01 81 02 c0
+ *
+ * This report descriptor appears to be identical for all Huion devices.
+ *
+ * Second hidraw node is the Pad. This one sends the button events until the tablet is
+ * switched to raw mode, then it's mute.
+ *
+ * # HUION Huion Keydial_K20
+ * # Report descriptor length: 135 bytes
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x06, // Usage (Keyboard) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x03, // Report ID (3) 6
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 8
+ * # 0x19, 0xe0, // UsageMinimum (224) 10
+ * # 0x29, 0xe7, // UsageMaximum (231) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x08, // Report Count (8) 20
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 22
+ * # 0x05, 0x07, // Usage Page (Keyboard/Keypad) 24
+ * # 0x19, 0x00, // UsageMinimum (0) 26
+ * # 0x29, 0xff, // UsageMaximum (255) 28
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 30
+ * # 0x75, 0x08, // Report Size (8) 33
+ * # 0x95, 0x06, // Report Count (6) 35
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 37
+ * # 0xc0, // End Collection 39
+ * # 0x05, 0x0c, // Usage Page (Consumer) 40
+ * # 0x09, 0x01, // Usage (Consumer Control) 42
+ * # 0xa1, 0x01, // Collection (Application) 44
+ * # 0x85, 0x04, // Report ID (4) 46
+ * # 0x05, 0x0c, // Usage Page (Consumer) 48
+ * # 0x19, 0x00, // UsageMinimum (0) 50
+ * # 0x2a, 0x80, 0x03, // UsageMaximum (896) 52
+ * # 0x15, 0x00, // Logical Minimum (0) 55
+ * # 0x26, 0x80, 0x03, // Logical Maximum (896) 57
+ * # 0x75, 0x10, // Report Size (16) 60
+ * # 0x95, 0x01, // Report Count (1) 62
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 64
+ * # 0xc0, // End Collection 66
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 67
+ * # 0x09, 0x02, // Usage (Mouse) 69
+ * # 0xa1, 0x01, // Collection (Application) 71
+ * # 0x09, 0x01, // Usage (Pointer) 73
+ * # 0x85, 0x05, // Report ID (5) 75
+ * # 0xa1, 0x00, // Collection (Physical) 77
+ * # 0x05, 0x09, // Usage Page (Button) 79
+ * # 0x19, 0x01, // UsageMinimum (1) 81
+ * # 0x29, 0x05, // UsageMaximum (5) 83
+ * # 0x15, 0x00, // Logical Minimum (0) 85
+ * # 0x25, 0x01, // Logical Maximum (1) 87
+ * # 0x95, 0x05, // Report Count (5) 89
+ * # 0x75, 0x01, // Report Size (1) 91
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # 0x75, 0x03, // Report Size (3) 97
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 99
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 101
+ * # 0x09, 0x30, // Usage (X) 103
+ * # 0x09, 0x31, // Usage (Y) 105
+ * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 107
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 110
+ * # 0x75, 0x10, // Report Size (16) 113
+ * # 0x95, 0x02, // Report Count (2) 115
+ * # 0x81, 0x06, // Input (Data,Var,Rel) 117
+ * # 0x95, 0x01, // Report Count (1) 119
+ * # 0x75, 0x08, // Report Size (8) 121
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 123
+ * # 0x09, 0x38, // Usage (Wheel) 125
+ * # 0x15, 0x81, // Logical Minimum (-127) 127
+ * # 0x25, 0x7f, // Logical Maximum (127) 129
+ * # 0x81, 0x06, // Input (Data,Var,Rel) 131
+ * # 0xc0, // End Collection 133
+ * # 0xc0, // End Collection 134
+ * R: 135 05 01 09 06 a1 01 85 03 05 07 19 e0 29 e7 15 00 25 01 75 01 95 08 81 02 05 07 19 00 29 ff 26 ff 00 75 08 95 06 81 00 c0 05 0c 09 01 a1 01 85 04 05 0c 19 00 2a 80 03 15 00 26 80 03 75 10 95 01 81 00 c0 05 01 09 02 a1 01 09 01 85 05 a1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 16 00 80 26 ff 7f 7510 95 02 81 06 95 01 75 08 05 01 09 38 15 81 25 7f 81 06 c0 c0
+ *
+ * Third hidraw node is a multi-axis controller which sends the dial events
+ * and the button inside the dial. If the tablet is switched to raw mode it is mute.
+ *
+ * # HUION Huion Keydial_K20
+ * # Report descriptor length: 108 bytes
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * # 0x09, 0x0e, // Usage (System Multi-Axis Controller) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x11, // Report ID (17) 6
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 8
+ * # 0x09, 0x21, // Usage (Puck) 10
+ * # 0xa1, 0x02, // Collection (Logical) 12
+ * # 0x15, 0x00, // Logical Minimum (0) 14
+ * # 0x25, 0x01, // Logical Maximum (1) 16
+ * # 0x75, 0x01, // Report Size (1) 18
+ * # 0x95, 0x01, // Report Count (1) 20
+ * # 0xa1, 0x00, // Collection (Physical) 22
+ * # 0x05, 0x09, // Usage Page (Button) 24
+ * # 0x09, 0x01, // Usage (Button 1) 26
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 30
+ * # 0x09, 0x33, // Usage (Touch) 32
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 34
+ * # 0x95, 0x06, // Report Count (6) 36
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 38
+ * # 0xa1, 0x02, // Collection (Logical) 40
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 42
+ * # 0x09, 0x37, // Usage (Dial) 44
+ * # 0x16, 0x00, 0x80, // Logical Minimum (-32768) 46
+ * # 0x26, 0xff, 0x7f, // Logical Maximum (32767) 49
+ * # 0x75, 0x10, // Report Size (16) 52
+ * # 0x95, 0x01, // Report Count (1) 54
+ * # 0x81, 0x06, // Input (Data,Var,Rel) 56
+ * # 0x35, 0x00, // Physical Minimum (0) 58
+ * # 0x46, 0x10, 0x0e, // Physical Maximum (3600) 60
+ * # 0x15, 0x00, // Logical Minimum (0) 63
+ * # 0x26, 0x10, 0x0e, // Logical Maximum (3600) 65
+ * # 0x09, 0x48, // Usage (Resolution Multiplier) 68
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 70
+ * # 0x45, 0x00, // Physical Maximum (0) 72
+ * # 0xc0, // End Collection 74
+ * # 0x75, 0x08, // Report Size (8) 75
+ * # 0x95, 0x01, // Report Count (1) 77
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 79
+ * # 0x75, 0x08, // Report Size (8) 81
+ * # 0x95, 0x01, // Report Count (1) 83
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 85
+ * # 0x75, 0x08, // Report Size (8) 87
+ * # 0x95, 0x01, // Report Count (1) 89
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 91
+ * # 0x75, 0x08, // Report Size (8) 93
+ * # 0x95, 0x01, // Report Count (1) 95
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 97
+ * # 0x75, 0x08, // Report Size (8) 99
+ * # 0x95, 0x01, // Report Count (1) 101
+ * # 0x81, 0x01, // Input (Cnst,Arr,Abs) 103
+ * # 0xc0, // End Collection 105
+ * # 0xc0, // End Collection 106
+ * # 0xc0, // End Collection 107
+ * R: 108 05 01 09 0e a1 01 85 11 05 0d 09 21 a1 02 15 00 25 01 75 01 95 01 a1 00 05 09 09 01 81 02 05 0d 09 33 81 02 95 06 81 03 a1 02 05 01 09 37 16 00 80 26 ff 7f 75 10 95 01 81 06 35 00 46 10 0e 15 00 26 10 0e 09 48 b1 02 45 00 c0 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 75 08 95 01 81 01 c0 c0 c0
+ *
+ */
+
+#define PAD_REPORT_DESCRIPTOR_LENGTH 135
+#define PUCK_REPORT_DESCRIPTOR_LENGTH 108
+#define VENDOR_REPORT_DESCRIPTOR_LENGTH 18
+#define PAD_KBD_REPORT_ID 3
+#define PAD_CC_REPORT_ID 3 // never sends events
+#define PAD_MOUSE_REPORT_ID 4 // never sends events
+#define PUCK_REPORT_ID 17
+#define VENDOR_REPORT_ID 8
+#define PAD_KBD_REPORT_LENGTH 8
+#define PAD_CC_REPORT_LENGTH 3
+#define PAD_MOUSE_REPORT_LENGTH 7
+#define PUCK_REPORT_LENGTH 9
+#define VENDOR_REPORT_LENGTH 12
+
+__u32 last_button_state;
+
+static const __u8 disabled_rdesc_puck[] = {
+ FixedSizeVendorReport(PUCK_REPORT_LENGTH)
+};
+
+static const __u8 disabled_rdesc_pad[] = {
+ FixedSizeVendorReport(PAD_KBD_REPORT_LENGTH)
+ FixedSizeVendorReport(PAD_CC_REPORT_LENGTH)
+ FixedSizeVendorReport(PAD_MOUSE_REPORT_LENGTH)
+};
+
+static const __u8 fixed_rdesc_vendor[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ // We send our pad events on the vendor report id because why not
+ ReportId(VENDOR_REPORT_ID)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 is a button so we look like a tablet
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Bytes 4-7 are the button state for 19 buttons + pad out to u32
+ // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9
+ UsagePage_Button
+ UsageMinimum_i8(1)
+ UsageMaximum_i8(10)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(10)
+ ReportSize(1)
+ Input(Var|Abs)
+ // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2
+ UsageMinimum_i8(0x31)
+ UsageMaximum_i8(0x3a)
+ ReportCount(9)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(13)
+ ReportSize(1)
+ Input(Const) // padding
+ // Byte 6 is the wheel
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report length
+ FixedSizeVendorReport(VENDOR_REPORT_LENGTH)
+ )
+};
+
+/* Identical to fixed_rdesc_pad but with different FixedSizeVendorReport */
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0
+ // We send our pad events on the vendor report id because why not
+ ReportId(VENDOR_REPORT_ID)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 is a button so we look like a tablet
+ Usage_Dig_BarrelSwitch // BTN_STYLUS, needed so we get to be a tablet pad
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // Padding
+ Input(Const)
+ // Bytes 2/3 - x/y just exist so we get to be a tablet pad
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ // Bytes 4-7 are the button state for 19 buttons + pad out to u32
+ // We send the first 10 buttons as buttons 1-10 which is BTN_0 -> BTN_9
+ UsagePage_Button
+ UsageMinimum_i8(1)
+ UsageMaximum_i8(10)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(10)
+ ReportSize(1)
+ Input(Var|Abs)
+ // We send the other 9 buttons as buttons 0x31 and above -> BTN_A - BTN_TL2
+ UsageMinimum_i8(0x31)
+ UsageMaximum_i8(0x3a)
+ ReportCount(9)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(13)
+ ReportSize(1)
+ Input(Const) // padding
+ // Byte 6 is the wheel
+ UsagePage_GenericDesktop
+ Usage_GD_Wheel
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(8)
+ Input(Var|Rel)
+ )
+ // Make sure we match our original report lengths
+ FixedSizeVendorReport(PAD_KBD_REPORT_LENGTH)
+ FixedSizeVendorReport(PAD_CC_REPORT_LENGTH)
+ FixedSizeVendorReport(PAD_MOUSE_REPORT_LENGTH)
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(k20_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;
+ __u8 have_fw_id;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* If we have a firmware ID and it matches our expected prefix, we
+ * disable the default pad/puck nodes. They won't send events
+ * but cause duplicate devices.
+ */
+ have_fw_id = __builtin_memcmp(UDEV_PROP_HUION_FIRMWARE_ID,
+ EXPECTED_FIRMWARE_ID,
+ sizeof(EXPECTED_FIRMWARE_ID) - 1) == 0;
+ if (rdesc_size == PAD_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_pad, sizeof(disabled_rdesc_pad));
+ return sizeof(disabled_rdesc_pad);
+ } else {
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+
+ }
+ }
+ if (rdesc_size == PUCK_REPORT_DESCRIPTOR_LENGTH) {
+ if (have_fw_id) {
+ __builtin_memcpy(data, disabled_rdesc_puck, sizeof(disabled_rdesc_puck));
+ return sizeof(disabled_rdesc_puck);
+ }
+ }
+ /* Always fix the vendor mode so the tablet will work even if nothing sets
+ * the udev property (e.g. huion-switcher run manually)
+ */
+ if (rdesc_size == VENDOR_REPORT_DESCRIPTOR_LENGTH) {
+ __builtin_memcpy(data, fixed_rdesc_vendor, sizeof(fixed_rdesc_vendor));
+ return sizeof(fixed_rdesc_vendor);
+
+ }
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(k20_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Only sent if tablet is in raw mode */
+ if (data[0] == VENDOR_REPORT_ID) {
+ /* See fixed_rdesc_pad */
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus:1;
+ __u8 pad:7;
+ __u8 x;
+ __u8 y;
+ __u32 buttons;
+ __u8 wheel;
+ } __attribute__((packed)) *pad_report;
+
+ __u8 wheel = 0;
+
+ /* Wheel report */
+ if (data[1] == 0xf1) {
+ if (data[5] == 2)
+ wheel = 0xff;
+ else
+ wheel = data[5];
+ } else {
+ /* data[4..6] are the buttons, mapped correctly */
+ last_button_state = data[4] | (data[5] << 8) | (data[6] << 16);
+ wheel = 0; // wheel
+ }
+
+ pad_report = (struct pad_report *)data;
+ pad_report->report_id = VENDOR_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = last_button_state;
+ pad_report->wheel = wheel;
+
+ return sizeof(struct pad_report);
+ }
+
+ if (data[0] == PAD_KBD_REPORT_ID) {
+ const __u8 button_mapping[] = {
+ 0x0e, /* Button 1: K */
+ 0x0a, /* Button 2: G */
+ 0x0f, /* Button 3: L */
+ 0x4c, /* Button 4: Delete */
+ 0x0c, /* Button 5: I */
+ 0x07, /* Button 6: D */
+ 0x05, /* Button 7: B */
+ 0x08, /* Button 8: E */
+ 0x16, /* Button 9: S */
+ 0x1d, /* Button 10: Z */
+ 0x06, /* Button 11: C */
+ 0x19, /* Button 12: V */
+ 0xff, /* Button 13: LeftControl */
+ 0xff, /* Button 14: LeftAlt */
+ 0xff, /* Button 15: LeftShift */
+ 0x28, /* Button 16: Return Enter */
+ 0x2c, /* Button 17: Spacebar */
+ 0x11, /* Button 18: N */
+ };
+ /* See fixed_rdesc_pad */
+ struct pad_report {
+ __u8 report_id;
+ __u8 btn_stylus:1;
+ __u8 pad:7;
+ __u8 x;
+ __u8 y;
+ __u32 buttons;
+ __u8 wheel;
+ } __attribute__((packed)) *pad_report;
+ int i;
+ size_t b;
+ __u8 modifiers = data[1];
+ __u32 buttons = 0;
+
+ if (modifiers & 0x01) { /* Control */
+ buttons |= BIT(12);
+ }
+ if (modifiers & 0x02) { /* Shift */
+ buttons |= BIT(14);
+ }
+ if (modifiers & 0x04) { /* Alt */
+ buttons |= BIT(13);
+ }
+
+ for (i = 2; i < PAD_KBD_REPORT_LENGTH; i++) {
+ if (!data[i])
+ break;
+
+ for (b = 0; b < ARRAY_SIZE(button_mapping); b++) {
+ if (data[i] == button_mapping[b]) {
+ buttons |= BIT(b);
+ break;
+ }
+ }
+ data[i] = 0;
+ }
+
+ pad_report = (struct pad_report *)data;
+ pad_report->report_id = VENDOR_REPORT_ID;
+ pad_report->btn_stylus = 0;
+ pad_report->x = 0;
+ pad_report->y = 0;
+ pad_report->buttons = buttons;
+ // The wheel happens on a different hidraw node but its
+ // values are unreliable (as is the button inside the wheel).
+ // So the wheel is simply always zero, if you want the wheel
+ // to work reliably, use the tablet mode.
+ pad_report->wheel = 0;
+
+ return sizeof(struct pad_report);
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(keydial_k20) = {
+ .hid_device_event = (void *)k20_fix_events,
+ .hid_rdesc_fixup = (void *)k20_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ case PUCK_REPORT_DESCRIPTOR_LENGTH:
+ case VENDOR_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c
new file mode 100644
index 000000000..253b96458
--- /dev/null
+++ b/drivers/hid/bpf/progs/IOGEAR__Kaliber-MMOmentum.bpf.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2023 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_IOGEAR 0x258A /* VID is shared with SinoWealth and Glorious and prob others */
+#define PID_MOMENTUM 0x0027
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_IOGEAR, PID_MOMENTUM)
+);
+
+/*
+ * The IOGear Kaliber Gaming MMOmentum Pro mouse has multiple buttons (12)
+ * but only 5 are accessible out of the box because the report descriptor
+ * marks the other buttons as constants.
+ * We just fix the report descriptor to enable those missing 7 buttons.
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ const u8 offsets[] = {84, 112, 140};
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* if not Keyboard */
+ if (data[3] != 0x06)
+ return 0;
+
+ for (size_t idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
+ u8 offset = offsets[idx];
+
+ /* if Input (Cnst,Var,Abs) , make it Input (Data,Var,Abs) */
+ if (data[offset] == 0x81 && data[offset + 1] == 0x03)
+ data[offset + 1] = 0x02;
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(iogear_kaliber_momentum) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /* only bind to the keyboard interface */
+ ctx->retval = ctx->rdesc_size != 213;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c b/drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c
new file mode 100644
index 000000000..b17719d6d
--- /dev/null
+++ b/drivers/hid/bpf/progs/Logitech__SpaceNavigator.bpf.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Curran Muhlberger
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_LOGITECH 0x046D
+#define PID_SPACENAVIGATOR 0xC626
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_LOGITECH, PID_SPACENAVIGATOR)
+);
+
+/*
+ * The 3Dconnexion SpaceNavigator 3D Mouse is a multi-axis controller with 6
+ * axes (grouped as X,Y,Z and Rx,Ry,Rz). Axis data is absolute, but the report
+ * descriptor erroneously declares it to be relative. We fix the report
+ * descriptor to mark both axis collections as absolute.
+ *
+ * The kernel attempted to fix this in commit 24985cf68612 (HID: support
+ * Logitech/3DConnexion SpaceTraveler and SpaceNavigator), but the descriptor
+ * data offsets are incorrect for at least some SpaceNavigator units.
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Offset of Input item in X,Y,Z and Rx,Ry,Rz collections for all known
+ * firmware variants.
+ * - 2009 model: X,Y,Z @ 32-33, Rx,Ry,Rz @ 49-50 (fixup originally
+ * applied in kernel)
+ * - 2016 model (size==228): X,Y,Z @ 36-37, Rx,Ry,Rz @ 53-54
+ *
+ * The descriptor size of the 2009 model is not known, and there is evidence
+ * for at least two other variants (with sizes 202 & 217) besides the 2016
+ * model, so we try all known offsets regardless of descriptor size.
+ */
+ const u8 offsets[] = {32, 36, 49, 53};
+
+ for (size_t idx = 0; idx < ARRAY_SIZE(offsets); idx++) {
+ u8 offset = offsets[idx];
+
+ /* if Input (Data,Var,Rel) , make it Input (Data,Var,Abs) */
+ if (data[offset] == 0x81 && data[offset + 1] == 0x06)
+ data[offset + 1] = 0x02;
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(logitech_spacenavigator) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /* Ensure report descriptor size matches one of the known variants. */
+ if (ctx->rdesc_size != 202 &&
+ ctx->rdesc_size != 217 &&
+ ctx->rdesc_size != 228) {
+ ctx->retval = -EINVAL;
+ return 0;
+ }
+
+ /* Check whether the kernel has already applied the fix. */
+ if ((ctx->rdesc[32] == 0x81 && ctx->rdesc[33] == 0x02 &&
+ ctx->rdesc[49] == 0x81 && ctx->rdesc[50] == 0x02) ||
+ (ctx->rdesc[36] == 0x81 && ctx->rdesc[37] == 0x02 &&
+ ctx->rdesc[53] == 0x81 && ctx->rdesc[54] == 0x02))
+ ctx->retval = -EINVAL;
+ else
+ ctx->retval = 0;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Makefile b/drivers/hid/bpf/progs/Makefile
new file mode 100644
index 000000000..66b8f38e5
--- /dev/null
+++ b/drivers/hid/bpf/progs/Makefile
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: GPL-2.0
+OUTPUT := .output
+abs_out := $(abspath $(OUTPUT))
+
+CLANG ?= clang
+LLC ?= llc
+LLVM_STRIP ?= llvm-strip
+
+TOOLS_PATH := $(abspath ../../../../tools)
+BPFTOOL_SRC := $(TOOLS_PATH)/bpf/bpftool
+BPFTOOL_OUTPUT := $(abs_out)/bpftool
+DEFAULT_BPFTOOL := $(BPFTOOL_OUTPUT)/bootstrap/bpftool
+BPFTOOL ?= $(DEFAULT_BPFTOOL)
+
+LIBBPF_SRC := $(TOOLS_PATH)/lib/bpf
+LIBBPF_OUTPUT := $(abs_out)/libbpf
+LIBBPF_DESTDIR := $(LIBBPF_OUTPUT)
+LIBBPF_INCLUDE := $(LIBBPF_DESTDIR)/include
+BPFOBJ := $(LIBBPF_OUTPUT)/libbpf.a
+
+INCLUDES := -I$(OUTPUT) -I$(LIBBPF_INCLUDE) -I$(TOOLS_PATH)/include/uapi
+CFLAGS := -g -Wall
+
+VMLINUX_BTF_PATHS ?= $(if $(O),$(O)/vmlinux) \
+ $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux) \
+ ../../../../vmlinux \
+ /sys/kernel/btf/vmlinux \
+ /boot/vmlinux-$(shell uname -r)
+VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS))))
+ifeq ($(VMLINUX_BTF),)
+$(error Cannot find a vmlinux for VMLINUX_BTF at any of "$(VMLINUX_BTF_PATHS)")
+endif
+
+ifeq ($(V),1)
+Q =
+msg =
+else
+Q = @
+msg = @printf ' %-8s %s%s\n' "$(1)" "$(notdir $(2))" "$(if $(3), $(3))";
+MAKEFLAGS += --no-print-directory
+submake_extras := feature_display=0
+endif
+
+.DELETE_ON_ERROR:
+
+.PHONY: all clean
+
+SOURCES = $(wildcard *.bpf.c)
+TARGETS = $(SOURCES:.bpf.c=.bpf.o)
+
+all: $(TARGETS)
+
+clean:
+ $(call msg,CLEAN)
+ $(Q)rm -rf $(OUTPUT) $(TARGETS)
+
+%.bpf.o: %.bpf.c vmlinux.h $(BPFOBJ) | $(OUTPUT)
+ $(call msg,BPF,$@)
+ $(Q)$(CLANG) -g -O2 --target=bpf -Wall -Werror $(INCLUDES) \
+ -Wno-microsoft-anon-tag \
+ -fms-extensions \
+ -c $(filter %.c,$^) -o $@ && \
+ $(LLVM_STRIP) -g $@
+
+vmlinux.h: $(VMLINUX_BTF) $(BPFTOOL) | $(INCLUDE_DIR)
+ifeq ($(VMLINUX_H),)
+ $(call msg,GEN,,$@)
+ $(Q)$(BPFTOOL) btf dump file $(VMLINUX_BTF) format c > $@
+else
+ $(call msg,CP,,$@)
+ $(Q)cp "$(VMLINUX_H)" $@
+endif
+
+$(OUTPUT) $(LIBBPF_OUTPUT) $(BPFTOOL_OUTPUT):
+ $(call msg,MKDIR,$@)
+ $(Q)mkdir -p $@
+
+$(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) \
+ OUTPUT=$(abspath $(dir $@))/ prefix= \
+ DESTDIR=$(LIBBPF_DESTDIR) $(abspath $@) install_headers
+
+ifeq ($(CROSS_COMPILE),)
+$(DEFAULT_BPFTOOL): $(BPFOBJ) | $(BPFTOOL_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
+ OUTPUT=$(BPFTOOL_OUTPUT)/ \
+ LIBBPF_BOOTSTRAP_OUTPUT=$(LIBBPF_OUTPUT)/ \
+ LIBBPF_BOOTSTRAP_DESTDIR=$(LIBBPF_DESTDIR)/ bootstrap
+else
+$(DEFAULT_BPFTOOL): | $(BPFTOOL_OUTPUT)
+ $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOL_SRC) \
+ OUTPUT=$(BPFTOOL_OUTPUT)/ bootstrap
+endif
diff --git a/drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c b/drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c
new file mode 100644
index 000000000..382bba735
--- /dev/null
+++ b/drivers/hid/bpf/progs/Microsoft__Xbox-Elite-2.bpf.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_MICROSOFT 0x045e
+#define PID_XBOX_ELITE_2 0x0b22
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_GENERIC, VID_MICROSOFT, PID_XBOX_ELITE_2)
+);
+
+/*
+ * When using the Xbox Wireless Controller Elite 2 over Bluetooth,
+ * the device exports the paddles on the back of the device as a single
+ * bitfield value of usage "Assign Selection".
+ *
+ * The kernel doesn't process the paddles usage properly and reports KEY_UNKNOWN.
+ *
+ * SDL doesn't know how to interpret KEY_UNKNOWN and thus ignores the paddles.
+ *
+ * Given that over USB the kernel uses BTN_TRIGGER_HAPPY[5-8], we
+ * can tweak the report descriptor to make the kernel interpret it properly:
+ * - We need an application collection of gamepad (so we have to close the current
+ * Consumer Control one)
+ * - We need to change the usage to be buttons from 0x15 to 0x18
+ */
+
+#define OFFSET_ASSIGN_SELECTION 211
+#define ORIGINAL_RDESC_SIZE 464
+
+const __u8 rdesc_assign_selection[] = {
+ 0x0a, 0x99, 0x00, // Usage (Media Select Security) 211
+ 0x15, 0x00, // Logical Minimum (0) 214
+ 0x26, 0xff, 0x00, // Logical Maximum (255) 216
+ 0x95, 0x01, // Report Count (1) 219
+ 0x75, 0x04, // Report Size (4) 221
+ 0x81, 0x02, // Input (Data,Var,Abs) 223
+ 0x15, 0x00, // Logical Minimum (0) 225
+ 0x25, 0x00, // Logical Maximum (0) 227
+ 0x95, 0x01, // Report Count (1) 229
+ 0x75, 0x04, // Report Size (4) 231
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 233
+ 0x0a, 0x81, 0x00, // Usage (Assign Selection) 235
+ 0x15, 0x00, // Logical Minimum (0) 238
+ 0x26, 0xff, 0x00, // Logical Maximum (255) 240
+ 0x95, 0x01, // Report Count (1) 243
+ 0x75, 0x04, // Report Size (4) 245
+ 0x81, 0x02, // Input (Data,Var,Abs) 247
+};
+
+/*
+ * we replace the above report descriptor extract
+ * with the one below.
+ * To make things equal in size, we take out a larger
+ * portion than just the "Assign Selection" range, because
+ * we need to insert a new application collection to force
+ * the kernel to use BTN_TRIGGER_HAPPY[4-7].
+ */
+const __u8 fixed_rdesc_assign_selection[] = {
+ 0x0a, 0x99, 0x00, // Usage (Media Select Security) 211
+ 0x15, 0x00, // Logical Minimum (0) 214
+ 0x26, 0xff, 0x00, // Logical Maximum (255) 216
+ 0x95, 0x01, // Report Count (1) 219
+ 0x75, 0x04, // Report Size (4) 221
+ 0x81, 0x02, // Input (Data,Var,Abs) 223
+ /* 0x15, 0x00, */ // Logical Minimum (0) ignored
+ 0x25, 0x01, // Logical Maximum (1) 225
+ 0x95, 0x04, // Report Count (4) 227
+ 0x75, 0x01, // Report Size (1) 229
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 231
+ 0xc0, // End Collection 233
+ 0x05, 0x01, // Usage Page (Generic Desktop) 234
+ 0x0a, 0x05, 0x00, // Usage (Game Pad) 236
+ 0xa1, 0x01, // Collection (Application) 239
+ 0x05, 0x09, // Usage Page (Button) 241
+ 0x19, 0x15, // Usage Minimum (21) 243
+ 0x29, 0x18, // Usage Maximum (24) 245
+ /* 0x15, 0x00, */ // Logical Minimum (0) ignored
+ /* 0x25, 0x01, */ // Logical Maximum (1) ignored
+ /* 0x95, 0x01, */ // Report Size (1) ignored
+ /* 0x75, 0x04, */ // Report Count (4) ignored
+ 0x81, 0x02, // Input (Data,Var,Abs) 247
+};
+
+_Static_assert(sizeof(rdesc_assign_selection) == sizeof(fixed_rdesc_assign_selection),
+ "Rdesc and fixed rdesc of different size");
+_Static_assert(sizeof(rdesc_assign_selection) + OFFSET_ASSIGN_SELECTION < ORIGINAL_RDESC_SIZE,
+ "Rdesc at given offset is too big");
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /* Check that the device is compatible */
+ if (__builtin_memcmp(data + OFFSET_ASSIGN_SELECTION,
+ rdesc_assign_selection,
+ sizeof(rdesc_assign_selection)))
+ return 0;
+
+ __builtin_memcpy(data + OFFSET_ASSIGN_SELECTION,
+ fixed_rdesc_assign_selection,
+ sizeof(fixed_rdesc_assign_selection));
+
+ return 0;
+}
+
+HID_BPF_OPS(xbox_elite_2) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /* only bind to the keyboard interface */
+ ctx->retval = ctx->rdesc_size != ORIGINAL_RDESC_SIZE;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ if (__builtin_memcmp(ctx->rdesc + OFFSET_ASSIGN_SELECTION,
+ rdesc_assign_selection,
+ sizeof(rdesc_assign_selection)))
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Mistel__MD770.bpf.c b/drivers/hid/bpf/progs/Mistel__MD770.bpf.c
new file mode 100644
index 000000000..fb8b5a696
--- /dev/null
+++ b/drivers/hid/bpf/progs/Mistel__MD770.bpf.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2024 Tatsuyuki Ishi
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_HOLTEK 0x04D9
+#define PID_MD770 0x0339
+#define RDESC_SIZE 203
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_HOLTEK, PID_MD770)
+);
+
+/*
+ * The Mistel MD770 keyboard reports the first 6 simultaneous key presses
+ * through the first interface, and anything beyond that through a second
+ * interface. Unfortunately, the second interface's report descriptor has an
+ * error, causing events to be malformed and ignored. This HID-BPF driver
+ * fixes the descriptor to allow NKRO to work again.
+ *
+ * For reference, this is the original report descriptor:
+ *
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * 0x09, 0x80, // Usage (System Control) 2
+ * 0xa1, 0x01, // Collection (Application) 4
+ * 0x85, 0x01, // Report ID (1) 6
+ * 0x19, 0x81, // Usage Minimum (129) 8
+ * 0x29, 0x83, // Usage Maximum (131) 10
+ * 0x15, 0x00, // Logical Minimum (0) 12
+ * 0x25, 0x01, // Logical Maximum (1) 14
+ * 0x95, 0x03, // Report Count (3) 16
+ * 0x75, 0x01, // Report Size (1) 18
+ * 0x81, 0x02, // Input (Data,Var,Abs) 20
+ * 0x95, 0x01, // Report Count (1) 22
+ * 0x75, 0x05, // Report Size (5) 24
+ * 0x81, 0x01, // Input (Cnst,Arr,Abs) 26
+ * 0xc0, // End Collection 28
+ * 0x05, 0x0c, // Usage Page (Consumer Devices) 29
+ * 0x09, 0x01, // Usage (Consumer Control) 31
+ * 0xa1, 0x01, // Collection (Application) 33
+ * 0x85, 0x02, // Report ID (2) 35
+ * 0x15, 0x00, // Logical Minimum (0) 37
+ * 0x25, 0x01, // Logical Maximum (1) 39
+ * 0x95, 0x12, // Report Count (18) 41
+ * 0x75, 0x01, // Report Size (1) 43
+ * 0x0a, 0x83, 0x01, // Usage (AL Consumer Control Config) 45
+ * 0x0a, 0x8a, 0x01, // Usage (AL Email Reader) 48
+ * 0x0a, 0x92, 0x01, // Usage (AL Calculator) 51
+ * 0x0a, 0x94, 0x01, // Usage (AL Local Machine Browser) 54
+ * 0x09, 0xcd, // Usage (Play/Pause) 57
+ * 0x09, 0xb7, // Usage (Stop) 59
+ * 0x09, 0xb6, // Usage (Scan Previous Track) 61
+ * 0x09, 0xb5, // Usage (Scan Next Track) 63
+ * 0x09, 0xe2, // Usage (Mute) 65
+ * 0x09, 0xea, // Usage (Volume Down) 67
+ * 0x09, 0xe9, // Usage (Volume Up) 69
+ * 0x0a, 0x21, 0x02, // Usage (AC Search) 71
+ * 0x0a, 0x23, 0x02, // Usage (AC Home) 74
+ * 0x0a, 0x24, 0x02, // Usage (AC Back) 77
+ * 0x0a, 0x25, 0x02, // Usage (AC Forward) 80
+ * 0x0a, 0x26, 0x02, // Usage (AC Stop) 83
+ * 0x0a, 0x27, 0x02, // Usage (AC Refresh) 86
+ * 0x0a, 0x2a, 0x02, // Usage (AC Bookmarks) 89
+ * 0x81, 0x02, // Input (Data,Var,Abs) 92
+ * 0x95, 0x01, // Report Count (1) 94
+ * 0x75, 0x0e, // Report Size (14) 96
+ * 0x81, 0x01, // Input (Cnst,Arr,Abs) 98
+ * 0xc0, // End Collection 100
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 101
+ * 0x09, 0x02, // Usage (Mouse) 103
+ * 0xa1, 0x01, // Collection (Application) 105
+ * 0x09, 0x01, // Usage (Pointer) 107
+ * 0xa1, 0x00, // Collection (Physical) 109
+ * 0x85, 0x03, // Report ID (3) 111
+ * 0x05, 0x09, // Usage Page (Button) 113
+ * 0x19, 0x01, // Usage Minimum (1) 115
+ * 0x29, 0x08, // Usage Maximum (8) 117
+ * 0x15, 0x00, // Logical Minimum (0) 119
+ * 0x25, 0x01, // Logical Maximum (1) 121
+ * 0x75, 0x01, // Report Size (1) 123
+ * 0x95, 0x08, // Report Count (8) 125
+ * 0x81, 0x02, // Input (Data,Var,Abs) 127
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 129
+ * 0x09, 0x30, // Usage (X) 131
+ * 0x09, 0x31, // Usage (Y) 133
+ * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 135
+ * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 138
+ * 0x75, 0x10, // Report Size (16) 141
+ * 0x95, 0x02, // Report Count (2) 143
+ * 0x81, 0x06, // Input (Data,Var,Rel) 145
+ * 0x09, 0x38, // Usage (Wheel) 147
+ * 0x15, 0x81, // Logical Minimum (-127) 149
+ * 0x25, 0x7f, // Logical Maximum (127) 151
+ * 0x75, 0x08, // Report Size (8) 153
+ * 0x95, 0x01, // Report Count (1) 155
+ * 0x81, 0x06, // Input (Data,Var,Rel) 157
+ * 0x05, 0x0c, // Usage Page (Consumer Devices) 159
+ * 0x0a, 0x38, 0x02, // Usage (AC Pan) 161
+ * 0x95, 0x01, // Report Count (1) 164
+ * 0x81, 0x06, // Input (Data,Var,Rel) 166
+ * 0xc0, // End Collection 168
+ * 0xc0, // End Collection 169
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 170
+ * 0x09, 0x06, // Usage (Keyboard) 172
+ * 0xa1, 0x01, // Collection (Application) 174
+ * 0x85, 0x04, // Report ID (4) 176
+ * 0x05, 0x07, // Usage Page (Keyboard) 178
+ * 0x95, 0x01, // Report Count (1) 180
+ * 0x75, 0x08, // Report Size (8) 182
+ * 0x81, 0x03, // Input (Cnst,Var,Abs) 184
+ * 0x95, 0xe8, // Report Count (232) 186
+ * 0x75, 0x01, // Report Size (1) 188
+ * 0x15, 0x00, // Logical Minimum (0) 190
+ * 0x25, 0x01, // Logical Maximum (1) 192
+ * 0x05, 0x07, // Usage Page (Keyboard) 194
+ * 0x19, 0x00, // Usage Minimum (0) 196
+ * 0x29, 0xe7, // Usage Maximum (231) 198
+ * 0x81, 0x00, // Input (Data,Arr,Abs) 200 <- change to 0x81, 0x02 (Data,Var,Abs)
+ * 0xc0, // End Collection 202
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_rdesc_fixup_mistel_md770, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[201] == 0x00)
+ data[201] = 0x02;
+
+ return 0;
+}
+
+HID_BPF_OPS(mistel_md770) = {
+ .hid_rdesc_fixup = (void *)hid_rdesc_fixup_mistel_md770,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != RDESC_SIZE;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/README b/drivers/hid/bpf/progs/README
new file mode 100644
index 000000000..20b0928f3
--- /dev/null
+++ b/drivers/hid/bpf/progs/README
@@ -0,0 +1,102 @@
+# HID-BPF programs
+
+This directory contains various fixes for devices. They add new features or
+fix some behaviors without being entirely mandatory. It is better to load them
+when you have such a device, but they should not be a requirement for a device
+to be working during the boot stage.
+
+The .bpf.c files provided here are not automatically compiled in the kernel.
+They should be loaded in the kernel by `udev-hid-bpf`:
+
+https://gitlab.freedesktop.org/libevdev/udev-hid-bpf
+
+The main reasons for these fixes to be here is to have a central place to
+"upstream" them, but also this way we can test them thanks to the HID
+selftests.
+
+Once a .bpf.c file is accepted here, it is duplicated in `udev-hid-bpf`
+in the `src/bpf/stable` directory, and distributions are encouraged to
+only ship those bpf objects. So adding a file here should eventually
+land in distributions when they update `udev-hid-bpf`
+
+## Compilation
+
+Just run `make`
+
+## Installation
+
+### Automated way
+
+Just run `sudo udev-hid-bpf install ./my-awesome-fix.bpf.o`
+
+### Manual way
+
+- copy the `.bpf.o` you want in `/etc/udev-hid-bpf/`
+- create a new udev rule to automatically load it
+
+The following should do the trick (assuming udev-hid-bpf is available in
+/usr/bin):
+
+```
+$> cp xppen-ArtistPro16Gen2.bpf.o /etc/udev-hid-bpf/
+$> udev-hid-bpf inspect xppen-ArtistPro16Gen2.bpf.o
+[
+ {
+ "name": "xppen-ArtistPro16Gen2.bpf.o",
+ "devices": [
+ {
+ "bus": "0x0003",
+ "group": "0x0001",
+ "vid": "0x28BD",
+ "pid": "0x095A"
+ },
+ {
+ "bus": "0x0003",
+ "group": "0x0001",
+ "vid": "0x28BD",
+ "pid": "0x095B"
+ }
+ ],
+...
+$> cat <EOF > /etc/udev/rules.d/99-load-hid-bpf-xppen-ArtistPro16Gen2.rules
+ACTION!="add|remove", GOTO="hid_bpf_end"
+SUBSYSTEM!="hid", GOTO="hid_bpf_end"
+
+# xppen-ArtistPro16Gen2.bpf.o
+ACTION=="add",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095A", RUN{program}+="/usr/local/bin/udev-hid-bpf add $sys$devpath /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o"
+ACTION=="remove",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095A", RUN{program}+="/usr/local/bin/udev-hid-bpf remove $sys$devpath "
+# xppen-ArtistPro16Gen2.bpf.o
+ACTION=="add",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095B", RUN{program}+="/usr/local/bin/udev-hid-bpf add $sys$devpath /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o"
+ACTION=="remove",ENV{MODALIAS}=="hid:b0003g0001v000028BDp0000095B", RUN{program}+="/usr/local/bin/udev-hid-bpf remove $sys$devpath "
+
+LABEL="hid_bpf_end"
+EOF
+$> udevadm control --reload
+```
+
+Then unplug and replug the device.
+
+## Checks
+
+### udev rule
+
+You can check that the udev rule is correctly working by issuing
+
+```
+$> udevadm test /sys/bus/hid/devices/0003:28BD:095B*
+...
+run: '/usr/local/bin/udev-hid-bpf add /sys/devices/virtual/misc/uhid/0003:28BD:095B.0E57 /etc/udev-hid-bpf/xppen-ArtistPro16Gen2.bpf.o'
+```
+
+### program loaded
+
+You can check that the program has been properly loaded with `bpftool`
+
+```
+$> bpftool prog
+...
+247: tracing name xppen_16_fix_eraser tag 18d389353ed2ef07 gpl
+ loaded_at 2024-03-28T16:02:28+0100 uid 0
+ xlated 120B jited 77B memlock 4096B
+ btf_id 487
+```
diff --git a/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c b/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c
new file mode 100644
index 000000000..6b379e45f
--- /dev/null
+++ b/drivers/hid/bpf/progs/Rapoo__M50-Plus-Silent.bpf.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 José Expósito
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_RAPOO 0x24AE
+#define PID_M50 0x2015
+#define RDESC_SIZE 186
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_RAPOO, PID_M50)
+);
+
+/*
+ * The Rapoo M50 Plus Silent mouse has 2 side buttons in addition to the left,
+ * right and middle buttons. However, its original HID descriptor has a Usage
+ * Maximum of 3, preventing the side buttons to work. This HID-BPF driver
+ * changes that usage to 5.
+ *
+ * For reference, this is the original report descriptor:
+ *
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * 0x09, 0x02, // Usage (Mouse) 2
+ * 0xa1, 0x01, // Collection (Application) 4
+ * 0x85, 0x01, // Report ID (1) 6
+ * 0x09, 0x01, // Usage (Pointer) 8
+ * 0xa1, 0x00, // Collection (Physical) 10
+ * 0x05, 0x09, // Usage Page (Button) 12
+ * 0x19, 0x01, // Usage Minimum (1) 14
+ * 0x29, 0x03, // Usage Maximum (3) 16 <- change to 0x05
+ * 0x15, 0x00, // Logical Minimum (0) 18
+ * 0x25, 0x01, // Logical Maximum (1) 20
+ * 0x75, 0x01, // Report Size (1) 22
+ * 0x95, 0x05, // Report Count (5) 24
+ * 0x81, 0x02, // Input (Data,Var,Abs) 26
+ * 0x75, 0x03, // Report Size (3) 28
+ * 0x95, 0x01, // Report Count (1) 30
+ * 0x81, 0x01, // Input (Cnst,Arr,Abs) 32
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 34
+ * 0x09, 0x30, // Usage (X) 36
+ * 0x09, 0x31, // Usage (Y) 38
+ * 0x16, 0x01, 0x80, // Logical Minimum (-32767) 40
+ * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 43
+ * 0x75, 0x10, // Report Size (16) 46
+ * 0x95, 0x02, // Report Count (2) 48
+ * 0x81, 0x06, // Input (Data,Var,Rel) 50
+ * 0x09, 0x38, // Usage (Wheel) 52
+ * 0x15, 0x81, // Logical Minimum (-127) 54
+ * 0x25, 0x7f, // Logical Maximum (127) 56
+ * 0x75, 0x08, // Report Size (8) 58
+ * 0x95, 0x01, // Report Count (1) 60
+ * 0x81, 0x06, // Input (Data,Var,Rel) 62
+ * 0xc0, // End Collection 64
+ * 0xc0, // End Collection 65
+ * 0x05, 0x0c, // Usage Page (Consumer Devices) 66
+ * 0x09, 0x01, // Usage (Consumer Control) 68
+ * 0xa1, 0x01, // Collection (Application) 70
+ * 0x85, 0x02, // Report ID (2) 72
+ * 0x75, 0x10, // Report Size (16) 74
+ * 0x95, 0x01, // Report Count (1) 76
+ * 0x15, 0x01, // Logical Minimum (1) 78
+ * 0x26, 0x8c, 0x02, // Logical Maximum (652) 80
+ * 0x19, 0x01, // Usage Minimum (1) 83
+ * 0x2a, 0x8c, 0x02, // Usage Maximum (652) 85
+ * 0x81, 0x00, // Input (Data,Arr,Abs) 88
+ * 0xc0, // End Collection 90
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 91
+ * 0x09, 0x80, // Usage (System Control) 93
+ * 0xa1, 0x01, // Collection (Application) 95
+ * 0x85, 0x03, // Report ID (3) 97
+ * 0x09, 0x82, // Usage (System Sleep) 99
+ * 0x09, 0x81, // Usage (System Power Down) 101
+ * 0x09, 0x83, // Usage (System Wake Up) 103
+ * 0x15, 0x00, // Logical Minimum (0) 105
+ * 0x25, 0x01, // Logical Maximum (1) 107
+ * 0x19, 0x01, // Usage Minimum (1) 109
+ * 0x29, 0x03, // Usage Maximum (3) 111
+ * 0x75, 0x01, // Report Size (1) 113
+ * 0x95, 0x03, // Report Count (3) 115
+ * 0x81, 0x02, // Input (Data,Var,Abs) 117
+ * 0x95, 0x05, // Report Count (5) 119
+ * 0x81, 0x01, // Input (Cnst,Arr,Abs) 121
+ * 0xc0, // End Collection 123
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 124
+ * 0x09, 0x00, // Usage (Undefined) 126
+ * 0xa1, 0x01, // Collection (Application) 128
+ * 0x85, 0x05, // Report ID (5) 130
+ * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 132
+ * 0x09, 0x01, // Usage (Vendor Usage 1) 135
+ * 0x15, 0x81, // Logical Minimum (-127) 137
+ * 0x25, 0x7f, // Logical Maximum (127) 139
+ * 0x75, 0x08, // Report Size (8) 141
+ * 0x95, 0x07, // Report Count (7) 143
+ * 0xb1, 0x02, // Feature (Data,Var,Abs) 145
+ * 0xc0, // End Collection 147
+ * 0x06, 0x00, 0xff, // Usage Page (Vendor Defined Page 1) 148
+ * 0x09, 0x0e, // Usage (Vendor Usage 0x0e) 151
+ * 0xa1, 0x01, // Collection (Application) 153
+ * 0x85, 0xba, // Report ID (186) 155
+ * 0x95, 0x1f, // Report Count (31) 157
+ * 0x75, 0x08, // Report Size (8) 159
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 161
+ * 0x15, 0x00, // Logical Minimum (0) 164
+ * 0x09, 0x01, // Usage (Vendor Usage 1) 166
+ * 0x91, 0x02, // Output (Data,Var,Abs) 168
+ * 0x85, 0xba, // Report ID (186) 170
+ * 0x95, 0x1f, // Report Count (31) 172
+ * 0x75, 0x08, // Report Size (8) 174
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 176
+ * 0x15, 0x00, // Logical Minimum (0) 179
+ * 0x09, 0x01, // Usage (Vendor Usage 1) 181
+ * 0x81, 0x02, // Input (Data,Var,Abs) 183
+ * 0xc0, // End Collection 185
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_rdesc_fixup_rapoo_m50, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[17] == 0x03)
+ data[17] = 0x05;
+
+ return 0;
+}
+
+HID_BPF_OPS(rapoo_m50) = {
+ .hid_rdesc_fixup = (void *)hid_rdesc_fixup_rapoo_m50,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != RDESC_SIZE;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/TUXEDO__Sirius-16-Gen1-and-Gen2.bpf.c b/drivers/hid/bpf/progs/TUXEDO__Sirius-16-Gen1-and-Gen2.bpf.c
new file mode 100644
index 000000000..a123003fb
--- /dev/null
+++ b/drivers/hid/bpf/progs/TUXEDO__Sirius-16-Gen1-and-Gen2.bpf.c
@@ -0,0 +1,47 @@
+// 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";
diff --git a/drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c b/drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c
new file mode 100644
index 000000000..ecf775a99
--- /dev/null
+++ b/drivers/hid/bpf/progs/Thrustmaster__TCA-Yoke-Boeing.bpf.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 Kumar Swarnam Iyer (kumar.s.iyer65@gmail.com)
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_THRUSTMASTER 0x044F
+#define PID_TCA_YOKE_BOEING 0x0409
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_THRUSTMASTER, PID_TCA_YOKE_BOEING)
+);
+
+/* The original HID descriptor of the Thrustmaster TCA Yoke Boeing joystick contains
+ * an Input field that shows up as an axis, ABS_MISC in Linux. But it is not possible
+ * to assign an actual physical control to this axis as they're all taken up. There
+ * are 2 vendor-defined inputs where the Input type appears to be defined wrongly.
+ * This bpf attempts to fix this by changing the Inputs so that it doesn't show up in
+ * Linux at all.
+ * This version is the short version fix that only changes 2 fields in the descriptor
+ * instead of the whole report descriptor.
+ * For reference, this is the original report descriptor:
+ *
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 0
+ * 0x09, 0x04, // Usage (Joystick) 2
+ * 0xa1, 0x01, // Collection (Application) 4
+ * 0x85, 0x01, // Report ID (1) 6
+ * 0x09, 0x39, // Usage (Hat switch) 8
+ * 0x15, 0x00, // Logical Minimum (0) 10
+ * 0x25, 0x07, // Logical Maximum (7) 12
+ * 0x35, 0x00, // Physical Minimum (0) 14
+ * 0x46, 0x3b, 0x01, // Physical Maximum (315) 16
+ * 0x65, 0x14, // Unit (EnglishRotation: deg) 19
+ * 0x75, 0x04, // Report Size (4) 21
+ * 0x95, 0x01, // Report Count (1) 23
+ * 0x81, 0x42, // Input (Data,Var,Abs,Null) 25
+ * 0x65, 0x00, // Unit (None) 27
+ * 0x05, 0x09, // Usage Page (Button) 29
+ * 0x19, 0x01, // Usage Minimum (1) 31
+ * 0x29, 0x12, // Usage Maximum (18) 33
+ * 0x15, 0x00, // Logical Minimum (0) 35
+ * 0x25, 0x01, // Logical Maximum (1) 37
+ * 0x75, 0x01, // Report Size (1) 39
+ * 0x95, 0x12, // Report Count (18) 41
+ * 0x81, 0x02, // Input (Data,Var,Abs) 43
+ * 0x95, 0x02, // Report Count (2) 45
+ * 0x81, 0x03, // Input (Cnst,Var,Abs) 47
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 49
+ * 0x09, 0x31, // Usage (Y) 51
+ * 0x09, 0x30, // Usage (X) 53
+ * 0x09, 0x32, // Usage (Z) 55
+ * 0x09, 0x34, // Usage (Ry) 57
+ * 0x09, 0x33, // Usage (Rx) 59
+ * 0x09, 0x35, // Usage (Rz) 61
+ * 0x15, 0x00, // Logical Minimum (0) 63
+ * 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 65
+ * 0x75, 0x10, // Report Size (16) 70
+ * 0x95, 0x06, // Report Count (6) 72
+ * 0x81, 0x02, // Input (Data,Var,Abs) 74
+ * 0x06, 0xf0, 0xff, // Usage Page (Vendor Usage Page 0xfff0) 76
+ * 0x09, 0x59, // Usage (Vendor Usage 0x59) 79
+ * 0x15, 0x00, // Logical Minimum (0) 81
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 83
+ * 0x75, 0x08, // Report Size (8) 86
+ * 0x95, 0x01, // Report Count (1) 88
+ * 0x81, 0x02, // Input (Data,Var,Abs) 90 --> Needs to be changed
+ * 0x09, 0x51, // Usage (Vendor Usage 0x51) 92
+ * 0x15, 0x00, // Logical Minimum (0) 94
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 96
+ * 0x75, 0x08, // Report Size (8) 99
+ * 0x95, 0x20, // Report Count (32) 101 --> Needs to be changed
+ * 0x81, 0x02, // Input (Data,Var,Abs) 103
+ * 0x09, 0x50, // Usage (Vendor Usage 0x50) 105
+ * 0x15, 0x00, // Logical Minimum (0) 107
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 109
+ * 0x75, 0x08, // Report Size (8) 112
+ * 0x95, 0x0f, // Report Count (15) 114
+ * 0x81, 0x03, // Input (Cnst,Var,Abs) 116
+ * 0x09, 0x47, // Usage (Vendor Usage 0x47) 118
+ * 0x85, 0xf2, // Report ID (242) 120
+ * 0x15, 0x00, // Logical Minimum (0) 122
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 124
+ * 0x75, 0x08, // Report Size (8) 127
+ * 0x95, 0x3f, // Report Count (63) 129
+ * 0xb1, 0x02, // Feature (Data,Var,Abs) 131
+ * 0x09, 0x48, // Usage (Vendor Usage 0x48) 133
+ * 0x85, 0xf3, // Report ID (243) 135
+ * 0x15, 0x00, // Logical Minimum (0) 137
+ * 0x26, 0xff, 0x00, // Logical Maximum (255) 139
+ * 0x75, 0x08, // Report Size (8) 142
+ * 0x95, 0x3f, // Report Count (63) 144
+ * 0xb1, 0x02, // Feature (Data,Var,Abs) 146
+ * 0xc0, // End Collection 148
+ */
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_tca_yoke, struct hid_bpf_ctx *hctx)
+{
+ const int expected_length = 148;
+
+ if (hctx->size != expected_length)
+ return 0;
+
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+
+ if (!data)
+ return 0; /* EPERM */
+
+ /* Safety check, our probe() should take care of this though */
+ if (data[1] != 0x01 /* Generic Desktop */ || data[3] != 0x04 /* Joystick */)
+ return 0;
+
+ /* The report descriptor sets incorrect Input items in 2 places, resulting in a
+ * non-existing axis showing up.
+ * This change sets the correct Input which prevents the axis from showing up in Linux.
+ */
+
+ if (data[90] == 0x81 && /* Input */
+ data[103] == 0x81) { /* Input */
+ data[91] = 0x03; /* Input set to 0x03 Constant, Variable Absolute */
+ data[104] = 0x03; /* Input set to 0X03 Constant, Variable Absolute */
+ }
+
+ return 0;
+}
+
+HID_BPF_OPS(tca_yoke) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_tca_yoke,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /* ensure the kernel isn't fixed already */
+ if (ctx->rdesc[91] != 0x02) /* Input for 0x59 Usage type has changed */
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Trust__Philips-SPK6327.bpf.c b/drivers/hid/bpf/progs/Trust__Philips-SPK6327.bpf.c
new file mode 100644
index 000000000..bc7ff27ea
--- /dev/null
+++ b/drivers/hid/bpf/progs/Trust__Philips-SPK6327.bpf.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Fix for Trust Philips SPK6327 (145f:024b)
+ * Modifier keys report as Array (0x00) instead of Variable (0x02)
+ * causing LCtrl, LAlt, Super etc. to all act as LShift
+ */
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_TRUST 0x145F
+#define PID_SPK6327 0x024B
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_TRUST, PID_SPK6327)
+);
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, 4096);
+
+ if (!data)
+ return 0;
+
+ /* Fix modifier keys: Input Array (0x00) -> Input Variable (0x02) */
+ if (data[101] == 0x00)
+ data[101] = 0x02;
+
+ return 0;
+}
+
+HID_BPF_OPS(trust_spk6327) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /* Only apply to interface 1 (169 bytes) not interface 0 (62 bytes) */
+ if (ctx->rdesc_size == 169)
+ ctx->retval = 0;
+ else
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c b/drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c
new file mode 100644
index 000000000..156d75af5
--- /dev/null
+++ b/drivers/hid/bpf/progs/WALTOP__Batteryless-Tablet.bpf.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Red Hat
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_WALTOP 0x172F
+#define PID_BATTERYLESS_TABLET 0x0505
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_ANY, VID_WALTOP, PID_BATTERYLESS_TABLET)
+);
+
+#define EXPECTED_RDESC_SIZE 335
+#define PEN_REPORT_ID 16
+
+#define TIP_SWITCH BIT(0)
+#define BARREL_SWITCH BIT(1)
+#define SECONDARY_BARREL_SWITCH BIT(5)
+
+static __u8 last_button_state;
+
+static const __u8 fixed_rdesc[] = {
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x02, // Usage (Mouse)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x01, // Report ID (1)
+ 0x09, 0x01, // Usage (Pointer)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x05, 0x09, // Usage Page (Button)
+ 0x19, 0x01, // Usage Minimum (1)
+ 0x29, 0x05, // Usage Maximum (5)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x05, // Report Count (5)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x75, 0x03, // Report Size (3)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x03, // Input (Cnst,Var,Abs)
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x30, // Usage (X)
+ 0x09, 0x31, // Usage (Y)
+ 0x09, 0x38, // Usage (Wheel)
+ 0x15, 0x81, // Logical Minimum (-127)
+ 0x25, 0x7f, // Logical Maximum (127)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x03, // Report Count (3)
+ 0x81, 0x06, // Input (Data,Var,Rel)
+ 0x05, 0x0c, // Usage Page (Consumer)
+ 0x15, 0x81, // Logical Minimum (-127)
+ 0x25, 0x7f, // Logical Maximum (127)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x01, // Report Count (1)
+ 0x0a, 0x38, 0x02, // Usage (AC Pan)
+ 0x81, 0x06, // Input (Data,Var,Rel)
+ 0xc0, // End Collection
+ 0xc0, // End Collection
+ 0x05, 0x0d, // Usage Page (Digitizers)
+ 0x09, 0x02, // Usage (Pen)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x02, // Report ID (2)
+ 0x09, 0x20, // Usage (Stylus)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x09, 0x00, // Usage (0x0000)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x09, // Report Count (9)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x09, 0x3f, // Usage (Azimuth)
+ 0x09, 0x40, // Usage (Altitude)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x02, // Report Count (2)
+ 0xb1, 0x02, // Feature (Data,Var,Abs)
+ 0xc0, // End Collection
+ 0x85, 0x05, // Report ID (5)
+ 0x05, 0x0d, // Usage Page (Digitizers)
+ 0x09, 0x20, // Usage (Stylus)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x09, 0x00, // Usage (0x0000)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x07, // Report Count (7)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0xc0, // End Collection
+ 0x85, 0x0a, // Report ID (10)
+ 0x05, 0x0d, // Usage Page (Digitizers)
+ 0x09, 0x20, // Usage (Stylus)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x09, 0x00, // Usage (0x0000)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x00, // Logical Maximum (255)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x07, // Report Count (7)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0xc0, // End Collection
+ 0x85, 0x10, // Report ID (16)
+ 0x09, 0x20, // Usage (Stylus)
+ 0xa1, 0x00, // Collection (Physical)
+ 0x09, 0x42, // Usage (Tip Switch)
+ 0x09, 0x44, // Usage (Barrel Switch)
+ 0x09, 0x3c, // Usage (Invert)
+ 0x09, 0x45, // Usage (Eraser)
+ 0x09, 0x32, // Usage (In Range)
+ 0x09, 0x5a, // Usage (Secondary Barrel Switch) <-- added
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x06, // Report Count (6) <--- changed from 5
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x95, 0x02, // Report Count (2) <--- changed from 3
+ 0x81, 0x03, // Input (Cnst,Var,Abs)
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x30, // Usage (X)
+ 0x75, 0x10, // Report Size (16)
+ 0x95, 0x01, // Report Count (1)
+ 0xa4, // Push
+ 0x55, 0x0d, // Unit Exponent (-3)
+ 0x65, 0x33, // Unit (EnglishLinear: in³)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0x00, 0x7d, // Logical Maximum (32000)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0x00, 0x7d, // Physical Maximum (32000)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x09, 0x31, // Usage (Y)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0x20, 0x4e, // Logical Maximum (20000)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0x20, 0x4e, // Physical Maximum (20000)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x05, 0x0d, // Usage Page (Digitizers)
+ 0x09, 0x30, // Usage (Tip Pressure)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x26, 0xff, 0x07, // Logical Maximum (2047)
+ 0x35, 0x00, // Physical Minimum (0)
+ 0x46, 0xff, 0x07, // Physical Maximum (2047)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x05, 0x0d, // Usage Page (Digitizers)
+ 0x09, 0x3d, // Usage (X Tilt)
+ 0x09, 0x3e, // Usage (Y Tilt)
+ 0x15, 0xc4, // Logical Minimum (-60) <- changed from -127
+ 0x25, 0x3c, // Logical Maximum (60) <- changed from 127
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x02, // Report Count (2)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0xc0, // End Collection
+ 0xc0, // End Collection
+ 0x05, 0x01, // Usage Page (Generic Desktop)
+ 0x09, 0x06, // Usage (Keyboard)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x0d, // Report ID (13)
+ 0x05, 0x07, // Usage Page (Keyboard/Keypad)
+ 0x19, 0xe0, // Usage Minimum (224)
+ 0x29, 0xe7, // Usage Maximum (231)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Data,Var,Abs)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x01, // Input (Cnst,Arr,Abs)
+ 0x05, 0x07, // Usage Page (Keyboard/Keypad)
+ 0x19, 0x00, // Usage Minimum (0)
+ 0x29, 0x65, // Usage Maximum (101)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x65, // Logical Maximum (101)
+ 0x75, 0x08, // Report Size (8)
+ 0x95, 0x05, // Report Count (5)
+ 0x81, 0x00, // Input (Data,Arr,Abs)
+ 0xc0, // End Collection
+ 0x05, 0x0c, // Usage Page (Consumer)
+ 0x09, 0x01, // Usage (Consumer Control)
+ 0xa1, 0x01, // Collection (Application)
+ 0x85, 0x0c, // Report ID (12)
+ 0x09, 0xe9, // Usage (Volume Increment)
+ 0x09, 0xea, // Usage (Volume Decrement)
+ 0x09, 0xe2, // Usage (Mute)
+ 0x15, 0x00, // Logical Minimum (0)
+ 0x25, 0x01, // Logical Maximum (1)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x03, // Report Count (3)
+ 0x81, 0x06, // Input (Data,Var,Rel)
+ 0x75, 0x05, // Report Size (5)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x07, // Input (Cnst,Var,Rel)
+ 0xc0, // End Collection
+};
+
+static inline unsigned int bitwidth32(__u32 x)
+{
+ return 32 - __builtin_clzg(x, 32);
+}
+
+static inline unsigned int floor_log2_32(__u32 x)
+{
+ return bitwidth32(x) - 1;
+}
+
+/* Maps the interval [0, 2047] to itself using a scaled
+ * approximation of the function log2(x+1).
+ */
+static unsigned int scaled_log2(__u16 v)
+{
+ const unsigned int XMAX = 2047;
+ const unsigned int YMAX = 11; /* log2(2048) = 11 */
+
+ unsigned int x = v + 1;
+ unsigned int n = floor_log2_32(x);
+ unsigned int b = 1 << n;
+
+ /* Fixed-point fraction in [0, 1), linearly
+ * interpolated using delta-y = 1 and
+ * delta-x = (2b - b) = b.
+ */
+ unsigned int frac = (x - b) << YMAX;
+ unsigned int lerp = frac / b;
+ unsigned int log2 = (n << YMAX) + lerp;
+
+ return ((log2 * XMAX) / YMAX) >> YMAX;
+}
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc));
+
+ return sizeof(fixed_rdesc);
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(waltop_fix_events, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ __u8 report_id = data[0];
+
+ if (report_id != PEN_REPORT_ID)
+ return 0;
+
+ /* On this tablet if the secondary barrel switch is pressed,
+ * the tablet sends tip down and barrel down. Change this to
+ * just secondary barrel down when there is no ambiguity.
+ *
+ * It's possible that there is a bug in the firmware and the
+ * device intends to set invert + eraser instead (i.e. the
+ * pysical button is an eraser button) but since
+ * the pressure is always zero, said eraser button
+ * would be useless anyway.
+ *
+ * So let's just change the button to secondary barrel down.
+ */
+
+ __u8 tip_switch = data[1] & TIP_SWITCH;
+ __u8 barrel_switch = data[1] & BARREL_SWITCH;
+
+ __u8 tip_held = last_button_state & TIP_SWITCH;
+ __u8 barrel_held = last_button_state & BARREL_SWITCH;
+
+ if (tip_switch && barrel_switch && !tip_held && !barrel_held) {
+ data[1] &= ~(TIP_SWITCH | BARREL_SWITCH); /* release tip and barrel */
+ data[1] |= SECONDARY_BARREL_SWITCH; /* set secondary barrel switch */
+ }
+
+ last_button_state = data[1];
+
+ /* The pressure sensor on this tablet maps around half of the
+ * logical pressure range into the interval [0-100]. Further
+ * pressure causes the sensor value to increase exponentially
+ * up to a maximum value of 2047.
+ *
+ * The values 12 and 102 were chosen to have an integer slope
+ * with smooth transition between the two curves around the
+ * value 100.
+ */
+
+ __u16 pressure = (((__u16)data[6]) << 0) | (((__u16)data[7]) << 8);
+
+ if (pressure <= 102)
+ pressure *= 12;
+ else
+ pressure = scaled_log2(pressure);
+
+ data[6] = pressure >> 0;
+ data[7] = pressure >> 8;
+
+ return 0;
+}
+
+HID_BPF_OPS(waltop_batteryless) = {
+ .hid_device_event = (void *)waltop_fix_events,
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ if (ctx->rdesc_size == EXPECTED_RDESC_SIZE)
+ ctx->retval = 0;
+ else
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c
new file mode 100644
index 000000000..ed60a660c
--- /dev/null
+++ b/drivers/hid/bpf/progs/Wacom__ArtPen.bpf.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_WACOM 0x056a
+#define ART_PEN_ID 0x0804
+#define PID_INTUOS_PRO_2_M 0x0357
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_WACOM, PID_INTUOS_PRO_2_M)
+);
+
+/*
+ * This filter is here for the Art Pen stylus only:
+ * - when used on some Wacom devices (see the list of attached PIDs), this pen
+ * reports pressure every other events.
+ * - to solve that, given that we know that the next event will be the same as
+ * the current one, we can emulate a smoother pressure reporting by reporting
+ * the mean of the previous value and the current one.
+ *
+ * We are effectively delaying the pressure by one event every other event, but
+ * that's less of an annoyance compared to the chunkiness of the reported data.
+ *
+ * For example, let's assume the following set of events:
+ * <Tip switch 0> <X 0> <Y 0> <Pressure 0 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 1> <Y 1> <Pressure 100 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 2> <Y 2> <Pressure 100 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 3> <Y 3> <Pressure 200 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 4> <Y 4> <Pressure 200 > <Tooltype 0x0804>
+ * <Tip switch 0> <X 5> <Y 5> <Pressure 0 > <Tooltype 0x0804>
+ *
+ * The filter will report:
+ * <Tip switch 0> <X 0> <Y 0> <Pressure 0 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 1> <Y 1> <Pressure * 50*> <Tooltype 0x0804>
+ * <Tip switch 1> <X 2> <Y 2> <Pressure 100 > <Tooltype 0x0804>
+ * <Tip switch 1> <X 3> <Y 3> <Pressure *150*> <Tooltype 0x0804>
+ * <Tip switch 1> <X 4> <Y 4> <Pressure 200 > <Tooltype 0x0804>
+ * <Tip switch 0> <X 5> <Y 5> <Pressure 0 > <Tooltype 0x0804>
+ *
+ */
+
+struct wacom_params {
+ __u16 pid;
+ __u16 rdesc_len;
+ __u8 report_id;
+ __u8 report_len;
+ struct {
+ __u8 tip_switch;
+ __u8 pressure;
+ __u8 tool_type;
+ } offsets;
+};
+
+/*
+ * Multiple device can support the same stylus, so
+ * we need to know which device has which offsets
+ */
+static const struct wacom_params devices[] = {
+ {
+ .pid = PID_INTUOS_PRO_2_M,
+ .rdesc_len = 949,
+ .report_id = 16,
+ .report_len = 27,
+ .offsets = {
+ .tip_switch = 1,
+ .pressure = 8,
+ .tool_type = 25,
+ },
+ },
+};
+
+static struct wacom_params params = { 0 };
+
+/* HID-BPF reports a 64 bytes chunk anyway, so this ensures
+ * the verifier to know we are addressing the memory correctly
+ */
+#define PEN_REPORT_LEN 64
+
+/* only odd frames are modified */
+static bool odd;
+
+static __u16 prev_pressure;
+
+static inline void *get_bits(__u8 *data, unsigned int byte_offset)
+{
+ return data + byte_offset;
+}
+
+static inline __u16 *get_u16(__u8 *data, unsigned int offset)
+{
+ return (__u16 *)get_bits(data, offset);
+}
+
+static inline __u8 *get_u8(__u8 *data, unsigned int offset)
+{
+ return (__u8 *)get_bits(data, offset);
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(artpen_pressure_interpolate, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PEN_REPORT_LEN /* size */);
+ __u16 *pressure, *tool_type;
+ __u8 *tip_switch;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[0] != params.report_id ||
+ params.offsets.tip_switch >= PEN_REPORT_LEN ||
+ params.offsets.pressure >= PEN_REPORT_LEN - 1 ||
+ params.offsets.tool_type >= PEN_REPORT_LEN - 1)
+ return 0; /* invalid report or parameters */
+
+ tool_type = get_u16(data, params.offsets.tool_type);
+ if (*tool_type != ART_PEN_ID)
+ return 0;
+
+ tip_switch = get_u8(data, params.offsets.tip_switch);
+ if ((*tip_switch & 0x01) == 0) {
+ prev_pressure = 0;
+ odd = true;
+ return 0;
+ }
+
+ pressure = get_u16(data, params.offsets.pressure);
+
+ if (odd)
+ *pressure = (*pressure + prev_pressure) / 2;
+
+ prev_pressure = *pressure;
+ odd = !odd;
+
+ return 0;
+}
+
+HID_BPF_OPS(wacom_artpen) = {
+ .hid_device_event = (void *)artpen_pressure_interpolate,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ struct hid_bpf_ctx *hid_ctx;
+ __u16 pid;
+ size_t i;
+
+ /* get a struct hid_device to access the actual pid of the device */
+ hid_ctx = hid_bpf_allocate_context(ctx->hid);
+ if (!hid_ctx) {
+ ctx->retval = -ENODEV;
+ return -1; /* EPERM check */
+ }
+ pid = hid_ctx->hid->product;
+
+ ctx->retval = -EINVAL;
+
+ /* Match the given device with the list of known devices */
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ const struct wacom_params *device = &devices[i];
+
+ if (device->pid == pid && device->rdesc_len == ctx->rdesc_size) {
+ params = *device;
+ ctx->retval = 0;
+ }
+ }
+
+ hid_bpf_release_context(hid_ctx);
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/XPPen__ACK05.bpf.c b/drivers/hid/bpf/progs/XPPen__ACK05.bpf.c
new file mode 100644
index 000000000..a754710fc
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__ACK05.bpf.c
@@ -0,0 +1,331 @@
+// 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
+ UsagePage_Digitizers
+ 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";
diff --git a/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c
new file mode 100644
index 000000000..c24fe905c
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__Artist24.bpf.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2023 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */
+#define PID_ARTIST_24 0x093A
+#define PID_ARTIST_24_PRO 0x092D
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_24),
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_ARTIST_24_PRO)
+);
+
+/*
+ * We need to amend the report descriptor for the following:
+ * - the device reports Eraser instead of using Secondary Barrel Switch
+ * - the pen doesn't have a rubber tail, so basically we are removing any
+ * eraser/invert bits
+ */
+static const __u8 fixed_rdesc[] = {
+ 0x05, 0x0d, // Usage Page (Digitizers) 0
+ 0x09, 0x02, // Usage (Pen) 2
+ 0xa1, 0x01, // Collection (Application) 4
+ 0x85, 0x07, // Report ID (7) 6
+ 0x09, 0x20, // Usage (Stylus) 8
+ 0xa1, 0x00, // Collection (Physical) 10
+ 0x09, 0x42, // Usage (Tip Switch) 12
+ 0x09, 0x44, // Usage (Barrel Switch) 14
+ 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from 0x45 (Eraser) to 0x5a (Secondary Barrel Switch) */
+ 0x15, 0x00, // Logical Minimum (0) 18
+ 0x25, 0x01, // Logical Maximum (1) 20
+ 0x75, 0x01, // Report Size (1) 22
+ 0x95, 0x03, // Report Count (3) 24
+ 0x81, 0x02, // Input (Data,Var,Abs) 26
+ 0x95, 0x02, // Report Count (2) 28
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 30
+ 0x09, 0x32, // Usage (In Range) 32
+ 0x95, 0x01, // Report Count (1) 34
+ 0x81, 0x02, // Input (Data,Var,Abs) 36
+ 0x95, 0x02, // Report Count (2) 38
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 40
+ 0x75, 0x10, // Report Size (16) 42
+ 0x95, 0x01, // Report Count (1) 44
+ 0x35, 0x00, // Physical Minimum (0) 46
+ 0xa4, // Push 48
+ 0x05, 0x01, // Usage Page (Generic Desktop) 49
+ 0x09, 0x30, // Usage (X) 51
+ 0x65, 0x13, // Unit (EnglishLinear: in) 53
+ 0x55, 0x0d, // Unit Exponent (-3) 55
+ 0x46, 0xf0, 0x50, // Physical Maximum (20720) 57
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 60
+ 0x81, 0x02, // Input (Data,Var,Abs) 63
+ 0x09, 0x31, // Usage (Y) 65
+ 0x46, 0x91, 0x2d, // Physical Maximum (11665) 67
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 70
+ 0x81, 0x02, // Input (Data,Var,Abs) 73
+ 0xb4, // Pop 75
+ 0x09, 0x30, // Usage (Tip Pressure) 76
+ 0x45, 0x00, // Physical Maximum (0) 78
+ 0x26, 0xff, 0x1f, // Logical Maximum (8191) 80
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 83
+ 0x09, 0x3d, // Usage (X Tilt) 85
+ 0x15, 0x81, // Logical Minimum (-127) 87
+ 0x25, 0x7f, // Logical Maximum (127) 89
+ 0x75, 0x08, // Report Size (8) 91
+ 0x95, 0x01, // Report Count (1) 93
+ 0x81, 0x02, // Input (Data,Var,Abs) 95
+ 0x09, 0x3e, // Usage (Y Tilt) 97
+ 0x15, 0x81, // Logical Minimum (-127) 99
+ 0x25, 0x7f, // Logical Maximum (127) 101
+ 0x81, 0x02, // Input (Data,Var,Abs) 103
+ 0xc0, // End Collection 105
+ 0xc0, // End Collection 106
+};
+
+#define TIP_SWITCH BIT(0)
+#define BARREL_SWITCH BIT(1)
+#define ERASER BIT(2)
+/* padding BIT(3) */
+/* padding BIT(4) */
+#define IN_RANGE BIT(5)
+/* padding BIT(6) */
+/* padding BIT(7) */
+
+#define U16(index) (data[index] | (data[index + 1] << 8))
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_xppen_artist24, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc));
+
+ return sizeof(fixed_rdesc);
+}
+
+static __u8 prev_state = 0;
+
+/*
+ * There are a few cases where the device is sending wrong event
+ * sequences, all related to the second button (the pen doesn't
+ * have an eraser switch on the tail end):
+ *
+ * whenever the second button gets pressed or released, an
+ * out-of-proximity event is generated and then the firmware
+ * compensate for the missing state (and the firmware uses
+ * eraser for that button):
+ *
+ * - if the pen is in range, an extra out-of-range is sent
+ * when the second button is pressed/released:
+ * // Pen is in range
+ * E: InRange
+ *
+ * // Second button is pressed
+ * E:
+ * E: Eraser InRange
+ *
+ * // Second button is released
+ * E:
+ * E: InRange
+ *
+ * This case is ignored by this filter, it's "valid"
+ * and userspace knows how to deal with it, there are just
+ * a few out-of-prox events generated, but the user doesn´t
+ * see them.
+ *
+ * - if the pen is in contact, 2 extra events are added when
+ * the second button is pressed/released: an out of range
+ * and an in range:
+ *
+ * // Pen is in contact
+ * E: TipSwitch InRange
+ *
+ * // Second button is pressed
+ * E: <- false release, needs to be filtered out
+ * E: Eraser InRange <- false release, needs to be filtered out
+ * E: TipSwitch Eraser InRange
+ *
+ * // Second button is released
+ * E: <- false release, needs to be filtered out
+ * E: InRange <- false release, needs to be filtered out
+ * E: TipSwitch InRange
+ *
+ */
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(xppen_24_fix_eraser, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+ __u8 current_state, changed_state;
+ bool prev_tip;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ current_state = data[1];
+
+ /* if the state is identical to previously, early return */
+ if (current_state == prev_state)
+ return 0;
+
+ prev_tip = !!(prev_state & TIP_SWITCH);
+
+ /*
+ * Illegal transition: pen is in range with the tip pressed, and
+ * it goes into out of proximity.
+ *
+ * Ideally we should hold the event, start a timer and deliver it
+ * only if the timer ends, but we are not capable of that now.
+ *
+ * And it doesn't matter because when we are in such cases, this
+ * means we are detecting a false release.
+ */
+ if ((current_state & IN_RANGE) == 0) {
+ if (prev_tip)
+ return HID_IGNORE_EVENT;
+ return 0;
+ }
+
+ /*
+ * XOR to only set the bits that have changed between
+ * previous and current state
+ */
+ changed_state = prev_state ^ current_state;
+
+ /* Store the new state for future processing */
+ prev_state = current_state;
+
+ /*
+ * We get both a tipswitch and eraser change in the same HID report:
+ * this is not an authorized transition and is unlikely to happen
+ * in real life.
+ * This is likely to be added by the firmware to emulate the
+ * eraser mode so we can skip the event.
+ */
+ if ((changed_state & (TIP_SWITCH | ERASER)) == (TIP_SWITCH | ERASER)) /* we get both a tipswitch and eraser change at the same time */
+ return HID_IGNORE_EVENT;
+
+ return 0;
+}
+
+HID_BPF_OPS(xppen_artist_24) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_xppen_artist24,
+ .hid_device_event = (void *)xppen_24_fix_eraser,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /*
+ * The device exports 3 interfaces.
+ */
+ ctx->retval = ctx->rdesc_size != 107;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ /* ensure the kernel isn't fixed already */
+ if (ctx->rdesc[17] != 0x45) /* Eraser */
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c
new file mode 100644
index 000000000..0c7e5cc5d
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__ArtistPro16Gen2.bpf.c
@@ -0,0 +1,324 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2023 Benjamin Tissoires
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#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_PRO19_GEN2)
+);
+
+/*
+ * We need to amend the report descriptor for the following:
+ * - the device reports Eraser instead of using Secondary Barrel Switch
+ * - 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 the physical dimensions of the 16" device.
+ */
+static const __u8 fixed_rdesc[] = {
+ 0x05, 0x0d, // Usage Page (Digitizers) 0
+ 0x09, 0x02, // Usage (Pen) 2
+ 0xa1, 0x01, // Collection (Application) 4
+ 0x85, 0x07, // Report ID (7) 6
+ 0x09, 0x20, // Usage (Stylus) 8
+ 0xa1, 0x00, // Collection (Physical) 10
+ 0x09, 0x42, // Usage (Tip Switch) 12
+ 0x09, 0x44, // Usage (Barrel Switch) 14
+ 0x09, 0x5a, // Usage (Secondary Barrel Switch) 16 /* changed from 0x45 (Eraser) to 0x5a (Secondary Barrel Switch) */
+ 0x09, 0x3c, // Usage (Invert) 18
+ 0x09, 0x45, // Usage (Eraser) 16 /* created over a padding bit at offset 29-33 */
+ 0x15, 0x00, // Logical Minimum (0) 20
+ 0x25, 0x01, // Logical Maximum (1) 22
+ 0x75, 0x01, // Report Size (1) 24
+ 0x95, 0x05, // Report Count (5) 26 /* changed from 4 to 5 */
+ 0x81, 0x02, // Input (Data,Var,Abs) 28
+ 0x09, 0x32, // Usage (In Range) 34
+ 0x15, 0x00, // Logical Minimum (0) 36
+ 0x25, 0x01, // Logical Maximum (1) 38
+ 0x95, 0x01, // Report Count (1) 40
+ 0x81, 0x02, // Input (Data,Var,Abs) 42
+ 0x95, 0x02, // Report Count (2) 44
+ 0x81, 0x03, // Input (Cnst,Var,Abs) 46
+ 0x75, 0x10, // Report Size (16) 48
+ 0x95, 0x01, // Report Count (1) 50
+ 0x35, 0x00, // Physical Minimum (0) 52
+ 0xa4, // Push 54
+ 0x05, 0x01, // Usage Page (Generic Desktop) 55
+ 0x09, 0x30, // Usage (X) 57
+ 0x65, 0x13, // Unit (EnglishLinear: in) 59
+ 0x55, 0x0d, // Unit Exponent (-3) 61
+ 0x46, 0xff, 0x34, // Physical Maximum (13567) 63
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 66
+ 0x81, 0x02, // Input (Data,Var,Abs) 69
+ 0x09, 0x31, // Usage (Y) 71
+ 0x46, 0x20, 0x21, // Physical Maximum (8480) 73
+ 0x26, 0xff, 0x7f, // Logical Maximum (32767) 76
+ 0x81, 0x02, // Input (Data,Var,Abs) 79
+ 0xb4, // Pop 81
+ 0x09, 0x30, // Usage (Tip Pressure) 82
+ 0x45, 0x00, // Physical Maximum (0) 84
+ 0x26, 0xff, 0x3f, // Logical Maximum (16383) 86
+ 0x81, 0x42, // Input (Data,Var,Abs,Null) 89
+ 0x09, 0x3d, // Usage (X Tilt) 91
+ 0x15, 0x81, // Logical Minimum (-127) 93
+ 0x25, 0x7f, // Logical Maximum (127) 95
+ 0x75, 0x08, // Report Size (8) 97
+ 0x95, 0x01, // Report Count (1) 99
+ 0x81, 0x02, // Input (Data,Var,Abs) 101
+ 0x09, 0x3e, // Usage (Y Tilt) 103
+ 0x15, 0x81, // Logical Minimum (-127) 105
+ 0x25, 0x7f, // Logical Maximum (127) 107
+ 0x81, 0x02, // Input (Data,Var,Abs) 109
+ 0xc0, // End Collection 111
+ 0xc0, // End Collection 112
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_fix_rdesc_xppen_artistpro16gen2, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 4096 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ __builtin_memcpy(data, fixed_rdesc, sizeof(fixed_rdesc));
+
+ /* Fix the Physical maximum values for different sizes of the device
+ * The 14" screen device descriptor size is 11.874" x 7.421"
+ */
+ if (hctx->hid->product == PID_ARTIST_PRO14_GEN2) {
+ data[63] = 0x2e;
+ 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);
+}
+
+static int xppen_16_fix_eraser(struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if ((data[1] & 0x29) != 0x29) /* tip switch=1 invert=1 inrange=1 */
+ return 0;
+
+ /* xor bits 0,3 and 4: convert Tip Switch + Invert into Eraser only */
+ data[1] ^= 0x19;
+
+ return 0;
+}
+
+/*
+ * Static coordinate offset table based on positive only angles
+ * Two tables are needed, because the logical coordinates are scaled
+ *
+ * The table can be generated by Python like this:
+ * >>> full_scale = 11.874 # the display width/height in inches
+ * >>> tip_height = 0.055677699 # the center of the pen coil distance from screen in inch (empirical)
+ * >>> h = tip_height * (32767 / full_scale) # height of the coil in logical coordinates
+ * >>> [round(h*math.sin(math.radians(d))) for d in range(0, 128)]
+ * [0, 13, 26, ....]
+ */
+
+/* 14" inch screen 11.874" x 7.421" */
+static const __u16 angle_offsets_horizontal_14[128] = {
+ 0, 3, 5, 8, 11, 13, 16, 19, 21, 24, 27, 29, 32, 35, 37, 40, 42, 45, 47, 50, 53,
+ 55, 58, 60, 62, 65, 67, 70, 72, 74, 77, 79, 81, 84, 86, 88, 90, 92, 95, 97, 99,
+ 101, 103, 105, 107, 109, 111, 112, 114, 116, 118, 119, 121, 123, 124, 126, 127,
+ 129, 130, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
+ 147, 148, 148, 149, 150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 153, 154,
+ 154, 154, 154, 154, 153, 153, 153, 153, 153, 152, 152, 151, 151, 150, 150, 149,
+ 148, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 134, 133,
+ 132, 130, 129, 127, 126, 124, 123
+};
+static const __u16 angle_offsets_vertical_14[128] = {
+ 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 59, 64, 68, 72, 76, 80, 84,
+ 88, 92, 96, 100, 104, 108, 112, 115, 119, 123, 127, 130, 134, 137, 141, 145, 148,
+ 151, 155, 158, 161, 165, 168, 171, 174, 177, 180, 183, 186, 188, 191, 194, 196,
+ 199, 201, 204, 206, 208, 211, 213, 215, 217, 219, 221, 223, 225, 226, 228, 230,
+ 231, 232, 234, 235, 236, 237, 239, 240, 240, 241, 242, 243, 243, 244, 244, 245,
+ 245, 246, 246, 246, 246, 246, 246, 246, 245, 245, 244, 244, 243, 243, 242, 241,
+ 240, 240, 239, 237, 236, 235, 234, 232, 231, 230, 228, 226, 225, 223, 221, 219,
+ 217, 215, 213, 211, 208, 206, 204, 201, 199, 196
+};
+
+/* 16" inch screen 13.567" x 8.480" */
+static const __u16 angle_offsets_horizontal_16[128] = {
+ 0, 2, 5, 7, 9, 12, 14, 16, 19, 21, 23, 26, 28, 30, 33, 35, 37, 39, 42, 44, 46, 48,
+ 50, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90,
+ 92, 93, 95, 97, 98, 100, 101, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115,
+ 116, 118, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 129, 130,
+ 130, 131, 132, 132, 132, 133, 133, 133, 134, 134, 134, 134, 134, 134, 134, 134,
+ 134, 134, 134, 134, 134, 133, 133, 133, 132, 132, 132, 131, 130, 130, 129, 129,
+ 128, 127, 126, 126, 125, 124, 123, 122, 121, 120, 119, 118, 116, 115, 114, 113,
+ 111, 110, 109, 107
+};
+static const __u16 angle_offsets_vertical_16[128] = {
+ 0, 4, 8, 11, 15, 19, 22, 26, 30, 34, 37, 41, 45, 48, 52, 56, 59, 63, 66, 70, 74,
+ 77, 81, 84, 88, 91, 94, 98, 101, 104, 108, 111, 114, 117, 120, 123, 126, 129, 132,
+ 135, 138, 141, 144, 147, 149, 152, 155, 157, 160, 162, 165, 167, 170, 172, 174,
+ 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 198, 199, 201, 202,
+ 203, 205, 206, 207, 208, 209, 210, 210, 211, 212, 212, 213, 214, 214, 214, 215,
+ 215, 215, 215, 215, 215, 215, 215, 215, 214, 214, 214, 213, 212, 212, 211, 210,
+ 210, 209, 208, 207, 206, 205, 203, 202, 201, 199, 198, 197, 195, 193, 192, 190,
+ 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])
+{
+ __u16 coords = data[idx+1];
+
+ coords <<= 8;
+ coords += data[idx];
+
+ __u8 direction = tilt > 0 ? 0 : 1; /* Positive tilt means we need to subtract the compensation (vs. negative angle where we need to add) */
+ __u8 angle = tilt > 0 ? tilt : -tilt;
+
+ if (angle > 127)
+ return;
+
+ __u16 compensation = (*compensation_table)[angle];
+
+ if (direction == 0) {
+ coords = (coords > compensation) ? coords - compensation : 0;
+ } else {
+ const __u16 logical_maximum = 32767;
+ __u16 max = logical_maximum - compensation;
+
+ coords = (coords < max) ? coords + compensation : logical_maximum;
+ }
+
+ data[idx] = coords & 0xff;
+ data[idx+1] = coords >> 8;
+}
+
+static int xppen_16_fix_angle_offset(struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 10 /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ /*
+ * Compensate X and Y offset caused by tilt.
+ *
+ * The magnetic center moves when the pen is tilted, because the coil
+ * is not touching the screen.
+ *
+ * a (tilt angle)
+ * | /... h (coil distance from tip)
+ * | /
+ * |/______
+ * |x (position offset)
+ *
+ * x = sin a * h
+ *
+ * Subtract the offset from the coordinates. Use the precomputed table!
+ *
+ * bytes 0 - report id
+ * 1 - buttons
+ * 2-3 - X coords (logical)
+ * 4-5 - Y coords
+ * 6-7 - pressure (ignore)
+ * 8 - tilt X
+ * 9 - tilt Y
+ */
+
+ __s8 tilt_x = (__s8) data[8];
+ __s8 tilt_y = (__s8) data[9];
+
+ 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);
+ 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;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(xppen_artist_pro_16_device_event, struct hid_bpf_ctx *hctx)
+{
+ int ret = xppen_16_fix_angle_offset(hctx);
+
+ if (ret)
+ return ret;
+
+ return xppen_16_fix_eraser(hctx);
+}
+
+HID_BPF_OPS(xppen_artist_pro_16) = {
+ .hid_rdesc_fixup = (void *)hid_fix_rdesc_xppen_artistpro16gen2,
+ .hid_device_event = (void *)xppen_artist_pro_16_device_event,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /*
+ * The device exports 3 interfaces.
+ */
+ ctx->retval = ctx->rdesc_size != 113;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ /* ensure the kernel isn't fixed already */
+ if (ctx->rdesc[17] != 0x45) /* Eraser */
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c b/drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c
new file mode 100644
index 000000000..2502fcc9e
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__Deco01V3.bpf.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Red Hat
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include "hid_report_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_UGEE 0x28BD /* VID is shared with SinoWealth and Glorious and prob others */
+#define PID_DECO_01_V3 0x0947
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_01_V3),
+);
+
+/*
+ * Default report descriptor reports:
+ * - a report descriptor for the pad buttons, reported as key sequences
+ * - a report descriptor for the pen
+ * - a vendor-specific report descriptor
+ *
+ * The Pad report descriptor, see
+ * https://gitlab.freedesktop.org/libevdev/udev-hid-bpf/-/issues/54
+ *
+ * # 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
+ *
+ * And key events for buttons top->bottom are:
+ * Buttons released: 06 00 00 00 00 00 00 00
+ * Button1: 06 00 05 00 00 00 00 00 -> b
+ * Button2: 06 00 08 00 00 00 00 00 -> e
+ * Button3: 06 04 00 00 00 00 00 00 -> LAlt
+ * Button4: 06 00 2c 00 00 00 00 00 -> Space
+ * Button5: 06 01 16 00 00 00 00 00 -> LControl + s
+ * Button6: 06 01 1d 00 00 00 00 00 -> LControl + z
+ * Button7: 06 01 57 00 00 00 00 00 -> LControl + Keypad Plus
+ * Button8: 06 01 56 00 00 00 00 00 -> LControl + Keypad Dash
+ *
+ * When multiple buttons are pressed at the same time, the values used to
+ * identify the buttons are identical, but they appear in different bytes of the
+ * record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,
+ * this is the report:
+ *
+ * Buttons 2 and 1: 06 00 08 05 00 00 00 00 -> e + b
+ *
+ * Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the
+ * report.
+ *
+ * Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 3
+ * and 5 generates this report:
+ *
+ * Buttons 3 and 5: 06 05 16 00 00 00 00 00 -> LControl + LAlt + s
+ * -- --
+ * | |
+ * | `- Button 5 (0x16)
+ * `- 0x05 = 0101. Button 3 is pressed
+ * ^
+ *
+ * pad_buttons contains a list of buttons that can be matched in
+ * HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.
+ *
+ *
+ * The Pen report descriptor announces a wrong tilt range:
+ *
+ * Report descriptor length: 109 bytes
+ * 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * 0x09, 0x02, // Usage (Pen) 2
+ * 0xa1, 0x01, // Collection (Application) 4
+ * 0x85, 0x07, // Report ID (7) 6
+ * 0x09, 0x20, // Usage (Stylus) 8
+ * 0xa1, 0x01, // Collection (Application) 10
+ * 0x09, 0x42, // Usage (Tip Switch) 12
+ * 0x09, 0x44, // Usage (Barrel Switch) 14
+ * 0x09, 0x45, // Usage (Eraser) 16
+ * 0x09, 0x3c, // Usage (Invert) 18
+ * 0x15, 0x00, // Logical Minimum (0) 20
+ * 0x25, 0x01, // Logical Maximum (1) 22
+ * 0x75, 0x01, // Report Size (1) 24
+ * 0x95, 0x04, // Report Count (4) 26
+ * 0x81, 0x02, // Input (Data,Var,Abs) 28
+ * 0x95, 0x01, // Report Count (1) 30
+ * 0x81, 0x03, // Input (Cnst,Var,Abs) 32
+ * 0x09, 0x32, // Usage (In Range) 34
+ * 0x95, 0x01, // Report Count (1) 36
+ * 0x81, 0x02, // Input (Data,Var,Abs) 38
+ * 0x95, 0x02, // Report Count (2) 40
+ * 0x81, 0x03, // Input (Cnst,Var,Abs) 42
+ * 0x75, 0x10, // Report Size (16) 44
+ * 0x95, 0x01, // Report Count (1) 46
+ * 0x35, 0x00, // Physical Minimum (0) 48
+ * 0xa4, // Push 50
+ * 0x05, 0x01, // Usage Page (Generic Desktop) 51
+ * 0x09, 0x30, // Usage (X) 53
+ * 0x65, 0x13, // Unit (EnglishLinear: in) 55
+ * 0x55, 0x0d, // Unit Exponent (-3) 57
+ * 0x46, 0x10, 0x27, // Physical Maximum (10000) 59
+ * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 62
+ * 0x81, 0x02, // Input (Data,Var,Abs) 65
+ * 0x09, 0x31, // Usage (Y) 67
+ * 0x46, 0x6a, 0x18, // Physical Maximum (6250) 69
+ * 0x26, 0xff, 0x7f, // Logical Maximum (32767) 72
+ * 0x81, 0x02, // Input (Data,Var,Abs) 75
+ * 0xb4, // Pop 77
+ * 0x09, 0x30, // Usage (X) 78
+ * 0x45, 0x00, // Physical Maximum (0) 80
+ * 0x26, 0xff, 0x3f, // Logical Maximum (16383) 82
+ * 0x81, 0x42, // Input (Data,Var,Abs,Null) 85
+ * 0x09, 0x3d, // Usage (Start) 87
+ * 0x15, 0x81, // Logical Minimum (-127) 89 <- Change from -127 to -60
+ * 0x25, 0x7f, // Logical Maximum (127) 91 <- Change from 127 to 60
+ * 0x75, 0x08, // Report Size (8) 93
+ * 0x95, 0x01, // Report Count (1) 95
+ * 0x81, 0x02, // Input (Data,Var,Abs) 97
+ * 0x09, 0x3e, // Usage (Select) 99
+ * 0x15, 0x81, // Logical Minimum (-127) 101 <- Change from -127 to -60
+ * 0x25, 0x7f, // Logical Maximum (127) 103 <- Change from 127 to 60
+ * 0x81, 0x02, // Input (Data,Var,Abs) 105
+ * 0xc0, // End Collection 107
+ * 0xc0, // End Collection 108
+ */
+
+#define PEN_REPORT_DESCRIPTOR_LENGTH 109
+#define PAD_REPORT_DESCRIPTOR_LENGTH 102
+#define PAD_REPORT_LENGTH 8
+#define PAD_REPORT_ID 6
+#define PAD_NUM_BUTTONS 8
+
+static const __u8 fixed_rdesc_pad[] = {
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ // Byte 0 in report is the report ID
+ ReportId(PAD_REPORT_ID)
+ ReportCount(1)
+ ReportSize(8)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ // Byte 1 is the button state
+ UsagePage_Button
+ UsageMinimum_i8(0x01)
+ UsageMaximum_i8(PAD_NUM_BUTTONS)
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ ReportCount(PAD_NUM_BUTTONS)
+ ReportSize(1)
+ Input(Var|Abs)
+ // Byte 2 in report - just exists so we get to be a tablet pad
+ UsagePage_Digitizers
+ Usage_Dig_BarrelSwitch // BTN_STYLUS
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) // padding
+ Input(Const)
+ // Bytes 3/4 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 5-7 are padding so we match the original report lengtth
+ ReportCount(3)
+ ReportSize(8)
+ Input(Const)
+ )
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(xppen_deco01v3_rdesc_fixup, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, HID_MAX_DESCRIPTOR_SIZE /* size */);
+
+ const __u8 wrong_logical_range[] = {0x15, 0x81, 0x25, 0x7f};
+ const __u8 correct_logical_range[] = {0x15, 0xc4, 0x25, 0x3c};
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ switch (hctx->size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ case PEN_REPORT_DESCRIPTOR_LENGTH:
+ if (__builtin_memcmp(&data[89], wrong_logical_range,
+ sizeof(wrong_logical_range)) == 0)
+ __builtin_memcpy(&data[89], correct_logical_range,
+ sizeof(correct_logical_range));
+ if (__builtin_memcmp(&data[101], wrong_logical_range,
+ sizeof(wrong_logical_range)) == 0)
+ __builtin_memcpy(&data[101], correct_logical_range,
+ sizeof(correct_logical_range));
+ break;
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(xppen_deco01v3_device_event, struct hid_bpf_ctx *hctx)
+{
+ static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2c, 0x16, 0x1d, 0x57, 0x56 };
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, PAD_REPORT_LENGTH /* size */);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[0] == PAD_REPORT_ID) {
+ __u8 button_mask = 0;
+ size_t d, b;
+
+ /* data[1] stores the status of BTN_2 in the 3rd bit*/
+ if (data[1] & BIT(2))
+ button_mask |= BIT(2);
+
+ /* The rest of the descriptor stores the buttons as in pad_buttons */
+ for (d = 2; d < 8; d++) {
+ for (b = 0; b < sizeof(pad_buttons); b++) {
+ if (data[d] != 0 && data[d] == pad_buttons[b])
+ button_mask |= BIT(b);
+ }
+ }
+
+ __u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};
+
+ __builtin_memcpy(data, report, sizeof(report));
+ }
+ return 0;
+}
+
+HID_BPF_OPS(xppen_deco01v3) = {
+ .hid_rdesc_fixup = (void *)xppen_deco01v3_rdesc_fixup,
+ .hid_device_event = (void *)xppen_deco01v3_device_event,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ switch (ctx->rdesc_size) {
+ case PAD_REPORT_DESCRIPTOR_LENGTH:
+ case PEN_REPORT_DESCRIPTOR_LENGTH:
+ ctx->retval = 0;
+ break;
+ default:
+ ctx->retval = -EINVAL;
+ }
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/XPPen__Deco02.bpf.c b/drivers/hid/bpf/progs/XPPen__Deco02.bpf.c
new file mode 100644
index 000000000..4b2549031
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__Deco02.bpf.c
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include "hid_report_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_UGEE 0x28BD
+#define PID_DECO_02 0x0803
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_02),
+);
+
+/*
+ * Devices are:
+ * - Pad input, including pen (This is the only one we are interested in)
+ * - Pen input as mouse
+ * - Vendor
+ *
+ * Descriptors on main device are:
+ * - 7: Pen
+ * - 6: Vendor settings? Unclear
+ * - 3: Keyboard (This is what we want to modify)
+ * - 5: Feature report
+ *
+ * This creates three event nodes:
+ * - XP-PEN DECO 02 Stylus
+ * - XP-PEN DECO 02
+ * - XP-PEN DECO 02 Keyboard (Again, what we want to modify)
+ *
+ * # Report descriptor length: 188 bytes
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 0
+ * # 0x09, 0x02, // Usage (Pen) 2
+ * # 0xa1, 0x01, // Collection (Application) 4
+ * # 0x85, 0x07, // Report ID (7) 6
+ * # 0x09, 0x20, // Usage (Stylus) 8
+ * # 0xa1, 0x00, // Collection (Physical) 10
+ * # 0x09, 0x42, // Usage (Tip Switch) 12
+ * # 0x09, 0x44, // Usage (Barrel Switch) 14
+ * # 0x09, 0x45, // Usage (Eraser) 16
+ * # 0x09, 0x3c, // Usage (Invert) 18
+ * # 0x09, 0x32, // Usage (In Range) 20
+ * # 0x15, 0x00, // Logical Minimum (0) 22
+ * # 0x25, 0x01, // Logical Maximum (1) 24
+ * # 0x75, 0x01, // Report Size (1) 26
+ * # 0x95, 0x05, // Report Count (5) 28
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 30
+ * # 0x95, 0x03, // Report Count (3) 32
+ * # 0x81, 0x03, // Input (Cnst,Var,Abs) 34
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 36
+ * # 0x09, 0x30, // Usage (X) 38
+ * # 0x15, 0x00, // Logical Minimum (0) 40
+ * # 0x26, 0x50, 0x57, // Logical Maximum (22352) 42
+ * # 0x55, 0x0d, // Unit Exponent (-3) 45
+ * # 0x65, 0x13, // Unit (EnglishLinear: in) 47
+ * # 0x35, 0x00, // Physical Minimum (0) 49
+ * # 0x46, 0x50, 0x57, // Physical Maximum (22352) 51
+ * # 0x75, 0x10, // Report Size (16) 54
+ * # 0x95, 0x01, // Report Count (1) 56
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 58
+ * # 0x09, 0x31, // Usage (Y) 60
+ * # 0x15, 0x00, // Logical Minimum (0) 62
+ * # 0x26, 0x92, 0x36, // Logical Maximum (13970) 64
+ * # 0x55, 0x0d, // Unit Exponent (-3) 67
+ * # 0x65, 0x13, // Unit (EnglishLinear: in) 69
+ * # 0x35, 0x00, // Physical Minimum (0) 71
+ * # 0x46, 0x92, 0x36, // Physical Maximum (13970) 73
+ * # 0x75, 0x10, // Report Size (16) 76
+ * # 0x95, 0x01, // Report Count (1) 78
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 80
+ * # 0x05, 0x0d, // Usage Page (Digitizers) 82
+ * # 0x09, 0x30, // Usage (Tip Pressure) 84
+ * # 0x15, 0x00, // Logical Minimum (0) 86
+ * # 0x26, 0xff, 0x1f, // Logical Maximum (8191) 88
+ * # 0x75, 0x10, // Report Size (16) 91
+ * # 0x95, 0x01, // Report Count (1) 93
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 95
+ * # 0xc0, // End Collection 97
+ * # 0xc0, // End Collection 98
+ * # 0x09, 0x0e, // Usage (Device Configuration) 99
+ * # 0xa1, 0x01, // Collection (Application) 101
+ * # 0x85, 0x05, // Report ID (5) 103
+ * # 0x09, 0x23, // Usage (Device Settings) 105
+ * # 0xa1, 0x02, // Collection (Logical) 107
+ * # 0x09, 0x52, // Usage (Inputmode) 109
+ * # 0x09, 0x53, // Usage (Device Index) 111
+ * # 0x25, 0x0a, // Logical Maximum (10) 113
+ * # 0x75, 0x08, // Report Size (8) 115
+ * # 0x95, 0x02, // Report Count (2) 117
+ * # 0xb1, 0x02, // Feature (Data,Var,Abs) 119
+ * # 0xc0, // End Collection 121
+ * # 0xc0, // End Collection 122
+ * # 0x05, 0x0c, // Usage Page (Consumer Devices) 123
+ * # 0x09, 0x36, // Usage (Function Buttons) 125
+ * # 0xa1, 0x00, // Collection (Physical) 127
+ * # 0x85, 0x06, // Report ID (6) 129
+ * # 0x05, 0x09, // Usage Page (Button) 131
+ * # 0x19, 0x01, // Usage Minimum (1) 133
+ * # 0x29, 0x20, // Usage Maximum (32) 135
+ * # 0x15, 0x00, // Logical Minimum (0) 137
+ * # 0x25, 0x01, // Logical Maximum (1) 139
+ * # 0x95, 0x20, // Report Count (32) 141
+ * # 0x75, 0x01, // Report Size (1) 143
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 145
+ * # 0xc0, // End Collection 147
+ * # 0x05, 0x01, // Usage Page (Generic Desktop) 148
+ * # 0x09, 0x06, // Usage (Keyboard) 150
+ * # 0xa1, 0x01, // Collection (Application) 152
+ * # 0x85, 0x03, // Report ID (3) 154
+ * # 0x05, 0x07, // Usage Page (Keyboard) 156
+ * # 0x19, 0xe0, // Usage Minimum (224) 158
+ * # 0x29, 0xe7, // Usage Maximum (231) 160
+ * # 0x15, 0x00, // Logical Minimum (0) 162
+ * # 0x25, 0x01, // Logical Maximum (1) 164
+ * # 0x75, 0x01, // Report Size (1) 166
+ * # 0x95, 0x08, // Report Count (8) 168
+ * # 0x81, 0x02, // Input (Data,Var,Abs) 170
+ * # 0x05, 0x07, // Usage Page (Keyboard) 172
+ * # 0x19, 0x00, // Usage Minimum (0) 174
+ * # 0x29, 0xff, // Usage Maximum (255) 176
+ * # 0x26, 0xff, 0x00, // Logical Maximum (255) 178
+ * # 0x75, 0x08, // Report Size (8) 181
+ * # 0x95, 0x06, // Report Count (6) 183
+ * # 0x81, 0x00, // Input (Data,Arr,Abs) 185
+ * # 0xc0, // End Collection 187
+ *
+ * Key events; top to bottom:
+ * Buttons released: 03 00 00 00 00 00 00 00
+ * Button1: 03 00 05 00 00 00 00 00 -> 'b and B'
+ * Button2: 03 00 2c 00 00 00 00 00 -> 'Spacebar'
+ * Button3: 03 00 08 00 00 00 00 00 -> 'e and E'
+ * Button4: 03 00 0c 00 00 00 00 00 -> 'i and I'
+ * Button5: 03 05 1d 00 00 00 00 00 -> LeftControl + LeftAlt + 'z and Z'
+ * Button6: 03 01 16 00 00 00 00 00 -> LeftControl + 's and S'
+ *
+ * Dial Events:
+ * Clockwise: 03 01 2e 00 00 00 00 00 -> LeftControl + '= and +'
+ * Anticlockwise: 03 01 2d 00 00 00 00 00 -> LeftControl + '- and (underscore)'
+ *
+ * NOTE: Input event descriptions begin at byte 2, and progressively build
+ * towards byte 7 as each new key is pressed maintaining the press order.
+ * For example:
+ * BTN1 followed by BTN2 is 03 00 05 2c 00 00 00 00
+ * BTN2 followed by BTN1 is 03 00 2c 05 00 00 00 00
+ *
+ * Releasing a button causes its byte to be freed, and the next item in the list
+ * is pushed forwards. Dial events are released immediately after an event is
+ * registered (i.e. after each "click"), so will continually appear pushed
+ * backwards in the report.
+ *
+ * When a button with a modifier key is pressed, the button identifier stacks in
+ * an abnormal way, where the highest modifier byte always supersedes others.
+ * In these cases, the button with the higher modifier is always last.
+ * For example:
+ * BTN6 followed by BTN5 is 03 05 1d 16 00 00 00 00
+ * BTN5 followed by BTN6 is 03 05 1d 16 00 00 00 00
+ * BTN5 followed by BTN1 is 03 05 05 1d 00 00 00 00
+ *
+ * For three button presses in order, demonstrating strictly above rules:
+ * BTN6, BTN1, BTN5 is 03 05 05 1d 16 00 00 00
+ * BTN5, BTN1, BTN6 is 03 05 05 1d 16 00 00 00
+ *
+ * In short, when BTN5/6 are pressed, the order of operations is lost, as they
+ * will always float to the end when pressed in combination with others.
+ *
+ * Fortunately, all states are recorded in the same way, with no overlaps.
+ * Byte 1 can be used as a spare for the wheel, since this is for mod keys.
+ */
+
+#define RDESC_SIZE_PAD 188
+#define REPORT_SIZE_PAD 8
+#define REPORT_ID_BUTTONS 3
+#define PAD_BUTTON_COUNT 6
+#define RDESC_KEYBOARD_OFFSET 148
+
+static const __u8 fixed_rdesc_pad[] = {
+ /* Copy of pen descriptor to avoid losing functionality */
+ UsagePage_Digitizers
+ Usage_Dig_Pen
+ CollectionApplication(
+ ReportId(7)
+ Usage_Dig_Stylus
+ CollectionPhysical(
+ Usage_Dig_TipSwitch
+ Usage_Dig_BarrelSwitch
+ Usage_Dig_Eraser
+ Usage_Dig_Invert
+ Usage_Dig_InRange
+ LogicalMinimum_i8(0)
+ LogicalMaximum_i8(1)
+ ReportSize(1)
+ ReportCount(5)
+ Input(Var|Abs)
+ ReportCount(3)
+ Input(Const) /* Input (Const, Var, Abs) */
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(22352)
+ UnitExponent(-3)
+ Unit(in) /* (EnglishLinear: in) */
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(22352)
+ ReportSize(16)
+ ReportCount(1)
+ Input(Var|Abs)
+ Usage_GD_Y
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(13970)
+ UnitExponent(-3)
+ Unit(in) /* (EnglishLinear: in) */
+ PhysicalMinimum_i16(0)
+ PhysicalMaximum_i16(13970)
+ ReportSize(16)
+ ReportCount(1)
+ Input(Var|Abs)
+ UsagePage_Digitizers
+ Usage_Dig_TipPressure
+ LogicalMinimum_i16(0)
+ LogicalMaximum_i16(8191)
+ ReportSize(16)
+ ReportCount(1)
+ Input(Var|Abs)
+ )
+ )
+
+ /* FIXES BEGIN */
+ UsagePage_GenericDesktop
+ Usage_GD_Keypad
+ CollectionApplication(
+ ReportId(REPORT_ID_BUTTONS) /* Retain original ID on byte 0 */
+ ReportCount(1)
+ ReportSize(REPORT_SIZE_PAD)
+ UsagePage_Digitizers
+ Usage_Dig_TabletFunctionKeys
+ CollectionPhysical(
+ /* Byte 1: Dial state */
+ UsagePage_GenericDesktop
+ Usage_GD_Dial
+ LogicalMinimum_i8(-1)
+ LogicalMaximum_i8(1)
+ ReportCount(1)
+ ReportSize(REPORT_SIZE_PAD)
+ Input(Var|Rel)
+ /* Byte 2: Button state */
+ UsagePage_Button
+ ReportSize(1)
+ ReportCount(PAD_BUTTON_COUNT)
+ UsageMinimum_i8(0x01)
+ UsageMaximum_i8(PAD_BUTTON_COUNT) /* Number of buttons */
+ LogicalMinimum_i8(0x0)
+ LogicalMaximum_i8(0x1)
+ Input(Var|Abs)
+ /* Byte 3: Exists to be tablet pad */
+ UsagePage_Digitizers
+ Usage_Dig_BarrelSwitch
+ ReportCount(1)
+ ReportSize(1)
+ Input(Var|Abs)
+ ReportCount(7) /* Padding, to fill full report space */
+ Input(Const)
+ /* Byte 4/5: Exists to be a tablet pad */
+ UsagePage_GenericDesktop
+ Usage_GD_X
+ Usage_GD_Y
+ ReportCount(2)
+ ReportSize(8)
+ Input(Var|Abs)
+ /* Bytes 6/7: Padding, to match original length */
+ ReportCount(2)
+ ReportSize(8)
+ Input(Const)
+ )
+ FixedSizeVendorReport(RDESC_SIZE_PAD)
+ )
+};
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(xppen_deco02_rdesc_fixup, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
+
+ if (!data)
+ return 0; /* EPERM Check */
+
+ if (hctx->size == RDESC_SIZE_PAD) {
+ __builtin_memcpy(data, fixed_rdesc_pad, sizeof(fixed_rdesc_pad));
+ return sizeof(fixed_rdesc_pad);
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(xppen_deco02_device_event, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, REPORT_SIZE_PAD);
+
+ if (!data || data[0] != REPORT_ID_BUTTONS)
+ return 0; /* EPERM or wrong report */
+
+ __u8 dial_code = 0;
+ __u8 button_mask = 0;
+ size_t d;
+
+ /* Start from 2; 0 is report ID, 1 is modifier keys, replaced by dial */
+ for (d = 2; d < 8; d++) {
+ switch (data[d]) {
+ case 0x2e:
+ dial_code = 1;
+ break;
+ case 0x2d:
+ dial_code = -1;
+ break;
+ /* below are buttons, top to bottom */
+ case 0x05:
+ button_mask |= BIT(0);
+ break;
+ case 0x2c:
+ button_mask |= BIT(1);
+ break;
+ case 0x08:
+ button_mask |= BIT(2);
+ break;
+ case 0x0c:
+ button_mask |= BIT(3);
+ break;
+ case 0x1d:
+ button_mask |= BIT(4);
+ break;
+ case 0x16:
+ button_mask |= BIT(05);
+ break;
+ default:
+ break;
+ }
+ }
+
+ __u8 report[8] = { REPORT_ID_BUTTONS, dial_code, button_mask, 0x00 };
+
+ __builtin_memcpy(data, report, sizeof(report));
+ return 0;
+}
+
+HID_BPF_OPS(xppen_deco02) = {
+ .hid_rdesc_fixup = (void *)xppen_deco02_rdesc_fixup,
+ .hid_device_event = (void *)xppen_deco02_device_event,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD ? -EINVAL : 0;
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c b/drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c
new file mode 100644
index 000000000..ac07216f5
--- /dev/null
+++ b/drivers/hid/bpf/progs/XPPen__DecoMini4.bpf.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2024 José Expósito
+ */
+
+#include "vmlinux.h"
+#include "hid_bpf.h"
+#include "hid_bpf_helpers.h"
+#include <bpf/bpf_tracing.h>
+
+#define VID_UGEE 0x28BD
+#define PID_DECO_MINI_4 0x0929
+#define RDESC_SIZE_PAD 177
+#define RDESC_SIZE_PEN 109
+#define PAD_REPORT_ID 0x06
+
+/*
+ * XP-Pen devices return a descriptor with the values the driver should use when
+ * one of its interfaces is queried. For this device the descriptor is:
+ *
+ * 0E 03 60 4F 88 3B 06 00 FF 1F D8 13
+ * ----- ----- ----- -----
+ * | | | |
+ * | | | `- Resolution: 5080 (13d8)
+ * | | `- Maximum pressure: 8191 (1FFF)
+ * | `- Logical maximum Y: 15240 (3B88)
+ * `- Logical maximum X: 20320 (4F60)
+ *
+ * The physical maximum is calculated as (logical_max * 1000) / resolution.
+ */
+#define LOGICAL_MAX_X 0x60, 0x4F
+#define LOGICAL_MAX_Y 0x88, 0x3B
+#define PHYSICAL_MAX_X 0xA0, 0x0F
+#define PHYSICAL_MAX_Y 0xB8, 0x0B
+#define PRESSURE_MAX 0xFF, 0x1F
+
+HID_BPF_CONFIG(
+ HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, VID_UGEE, PID_DECO_MINI_4)
+);
+
+/*
+ * The tablet send these values when the pad buttons are pressed individually:
+ *
+ * Buttons released: 06 00 00 00 00 00 00 00
+ * Button 1: 06 00 05 00 00 00 00 00 -> b
+ * Button 2: 06 00 08 00 00 00 00 00 -> e
+ * Button 3: 06 04 00 00 00 00 00 00 -> LAlt
+ * Button 4: 06 00 2c 00 00 00 00 00 -> Space
+ * Button 5: 06 01 16 00 00 00 00 00 -> LControl + s
+ * Button 6: 06 01 1d 00 00 00 00 00 -> LControl + z
+ *
+ * When multiple buttons are pressed at the same time, the values used to
+ * identify the buttons are identical, but they appear in different bytes of the
+ * record. For example, when button 2 (0x08) and button 1 (0x05) are pressed,
+ * this is the report:
+ *
+ * Buttons 2 and 1: 06 00 08 05 00 00 00 00 -> e + b
+ *
+ * Buttons 1, 2, 4, 5 and 6 can be matched by finding their values in the
+ * report.
+ *
+ * Button 3 is pressed when the 3rd bit is 1. For example, pressing buttons 3
+ * and 5 generates this report:
+ *
+ * Buttons 3 and 5: 06 05 16 00 00 00 00 00 -> LControl + LAlt + s
+ * -- --
+ * | |
+ * | `- Button 5 (0x16)
+ * `- 0x05 = 0101. Button 3 is pressed
+ * ^
+ *
+ * pad_buttons contains a list of buttons that can be matched in
+ * HID_BPF_DEVICE_EVENT. Button 3 as it has a dedicated bit.
+ */
+static const __u8 pad_buttons[] = { 0x05, 0x08, 0x00, 0x2C, 0x16, 0x1D };
+
+static const __u8 fixed_pad_rdesc[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x07, /* Usage (Keypad), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x06, /* Report ID (6), */
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x39, /* Usage (Tablet Function Keys), */
+ 0xA0, /* Collection (Physical), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x06, /* Report Count (6), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x06, /* Usage Maximum (06h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x32, /* Report Count (50), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static const __u8 fixed_pen_rdesc[] = {
+ 0x05, 0x0d, /* Usage Page (Digitizers), */
+ 0x09, 0x01, /* Usage (Digitizer), */
+ 0xa1, 0x01, /* Collection (Application), */
+ 0x85, 0x07, /* Report ID (7), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xa1, 0x00, /* Collection (Physical), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x35, 0x00, /* Physical Minimum (0), */
+ 0xa4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0x0d, /* Unit Exponent (-3), */
+ 0x26, LOGICAL_MAX_X, /* Logical Maximum, */
+ 0x46, PHYSICAL_MAX_X, /* Physical Maximum, */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x26, LOGICAL_MAX_Y, /* Logical Maximum, */
+ 0x46, PHYSICAL_MAX_Y, /* Physical Maximum, */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xb4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x45, 0x00, /* Physical Maximum (0), */
+ 0x26, PRESSURE_MAX, /* Logical Maximum, */
+ 0x75, 0x0D, /* Report Size (13), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x13, /* Report Count (19), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xc0, /* End Collection, */
+ 0xc0, /* End Collection */
+};
+
+static const size_t fixed_pad_rdesc_size = sizeof(fixed_pad_rdesc);
+static const size_t fixed_pen_rdesc_size = sizeof(fixed_pen_rdesc);
+
+SEC(HID_BPF_RDESC_FIXUP)
+int BPF_PROG(hid_rdesc_fixup_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0, HID_MAX_DESCRIPTOR_SIZE);
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (hctx->size == RDESC_SIZE_PAD) {
+ __builtin_memcpy(data, fixed_pad_rdesc, fixed_pad_rdesc_size);
+ return fixed_pad_rdesc_size;
+ } else if (hctx->size == RDESC_SIZE_PEN) {
+ __builtin_memcpy(data, fixed_pen_rdesc, fixed_pen_rdesc_size);
+ return fixed_pen_rdesc_size;
+ }
+
+ return 0;
+}
+
+SEC(HID_BPF_DEVICE_EVENT)
+int BPF_PROG(hid_device_event_xppen_deco_mini_4, struct hid_bpf_ctx *hctx)
+{
+ __u8 *data = hid_bpf_get_data(hctx, 0 /* offset */, 8 /* size */);
+ __u8 button_mask = 0;
+ size_t d, b;
+
+ if (!data)
+ return 0; /* EPERM check */
+
+ if (data[0] != PAD_REPORT_ID)
+ return 0;
+
+ /* data[1] stores the status of BTN_2 in the 3rd bit*/
+ if (data[1] & BIT(2))
+ button_mask |= BIT(2);
+
+ /* The rest of the descriptor stores the buttons as in pad_buttons */
+ for (d = 2; d < 8; d++) {
+ for (b = 0; b < sizeof(pad_buttons); b++) {
+ if (data[d] != 0 && data[d] == pad_buttons[b])
+ button_mask |= BIT(b);
+ }
+ }
+
+ __u8 report[8] = {PAD_REPORT_ID, button_mask, 0x00};
+
+ __builtin_memcpy(data, report, sizeof(report));
+
+ return 0;
+}
+
+HID_BPF_OPS(deco_mini_4) = {
+ .hid_device_event = (void *)hid_device_event_xppen_deco_mini_4,
+ .hid_rdesc_fixup = (void *)hid_rdesc_fixup_xppen_deco_mini_4,
+};
+
+SEC("syscall")
+int probe(struct hid_bpf_probe_args *ctx)
+{
+ /*
+ * The device has 2 modes: The compatibility mode, enabled by default,
+ * and the raw mode, that can be activated by sending a buffer of magic
+ * data to a certain USB endpoint.
+ *
+ * Depending on the mode, different interfaces of the device are used:
+ * - First interface: Pad in compatibility mode
+ * - Second interface: Pen in compatibility mode
+ * - Third interface: Only used in raw mode
+ *
+ * We'll use the device in compatibility mode.
+ */
+ ctx->retval = ctx->rdesc_size != RDESC_SIZE_PAD &&
+ ctx->rdesc_size != RDESC_SIZE_PEN;
+ if (ctx->retval)
+ ctx->retval = -EINVAL;
+
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/drivers/hid/bpf/progs/hid_bpf.h b/drivers/hid/bpf/progs/hid_bpf.h
new file mode 100644
index 000000000..7cabd1b2e
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_bpf.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022 Benjamin Tissoires
+ */
+
+#ifndef ____HID_BPF__H
+#define ____HID_BPF__H
+
+#define HID_BPF_DEVICE_EVENT "struct_ops/hid_device_event"
+#define HID_BPF_RDESC_FIXUP "struct_ops/hid_rdesc_fixup"
+#define HID_BPF_OPS(name) SEC(".struct_ops.link") \
+ struct hid_bpf_ops name
+#define hid_set_name(_hdev, _name) __builtin_memcpy(_hdev->name, _name, sizeof(_name))
+
+struct hid_bpf_probe_args {
+ unsigned int hid;
+ unsigned int rdesc_size;
+ unsigned char rdesc[4096];
+ int retval;
+};
+
+#endif /* ____HID_BPF__H */
diff --git a/drivers/hid/bpf/progs/hid_bpf_async.h b/drivers/hid/bpf/progs/hid_bpf_async.h
new file mode 100644
index 000000000..877bb7e81
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_bpf_async.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2024 Benjamin Tissoires
+ */
+
+#ifndef __HID_BPF_ASYNC_H__
+#define __HID_BPF_ASYNC_H__
+
+#ifndef HID_BPF_ASYNC_MAX_CTX
+#error "HID_BPF_ASYNC_MAX_CTX should be set to the maximum number of concurrent async functions"
+#endif /* HID_BPF_ASYNC_MAX_CTX */
+
+#define CLOCK_MONOTONIC 1
+
+typedef int (*hid_bpf_async_callback_t)(void *map, int *key, void *value);
+
+enum hid_bpf_async_state {
+ HID_BPF_ASYNC_STATE_UNSET = 0,
+ HID_BPF_ASYNC_STATE_INITIALIZING,
+ HID_BPF_ASYNC_STATE_INITIALIZED,
+ HID_BPF_ASYNC_STATE_STARTING,
+ HID_BPF_ASYNC_STATE_RUNNING,
+};
+
+struct hid_bpf_async_map_elem {
+ struct bpf_spin_lock lock;
+ enum hid_bpf_async_state state;
+ struct bpf_timer t;
+ struct bpf_wq wq;
+ u32 hid;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_ARRAY);
+ __uint(max_entries, HID_BPF_ASYNC_MAX_CTX);
+ __type(key, u32);
+ __type(value, struct hid_bpf_async_map_elem);
+} hid_bpf_async_ctx_map SEC(".maps");
+
+/**
+ * HID_BPF_ASYNC_CB: macro to define an async callback used in a bpf_wq
+ *
+ * The caller is responsible for allocating a key in the async map
+ * with hid_bpf_async_get_ctx().
+ */
+#define HID_BPF_ASYNC_CB(cb) \
+cb(void *map, int *key, void *value); \
+static __always_inline int \
+____##cb(struct hid_bpf_ctx *ctx); \
+typeof(cb(0, 0, 0)) cb(void *map, int *key, void *value) \
+{ \
+ struct hid_bpf_async_map_elem *e; \
+ struct hid_bpf_ctx *ctx; \
+ \
+ e = (struct hid_bpf_async_map_elem *)value; \
+ ctx = hid_bpf_allocate_context(e->hid); \
+ if (!ctx) \
+ return 0; /* EPERM check */ \
+ \
+ e->state = HID_BPF_ASYNC_STATE_RUNNING; \
+ \
+ ____##cb(ctx); \
+ \
+ e->state = HID_BPF_ASYNC_STATE_INITIALIZED; \
+ hid_bpf_release_context(ctx); \
+ return 0; \
+} \
+static __always_inline int \
+____##cb
+
+/**
+ * ASYNC: macro to automatically handle async callbacks contexts
+ *
+ * Needs to be used in conjunction with HID_BPF_ASYNC_INIT and HID_BPF_ASYNC_DELAYED_CALL
+ */
+#define HID_BPF_ASYNC_FUN(fun) \
+fun(struct hid_bpf_ctx *ctx); \
+int ____key__##fun; \
+static int ____async_init_##fun(void) \
+{ \
+ ____key__##fun = hid_bpf_async_get_ctx(); \
+ if (____key__##fun < 0) \
+ return ____key__##fun; \
+ return 0; \
+} \
+static int HID_BPF_ASYNC_CB(____##fun##_cb)(struct hid_bpf_ctx *hctx) \
+{ \
+ return fun(hctx); \
+} \
+typeof(fun(0)) fun
+
+#define HID_BPF_ASYNC_INIT(fun) ____async_init_##fun()
+#define HID_BPF_ASYNC_DELAYED_CALL(fun, ctx, delay) \
+ hid_bpf_async_delayed_call(ctx, delay, ____key__##fun, ____##fun##_cb)
+
+/*
+ * internal cb for starting the delayed work callback in a workqueue.
+ */
+static int __start_wq_timer_cb(void *map, int *key, void *value)
+{
+ struct hid_bpf_async_map_elem *e = (struct hid_bpf_async_map_elem *)value;
+
+ bpf_wq_start(&e->wq, 0);
+
+ return 0;
+}
+
+static int hid_bpf_async_find_empty_key(void)
+{
+ int i;
+
+ bpf_for(i, 0, HID_BPF_ASYNC_MAX_CTX) {
+ struct hid_bpf_async_map_elem *elem;
+ int key = i;
+
+ elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key);
+ if (!elem)
+ return -ENOMEM; /* should never happen */
+
+ {
+ guard(bpf_spin)(&elem->lock);
+
+ if (elem->state == HID_BPF_ASYNC_STATE_UNSET) {
+ elem->state = HID_BPF_ASYNC_STATE_INITIALIZING;
+ return i;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int hid_bpf_async_get_ctx(void)
+{
+ int key = hid_bpf_async_find_empty_key();
+ struct hid_bpf_async_map_elem *elem;
+ int err;
+
+ if (key < 0)
+ return key;
+
+ elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key);
+ if (!elem)
+ return -EINVAL;
+
+ err = bpf_timer_init(&elem->t, &hid_bpf_async_ctx_map, CLOCK_MONOTONIC);
+ if (err)
+ return err;
+
+ err = bpf_timer_set_callback(&elem->t, __start_wq_timer_cb);
+ if (err)
+ return err;
+
+ err = bpf_wq_init(&elem->wq, &hid_bpf_async_ctx_map, 0);
+ if (err)
+ return err;
+
+ elem->state = HID_BPF_ASYNC_STATE_INITIALIZED;
+
+ return key;
+}
+
+static inline u64 ms_to_ns(u64 milliseconds)
+{
+ return (u64)milliseconds * 1000UL * 1000UL;
+}
+
+static int hid_bpf_async_delayed_call(struct hid_bpf_ctx *hctx, u64 milliseconds, int key,
+ hid_bpf_async_callback_t wq_cb)
+{
+ struct hid_bpf_async_map_elem *elem;
+ int err;
+
+ elem = bpf_map_lookup_elem(&hid_bpf_async_ctx_map, &key);
+ if (!elem)
+ return -EINVAL;
+
+ {
+ guard(bpf_spin)(&elem->lock);
+
+ /* The wq must be:
+ * - HID_BPF_ASYNC_STATE_INITIALIZED -> it's been initialized and ready to be called
+ * - HID_BPF_ASYNC_STATE_RUNNING -> possible re-entry from the wq itself
+ */
+ if (elem->state != HID_BPF_ASYNC_STATE_INITIALIZED &&
+ elem->state != HID_BPF_ASYNC_STATE_RUNNING)
+ return -EINVAL;
+
+ elem->state = HID_BPF_ASYNC_STATE_STARTING;
+ }
+
+ elem->hid = hctx->hid->id;
+
+ err = bpf_wq_set_callback(&elem->wq, wq_cb, 0);
+ if (err)
+ return err;
+
+ if (milliseconds) {
+ /* needed for every call because a cancel might unset this */
+ err = bpf_timer_set_callback(&elem->t, __start_wq_timer_cb);
+ if (err)
+ return err;
+
+ err = bpf_timer_start(&elem->t, ms_to_ns(milliseconds), 0);
+ if (err)
+ return err;
+
+ return 0;
+ }
+
+ return bpf_wq_start(&elem->wq, 0);
+}
+
+static inline int hid_bpf_async_call(struct hid_bpf_ctx *ctx, int key,
+ hid_bpf_async_callback_t wq_cb)
+{
+ return hid_bpf_async_delayed_call(ctx, 0, key, wq_cb);
+}
+
+#endif /* __HID_BPF_ASYNC_H__ */
diff --git a/drivers/hid/bpf/progs/hid_bpf_helpers.h b/drivers/hid/bpf/progs/hid_bpf_helpers.h
new file mode 100644
index 000000000..0fd8e7d90
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_bpf_helpers.h
@@ -0,0 +1,507 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022 Benjamin Tissoires
+ */
+
+#ifndef __HID_BPF_HELPERS_H
+#define __HID_BPF_HELPERS_H
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+#include <linux/errno.h>
+#include "hid_report_descriptor_helpers.h"
+
+/* Compiler attributes */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+#endif
+
+extern __u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx,
+ unsigned int offset,
+ const size_t __sz) __ksym;
+extern struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id) __ksym;
+extern void hid_bpf_release_context(struct hid_bpf_ctx *ctx) __ksym;
+extern int hid_bpf_hw_request(struct hid_bpf_ctx *ctx,
+ __u8 *data,
+ size_t buf__sz,
+ enum hid_report_type type,
+ enum hid_class_request reqtype) __ksym;
+extern int hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx,
+ __u8 *buf, size_t buf__sz) __weak __ksym;
+extern int hid_bpf_input_report(struct hid_bpf_ctx *ctx,
+ enum hid_report_type type,
+ __u8 *data,
+ size_t buf__sz) __weak __ksym;
+extern int hid_bpf_try_input_report(struct hid_bpf_ctx *ctx,
+ enum hid_report_type type,
+ __u8 *data,
+ size_t buf__sz) __weak __ksym;
+
+/* bpf_wq implementation */
+extern int bpf_wq_init(struct bpf_wq *wq, void *p__map, unsigned int flags) __weak __ksym;
+extern int bpf_wq_start(struct bpf_wq *wq, unsigned int flags) __weak __ksym;
+extern int bpf_wq_set_callback(struct bpf_wq *wq,
+ int (*callback_fn)(void *, int *, void *),
+ unsigned int flags) __weak __ksym;
+
+#define HID_MAX_DESCRIPTOR_SIZE 4096
+#define HID_IGNORE_EVENT -1
+
+/**
+ * Use: _cleanup_(somefunction) struct foo *bar;
+ */
+#define _cleanup_(_x) __attribute__((cleanup(_x)))
+
+/**
+ * Use: _release_(foo) *bar;
+ *
+ * This requires foo_releasep() to be present, use DEFINE_RELEASE_CLEANUP_FUNC.
+ */
+#define _release_(_type) struct _type __attribute__((cleanup(_type##_releasep)))
+
+/**
+ * Define a cleanup function for the struct type foo with a matching
+ * foo_release(). Use:
+ * DEFINE_RELEASE_CLEANUP_FUNC(foo)
+ * _unref_(foo) struct foo *bar;
+ */
+#define DEFINE_RELEASE_CLEANUP_FUNC(_type) \
+ static inline void _type##_releasep(struct _type **_p) { \
+ if (*_p) \
+ _type##_release(*_p); \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+/* for being able to have a cleanup function */
+#define hid_bpf_ctx_release hid_bpf_release_context
+DEFINE_RELEASE_CLEANUP_FUNC(hid_bpf_ctx);
+
+/*
+ * Kernel-style guard macros adapted for BPF
+ * Based on include/linux/cleanup.h from the Linux kernel
+ *
+ * These provide automatic lock/unlock using __attribute__((cleanup))
+ * similar to how _release_() works for contexts.
+ */
+
+/**
+ * DEFINE_GUARD(name, type, lock, unlock):
+ * Define a guard for automatic lock/unlock using the same pattern as _release_()
+ * @name: identifier for the guard (e.g., bpf_spin)
+ * @type: lock variable type (e.g., struct bpf_spin_lock)
+ * @lock: lock function name (e.g., bpf_spin_lock)
+ * @unlock: unlock function name (e.g., bpf_spin_unlock)
+ *
+ * guard(name):
+ * Declare and lock in one statement - lock held until end of scope
+ *
+ * Example:
+ * DEFINE_GUARD(bpf_spin, struct bpf_spin_lock, bpf_spin_lock, bpf_spin_unlock)
+ *
+ * void foo(struct bpf_spin_lock *lock) {
+ * guard(bpf_spin)(lock);
+ * // lock held until end of scope
+ * }
+ */
+
+/* Guard helper struct - stores lock pointer for cleanup */
+#define DEFINE_GUARD(_name, _type, _lock, _unlock) \
+struct _name##_guard { \
+ _type *lock; \
+}; \
+static inline void _name##_guard_cleanup(struct _name##_guard *g) { \
+ if (g && g->lock) \
+ _unlock(g->lock); \
+} \
+static inline struct _name##_guard _name##_guard_init(_type *l) { \
+ if (l) \
+ _lock(l); \
+ return (struct _name##_guard){.lock = l}; \
+} \
+struct __useless_struct_to_allow_trailing_semicolon__
+
+#define guard(_name) \
+ struct _name##_guard COMBINE(guard, __LINE__) __attribute__((cleanup(_name##_guard_cleanup))) = \
+ _name##_guard_init
+
+/* Define BPF spinlock guard */
+DEFINE_GUARD(bpf_spin, struct bpf_spin_lock, bpf_spin_lock, bpf_spin_unlock);
+
+/* extracted from <linux/input.h> */
+#define BUS_ANY 0x00
+#define BUS_PCI 0x01
+#define BUS_ISAPNP 0x02
+#define BUS_USB 0x03
+#define BUS_HIL 0x04
+#define BUS_BLUETOOTH 0x05
+#define BUS_VIRTUAL 0x06
+#define BUS_ISA 0x10
+#define BUS_I8042 0x11
+#define BUS_XTKBD 0x12
+#define BUS_RS232 0x13
+#define BUS_GAMEPORT 0x14
+#define BUS_PARPORT 0x15
+#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
+#define BUS_I2C 0x18
+#define BUS_HOST 0x19
+#define BUS_GSC 0x1A
+#define BUS_ATARI 0x1B
+#define BUS_SPI 0x1C
+#define BUS_RMI 0x1D
+#define BUS_CEC 0x1E
+#define BUS_INTEL_ISHTP 0x1F
+#define BUS_AMD_SFH 0x20
+
+/* extracted from <linux/hid.h> */
+#define HID_GROUP_ANY 0x0000
+#define HID_GROUP_GENERIC 0x0001
+#define HID_GROUP_MULTITOUCH 0x0002
+#define HID_GROUP_SENSOR_HUB 0x0003
+#define HID_GROUP_MULTITOUCH_WIN_8 0x0004
+#define HID_GROUP_RMI 0x0100
+#define HID_GROUP_WACOM 0x0101
+#define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102
+#define HID_GROUP_STEAM 0x0103
+#define HID_GROUP_LOGITECH_27MHZ_DEVICE 0x0104
+#define HID_GROUP_VIVALDI 0x0105
+
+/* include/linux/mod_devicetable.h defines as (~0), but that gives us negative size arrays */
+#define HID_VID_ANY 0x0000
+#define HID_PID_ANY 0x0000
+
+#define BIT(n) (1UL << (n))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/* Helper macro to convert (foo, __LINE__) into foo134 so we can use __LINE__ for
+ * field/variable names
+ */
+#define COMBINE1(X, Y) X ## Y
+#define COMBINE(X, Y) COMBINE1(X, Y)
+
+/* Macro magic:
+ * __uint(foo, 123) creates a int (*foo)[1234]
+ *
+ * We use that macro to declare an anonymous struct with several
+ * fields, each is the declaration of an pointer to an array of size
+ * bus/group/vid/pid. (Because it's a pointer to such an array, actual storage
+ * would be sizeof(pointer) rather than sizeof(array). Not that we ever
+ * instantiate it anyway).
+ *
+ * This is only used for BTF introspection, we can later check "what size
+ * is the bus array" in the introspection data and thus extract the bus ID
+ * again.
+ *
+ * And we use the __LINE__ to give each of our structs a unique name so the
+ * BPF program writer doesn't have to.
+ *
+ * $ bpftool btf dump file target/bpf/HP_Elite_Presenter.bpf.o
+ * shows the inspection data, start by searching for .hid_bpf_config
+ * and working backwards from that (each entry references the type_id of the
+ * content).
+ */
+
+#define HID_DEVICE(b, g, ven, prod) \
+ struct { \
+ __uint(name, 0); \
+ __uint(bus, (b)); \
+ __uint(group, (g)); \
+ __uint(vid, (ven)); \
+ __uint(pid, (prod)); \
+ } COMBINE(_entry, __LINE__)
+
+/* Macro magic below is to make HID_BPF_CONFIG() look like a function call that
+ * we can pass multiple HID_DEVICE() invocations in.
+ *
+ * For up to 16 arguments, HID_BPF_CONFIG(one, two) resolves to
+ *
+ * union {
+ * HID_DEVICE(...);
+ * HID_DEVICE(...);
+ * } _device_ids SEC(".hid_bpf_config")
+ *
+ */
+
+/* Returns the number of macro arguments, this expands
+ * NARGS(a, b, c) to NTH_ARG(a, b, c, 15, 14, 13, .... 4, 3, 2, 1).
+ * NTH_ARG always returns the 16th argument which in our case is 3.
+ *
+ * If we want more than 16 values _COUNTDOWN and _NTH_ARG both need to be
+ * updated.
+ */
+#define _NARGS(...) _NARGS1(__VA_ARGS__, _COUNTDOWN)
+#define _NARGS1(...) _NTH_ARG(__VA_ARGS__)
+
+/* Add to this if we need more than 16 args */
+#define _COUNTDOWN \
+ 15, 14, 13, 12, 11, 10, 9, 8, \
+ 7, 6, 5, 4, 3, 2, 1, 0
+
+/* Return the 16 argument passed in. See _NARGS above for usage. Note this is
+ * 1-indexed.
+ */
+#define _NTH_ARG( \
+ _1, _2, _3, _4, _5, _6, _7, _8, \
+ _9, _10, _11, _12, _13, _14, _15,\
+ N, ...) N
+
+/* Turns EXPAND(_ARG, a, b, c) into _ARG3(a, b, c) */
+#define _EXPAND(func, ...) COMBINE(func, _NARGS(__VA_ARGS__)) (__VA_ARGS__)
+
+/* And now define all the ARG macros for each number of args we want to accept */
+#define _ARG1(_1) _1;
+#define _ARG2(_1, _2) _1; _2;
+#define _ARG3(_1, _2, _3) _1; _2; _3;
+#define _ARG4(_1, _2, _3, _4) _1; _2; _3; _4;
+#define _ARG5(_1, _2, _3, _4, _5) _1; _2; _3; _4; _5;
+#define _ARG6(_1, _2, _3, _4, _5, _6) _1; _2; _3; _4; _5; _6;
+#define _ARG7(_1, _2, _3, _4, _5, _6, _7) _1; _2; _3; _4; _5; _6; _7;
+#define _ARG8(_1, _2, _3, _4, _5, _6, _7, _8) _1; _2; _3; _4; _5; _6; _7; _8;
+#define _ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9) _1; _2; _3; _4; _5; _6; _7; _8; _9;
+#define _ARG10(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a;
+#define _ARG11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b;
+#define _ARG12(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c;
+#define _ARG13(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d;
+#define _ARG14(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d, _e) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d; _e;
+#define _ARG15(_1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, _d, _e, _f) _1; _2; _3; _4; _5; _6; _7; _8; _9; _a; _b; _c; _d; _e; _f;
+
+
+#define HID_BPF_CONFIG(...) union { \
+ _EXPAND(_ARG, __VA_ARGS__) \
+} _device_ids SEC(".hid_bpf_config")
+
+
+/* Equivalency macros for bpf_htons and friends which are
+ * Big Endian only - HID needs little endian so these are the
+ * corresponding macros for that. See bpf/bpf_endian.h
+ */
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define __hid_bpf_le16_to_cpu(x) (x)
+# define __hid_bpf_le32_to_cpu(x) (x)
+# define __hid_bpf_le64_to_cpu(x) (x)
+# define __hid_bpf_cpu_to_le16(x) (x)
+# define __hid_bpf_cpu_to_le32(x) (x)
+# define __hid_bpf_cpu_to_le64(x) (x)
+# define __hid_bpf_constant_le16_to_cpu(x) (x)
+# define __hid_bpf_constant_le32_to_cpu(x) (x)
+# define __hid_bpf_constant_le64_to_cpu(x) (x)
+# define __hid_bpf_constant_cpu_to_le16(x) (x)
+# define __hid_bpf_constant_cpu_to_le32(x) (x)
+# define __hid_bpf_constant_cpu_to_le64(x) (x)
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define __hid_bpf_le16_to_cpu(x) __builtin_bswap16(x)
+# define __hid_bpf_le32_to_cpu(x) __builtin_bswap32(x)
+# define __hid_bpf_le64_to_cpu(x) __builtin_bswap64(x)
+# define __hid_bpf_cpu_to_le16(x) __builtin_bswap16(x)
+# define __hid_bpf_cpu_to_le32(x) __builtin_bswap32(x)
+# define __hid_bpf_cpu_to_le64(x) __builtin_bswap64(x)
+# define __hid_bpf_constant_le16_to_cpu(x) __bpf_swab16(x)
+# define __hid_bpf_constant_le32_to_cpu(x) __bpf_swab32(x)
+# define __hid_bpf_constant_le64_to_cpu(x) __bpf_swab64(x)
+# define __hid_bpf_constant_cpu_to_le16(x) __bpf_swab16(x)
+# define __hid_bpf_constant_cpu_to_le32(x) __bpf_swab32(x)
+# define __hid_bpf_constant_cpu_to_le64(x) __bpf_swab64(x)
+#else
+# error "Invalid __BYTE_ORDER__"
+#endif
+
+#define hid_bpf_le16_to_cpu(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_le16_to_cpu(x) : __hid_bpf_le16_to_cpu(x))
+
+#define hid_bpf_le32_to_cpu(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_le32_to_cpu(x) : __hid_bpf_le32_to_cpu(x))
+
+#define hid_bpf_le64_to_cpu(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_le64_to_cpu(x) : __hid_bpf_le64_to_cpu(x))
+
+#define hid_bpf_cpu_to_le16(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_cpu_to_le16(x) : __hid_bpf_cpu_to_le16(x))
+
+#define hid_bpf_cpu_to_le32(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_cpu_to_le32(x) : __hid_bpf_cpu_to_le32(x))
+
+#define hid_bpf_cpu_to_le64(x) \
+ (__builtin_constant_p(x) ? \
+ __hid_bpf_constant_cpu_to_le64(x) : __hid_bpf_cpu_to_le64(x))
+
+#define hid_bpf_be16_to_cpu(x) bpf_ntohs(x)
+#define hid_bpf_be32_to_cpu(x) bpf_ntohl(x)
+#define hid_bpf_be64_to_cpu(x) bpf_be64_to_cpu(x)
+#define hid_bpf_cpu_to_be16(x) bpf_htons(x)
+#define hid_bpf_cpu_to_be32(x) bpf_htonl(x)
+#define hid_bpf_cpu_to_be64(x) bpf_cpu_to_be64(x)
+
+/*
+ * The following macros are helpers for exporting udev properties:
+ *
+ * EXPORT_UDEV_PROP(name, len) generates:
+ * - a map with a single element UDEV_PROP_##name, of size len
+ * - a const global declaration of that len: SIZEOF_##name
+ *
+ * udev_prop_ptr(name) retrieves the data pointer behind the map.
+ *
+ * UDEV_PROP_SPRINTF(name, fmt, ...) writes data into the udev property.
+ *
+ * Can be used as such:
+ * EXPORT_UDEV_PROP(HID_FOO, 32);
+ *
+ * SEC("syscall")
+ * int probe(struct hid_bpf_probe_args *ctx)
+ * {
+ * const char *foo = "foo";
+ * UDEV_PROP_SPRINTF(HID_FOO, "%s", foo);
+ *
+ * return 0;
+ * }
+ */
+#define EXPORT_UDEV_PROP(name, len) \
+ const __u32 SIZEOF_##name = len; \
+ struct COMBINE(udev_prop, __LINE__) { \
+ __uint(type, BPF_MAP_TYPE_ARRAY); \
+ __uint(max_entries, 1); \
+ __type(key, __u32); \
+ __type(value, __u8[len]); \
+ } UDEV_PROP_##name SEC(".maps");
+
+#define udev_prop_ptr(name) \
+ bpf_map_lookup_elem(&UDEV_PROP_##name, &(__u32){0})
+
+#define UDEV_PROP_SPRINTF(name, fmt, ...) \
+ BPF_SNPRINTF(udev_prop_ptr(name), SIZEOF_##name, fmt, ##__VA_ARGS__)
+
+static inline __maybe_unused __u16 field_start_byte(struct hid_rdesc_field *field)
+{
+ return field->bits_start / 8;
+}
+
+static inline __maybe_unused __u16 field_end_byte(struct hid_rdesc_field *field)
+{
+ if (!field->bits_end)
+ return 0;
+
+ return (__u16)(field->bits_end - 1) / 8;
+}
+
+static __maybe_unused __u32 extract_bits(__u8 *buffer, const size_t size, struct hid_rdesc_field *field)
+{
+ __s32 nbits = field->bits_end - field->bits_start;
+ __u32 start = field_start_byte(field);
+ __u32 end = field_end_byte(field);
+ __u8 base_shift = field->bits_start % 8;
+
+ if (nbits <= 0 || nbits > 32 || start >= size || end >= size)
+ return 0;
+
+ /* Fast path for byte-aligned standard-sized reads */
+ if (base_shift == 0) {
+ /* 8-bit aligned read */
+ if (nbits == 8 && start < size)
+ return buffer[start];
+
+ /* 16-bit aligned read - use separate variables for verifier */
+ if (nbits == 16) {
+ __u32 off0 = start;
+ __u32 off1 = start + 1;
+
+ if (off0 < size && off1 < size) {
+ return buffer[off0] |
+ ((__u32)buffer[off1] << 8);
+ }
+ }
+
+ /* 32-bit aligned read - use separate variables for verifier */
+ if (nbits == 32) {
+ __u32 off0 = start;
+ __u32 off1 = start + 1;
+ __u32 off2 = start + 2;
+ __u32 off3 = start + 3;
+
+ if (off0 < size && off1 < size &&
+ off2 < size && off3 < size) {
+ return buffer[off0] |
+ ((__u32)buffer[off1] << 8) |
+ ((__u32)buffer[off2] << 16) |
+ ((__u32)buffer[off3] << 24);
+ }
+ }
+ }
+
+ /* General case: bit manipulation for unaligned or non-standard sizes */
+ int mask = 0xffffffff >> (32 - nbits);
+ __u64 value = 0;
+ __u32 i;
+
+ bpf_for (i, start, end + 1) {
+ value |= (__u64)buffer[i] << ((i - start) * 8);
+ }
+
+ return (value >> base_shift) & mask;
+}
+
+#define EXTRACT_BITS(buffer, field) extract_bits(buffer, sizeof(buffer), field)
+
+/* Base macro for iterating over HID arrays with bounds checking.
+ * Follows the bpf_for pattern from libbpf.
+ */
+#define __hid_bpf_for_each_array(array, num_elements, max_elements, var) \
+ for ( \
+ /* initialize and define destructor */ \
+ struct bpf_iter_num ___it __attribute__((aligned(8), \
+ cleanup(bpf_iter_num_destroy))), \
+ /* ___p pointer is necessary to call bpf_iter_num_new() *once* */ \
+ *___p __attribute__((unused)) = ( \
+ /* always initialize iterator; if bounds fail, iterate 0 times */ \
+ bpf_iter_num_new(&___it, 0, \
+ (num_elements) > (max_elements) ? \
+ 0 : (num_elements)), \
+ /* workaround for Clang bug */ \
+ (void)bpf_iter_num_destroy, (void *)0); \
+ ({ \
+ /* iteration step */ \
+ int *___t = bpf_iter_num_next(&___it); \
+ int ___i; \
+ /* termination and bounds check, assign var */ \
+ (___t && (___i = *___t, ___i >= 0 && ___i < (num_elements)) && \
+ ((num_elements) <= (max_elements)) && \
+ (var = &(array)[___i], 1)); \
+ }); \
+ )
+
+/* Iterate over input reports in a descriptor */
+#define hid_bpf_for_each_input_report(descriptor, report_var) \
+ __hid_bpf_for_each_array((descriptor)->input_reports, \
+ (descriptor)->num_input_reports, \
+ HID_MAX_REPORTS, report_var)
+
+/* Iterate over feature reports in a descriptor */
+#define hid_bpf_for_each_feature_report(descriptor, report_var) \
+ __hid_bpf_for_each_array((descriptor)->feature_reports, \
+ (descriptor)->num_feature_reports, \
+ HID_MAX_REPORTS, report_var)
+
+/* Iterate over output reports in a descriptor */
+#define hid_bpf_for_each_output_report(descriptor, report_var) \
+ __hid_bpf_for_each_array((descriptor)->output_reports, \
+ (descriptor)->num_output_reports, \
+ HID_MAX_REPORTS, report_var)
+
+/* Iterate over fields in a report */
+#define hid_bpf_for_each_field(report, field_var) \
+ __hid_bpf_for_each_array((report)->fields, (report)->num_fields, \
+ HID_MAX_FIELDS, field_var)
+
+/* Iterate over collections in a field */
+#define hid_bpf_for_each_collection(field, collection_var) \
+ __hid_bpf_for_each_array((field)->collections, (field)->num_collections, \
+ HID_MAX_COLLECTIONS, collection_var)
+
+#endif /* __HID_BPF_HELPERS_H */
diff --git a/drivers/hid/bpf/progs/hid_report_descriptor_helpers.h b/drivers/hid/bpf/progs/hid_report_descriptor_helpers.h
new file mode 100644
index 000000000..2aed5c0a6
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_report_descriptor_helpers.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2022 Benjamin Tissoires
+ */
+
+#ifndef __HID_REPORT_DESCRIPTOR_HELPERS_H
+#define __HID_REPORT_DESCRIPTOR_HELPERS_H
+
+#include "vmlinux.h"
+
+/* Compiler attributes */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
+#endif
+
+/* Report Descriptor Structures */
+#define HID_MAX_COLLECTIONS 32
+#define HID_MAX_FIELDS 64
+#define HID_MAX_REPORTS 16
+
+enum hid_rdesc_field_type {
+ HID_FIELD_VARIABLE = 0,
+ HID_FIELD_ARRAY = 1,
+ HID_FIELD_CONSTANT = 2,
+};
+
+struct hid_rdesc_collection {
+ __u16 usage_page;
+ __u16 usage_id;
+ __u8 collection_type;
+} __packed;
+
+struct hid_rdesc_field {
+ __u8 field_type; /* enum hid_rdesc_field_type */
+ __u8 num_collections;
+ __u16 bits_start;
+ __u16 bits_end;
+ __u16 usage_page;
+ union {
+ __u16 usage_id; /* For Variable fields */
+ struct __packed { /* For Array fields */
+ __u16 usage_minimum;
+ __u16 usage_maximum;
+ };
+ };
+ __s32 logical_minimum;
+ __s32 logical_maximum;
+ struct {
+ __u8 is_relative:1; /* Data is relative to previous value */
+ __u8 wraps:1; /* Value wraps around (e.g., rotary encoder) */
+ __u8 is_nonlinear:1; /* Non-linear relationship between logical/physical */
+ __u8 has_no_preferred_state:1; /* No rest position (e.g., free-floating joystick) */
+ __u8 has_null_state:1; /* Can report null/no-data values */
+ __u8 is_volatile:1; /* Volatile (Output/Feature) - NOT POPULATED, always 0 */
+ __u8 is_buffered_bytes:1; /* Fixed-size byte stream vs bitfield */
+ __u8 reserved:1; /* Reserved for future use */
+ } flags;
+ struct hid_rdesc_collection collections[HID_MAX_COLLECTIONS];
+} __packed;
+
+struct hid_rdesc_report {
+ __u8 report_id; /* 0 means no report ID */
+ __u16 size_in_bits;
+ __u8 num_fields;
+ struct hid_rdesc_field fields[HID_MAX_FIELDS];
+} __packed;
+
+struct hid_rdesc_descriptor {
+ __u8 num_input_reports;
+ __u8 num_output_reports;
+ __u8 num_feature_reports;
+ struct hid_rdesc_report input_reports[HID_MAX_REPORTS];
+ struct hid_rdesc_report output_reports[HID_MAX_REPORTS];
+ struct hid_rdesc_report feature_reports[HID_MAX_REPORTS];
+} __packed;
+
+#endif /* __HID_REPORT_DESCRIPTOR_HELPERS_H */
diff --git a/drivers/hid/bpf/progs/hid_report_helpers.h b/drivers/hid/bpf/progs/hid_report_helpers.h
new file mode 100644
index 000000000..9944ff54d
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_report_helpers.h
@@ -0,0 +1,2982 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2024 Red Hat, Inc
+ */
+
+// THIS FILE IS GENERATED, DO NOT EDIT
+
+#pragma once
+
+
+/* Macros for composing HID reports.
+ *
+ * HID Fields are added manually to the template, please add to it as needed
+ * for any individual device. The Usage Pages and Usages are generated.
+ *
+ * Some macros have a _i8, _i16, or _i32 suffix. Pick the
+ * right suffix given the passed-in value.
+ */
+
+/*
+ * This macro behaves like static_assert(), failing to
+ * compile if its argument is not true. However, it always
+ * returns 0, which allows using it everywhere an expression
+ * can be used.
+ */
+#define must_be(e, msg_) \
+( \
+ 0 * (int) sizeof( \
+ struct { \
+ _Static_assert(e, msg_); \
+ int ISO_C_forbids_a_struct_with_no_members; \
+ } \
+ ) \
+)
+
+/* Ensure the given value fits within 8/16/32 bits */
+#define i4(v_) (((__u8)(v_) & 0xf) + must_be((v_) >= -0x8 && (v_) <= 0x7, "not a i4"))
+#define i8(v_) ((__u8)(v_) + must_be((v_) >= -0x80 && (v_) <= 0xff, "not a i8/u8"))
+#define i16(v_) ((__u16)(v_) + must_be((v_) >= -0x8000 && (v_) <= 0xffff, "not a i16/u16"))
+#define i32(v_) ((__u32)(v_) + must_be((v_) >= -0x80000000L && (v_) <= 0xffffffffL, \
+ "not a i32/u16"))
+
+/* Split a value across multiple bytes in LE order */
+#define LE16(v_) i16(v_) & 0xff, ((v_) >> 8) & 0xff
+#define LE32(v_) i32(v_) & 0xff, ((v_) >> 8) & 0xff, ((v_) >> 16) & 0xff, ((v_) >> 24) & 0xff
+
+/* Collections require two items in the report descriptor, the start
+ * of the collection (0xa?) and the EndCollection item (0xc?).
+ * This macro provides both, use like this:
+ *
+ * static const __u8 fixed_rdesc[] = {
+ * UsagePage_Generic_Desktop
+ * Usage_GD_Keyboard
+ * CollectionApplication( ← Open the collection
+ * ReportId(3)
+ * LogicalMinimum_i8(0)
+ * LogicalMaximum_i8(1)
+ * // other fields
+ * ) ← End EndCollection
+ *
+ * Collections may be nested.
+ */
+#define Collection(col_, ...) 0xa1, i8(col_), __VA_ARGS__ 0xc0,
+#define CollectionPhysical(...) Collection(0x00, __VA_ARGS__)
+#define CollectionApplication(...) Collection(0x01, __VA_ARGS__)
+#define CollectionLogical(...) Collection(0x02, __VA_ARGS__)
+
+/* See Collections, this macro provides Push and Pop with
+ * elements in between
+ */
+#define PushPop(...) 0xa4, __VA_ARGS__ 0xb4,
+
+/* Arguments to use in bitwise-or for Input, Output, Feature */
+#define Const 0x1
+#define Var 0x2
+#define Arr 0x0
+#define Abs 0x0
+#define Rel 0x4
+#define Null 0x40
+#define Buff 0x0100
+
+/* Use like this: Input(Var|Abs) */
+#define Input(i_) 0x081, i8(i_),
+#define Output(i_) 0x091, i8(i_),
+#define Feature(i_) 0x0b1, i8(i_),
+
+#define Input_i16(i_) 0x082, LE16(i_),
+#define Output_i16(i_) 0x092, LE16(i_),
+#define Feature_i16(i_) 0x0b2, LE16(i_),
+
+#define ReportId(id_) 0x85, i8(id_),
+#define ReportSize(sz_) 0x75, i8(sz_),
+#define ReportCount(cnt_) 0x95, i8(cnt_),
+
+#define LogicalMinimum_i8(min_) 0x15, i8(min_),
+#define LogicalMinimum_i16(min_) 0x16, LE16(min_),
+#define LogicalMinimum_i32(min_) 0x17, LE32(min_),
+
+#define LogicalMaximum_i8(max_) 0x25, i8(max_),
+#define LogicalMaximum_i16(max_) 0x26, LE16(max_),
+#define LogicalMaximum_i32(max_) 0x27, LE32(max_),
+
+#define PhysicalMinimum_i8(min_) 0x35, i8(min_),
+#define PhysicalMinimum_i16(min_) 0x36, LE16(min_),
+#define PhysicalMinimum_i32(min_) 0x37, LE32(min_),
+
+#define PhysicalMaximum_i8(max_) 0x45, i8(max_),
+#define PhysicalMaximum_i16(max_) 0x46, LE16(max_),
+#define PhysicalMaximum_i32(max_) 0x47, LE32(max_),
+
+#define UsageMinimum_i8(min_) 0x19, i8(min_),
+#define UsageMinimum_i16(min_) 0x1a, LE16(min_),
+
+#define UsageMaximum_i8(max_) 0x29, i8(max_),
+#define UsageMaximum_i16(max_) 0x2a, LE16(max_),
+
+#define UsagePage_i8(p_) 0x05, i8(p_),
+#define UsagePage_i16(p_) 0x06, LE16(p_),
+
+#define Usage_i8(u_) 0x09, i8(u_),
+#define Usage_i16(u_) 0x0a, LE16(u_),
+#define Usage_i32(u_) 0x0b, LE32(u_),
+
+#define SILinear 0x1
+#define SIRotation 0x2
+#define EnglishLinear 0x3
+#define EnglishRotation 0x4
+#define cm (SILinear | (0x1 << 4))
+#define rad (SIRotation | (0x1 << 4))
+#define deg (EnglishRotation | (0x1 << 4))
+#define in (EnglishLinear | (0x1 << 4))
+/* Use as Unit(cm) or Unit(rad) or similar.
+ * This macro currently defaults to exponent 1 only, so no
+ * cm^2 or others
+ */
+#define Unit(u_) Unit_i8(u_)
+#define Unit_i8(u_) 0x65, i8(u_),
+#define Unit_i16(u_) 0x66, i16(u_),
+#define Unit_i32(u_) 0x67, i32(u_),
+
+#define UnitExponent(u_) 0x55, i4(u_),
+
+/* A macro to generate a vendor-specific padding-only
+ * report with Report ID 0xac of the given size in bytes.
+ * The size is inclusive of the 1 byte Report ID prefix.
+ *
+ * The kernel discards any HID reports that are larger
+ * than the largest report in a HID report descriptor.
+ * Thus at least one report must have (at least)
+ * the same size as the largest original report from
+ * the device.
+ * The easy way to ensure that is to add this
+ * macro as the last element of your CollectionApplication
+ * other reports can be of any size less than this.
+ *
+ * e.g.
+ * static __u8 fixed_rdesc = [
+ * UsagePage_Generic_Desktop
+ * Usage_GD_Keyboard
+ * CollectionApplication(
+ * ... intended rdesc items go here ...
+ * FixedSizeVendorReport(12)
+ * )
+ * ];
+ *
+ * If the FixedSizeVendorReport is placed outside
+ * a CollectionApplication it will result in
+ * an extra useless evdev node being created.
+ */
+#define FixedSizeVendorReport(bytes_) \
+ UsagePage_Vendor(0xffff) \
+ Usage_i8(0x01) \
+ CollectionPhysical( \
+ ReportId(0xac) \
+ ReportSize(8) \
+ ReportCount((bytes_) - 1) \
+ Input(Const) \
+ )
+
+/* ----- Generated Usage Pages and Usages ------ */
+#define UsagePage_GenericDesktop UsagePage_i8(0x1)
+#define UsagePage_SimulationControls UsagePage_i8(0x2)
+#define UsagePage_VRControls UsagePage_i8(0x3)
+#define UsagePage_SportControls UsagePage_i8(0x4)
+#define UsagePage_GameControls UsagePage_i8(0x5)
+#define UsagePage_GenericDeviceControls UsagePage_i8(0x6)
+#define UsagePage_KeyboardKeypad UsagePage_i8(0x7)
+#define UsagePage_LED UsagePage_i8(0x8)
+#define UsagePage_Button UsagePage_i8(0x9)
+#define UsagePage_Ordinal UsagePage_i8(0xa)
+#define UsagePage_TelephonyDevice UsagePage_i8(0xb)
+#define UsagePage_Consumer UsagePage_i8(0xc)
+#define UsagePage_Digitizers UsagePage_i8(0xd)
+#define UsagePage_Haptics UsagePage_i8(0xe)
+#define UsagePage_PhysicalInputDevice UsagePage_i8(0xf)
+#define UsagePage_Unicode UsagePage_i8(0x10)
+#define UsagePage_SoC UsagePage_i8(0x11)
+#define UsagePage_EyeandHeadTrackers UsagePage_i8(0x12)
+#define UsagePage_AuxiliaryDisplay UsagePage_i8(0x14)
+#define UsagePage_Sensors UsagePage_i8(0x20)
+#define UsagePage_MedicalInstrument UsagePage_i8(0x40)
+#define UsagePage_BrailleDisplay UsagePage_i8(0x41)
+#define UsagePage_LightingAndIllumination UsagePage_i8(0x59)
+#define UsagePage_Monitor UsagePage_i8(0x80)
+#define UsagePage_MonitorEnumerated UsagePage_i8(0x81)
+#define UsagePage_VESAVirtualControls UsagePage_i8(0x82)
+#define UsagePage_Power UsagePage_i8(0x84)
+#define UsagePage_BatterySystem UsagePage_i8(0x85)
+#define UsagePage_BarcodeScanner UsagePage_i8(0x8c)
+#define UsagePage_Scales UsagePage_i8(0x8d)
+#define UsagePage_MagneticStripeReader UsagePage_i8(0x8e)
+#define UsagePage_CameraControl UsagePage_i8(0x90)
+#define UsagePage_Arcade UsagePage_i8(0x91)
+#define UsagePage_FIDOAlliance UsagePage_i16(0xf1d0)
+#define UsagePage_Vendor(u_) \
+ UsagePage_i16((u_) + must_be(((u_) & 0xff00) == 0xff00, "not a 0xff00 vendor page"))
+
+#define Usage_GD_Pointer Usage_i8(0x1)
+#define Usage_GD_Mouse Usage_i8(0x2)
+#define Usage_GD_Joystick Usage_i8(0x4)
+#define Usage_GD_Gamepad Usage_i8(0x5)
+#define Usage_GD_Keyboard Usage_i8(0x6)
+#define Usage_GD_Keypad Usage_i8(0x7)
+#define Usage_GD_MultiaxisController Usage_i8(0x8)
+#define Usage_GD_TabletPCSystemControls Usage_i8(0x9)
+#define Usage_GD_WaterCoolingDevice Usage_i8(0xa)
+#define Usage_GD_ComputerChassisDevice Usage_i8(0xb)
+#define Usage_GD_WirelessRadioControls Usage_i8(0xc)
+#define Usage_GD_PortableDeviceControl Usage_i8(0xd)
+#define Usage_GD_SystemMultiAxisController Usage_i8(0xe)
+#define Usage_GD_SpatialController Usage_i8(0xf)
+#define Usage_GD_AssistiveControl Usage_i8(0x10)
+#define Usage_GD_DeviceDock Usage_i8(0x11)
+#define Usage_GD_DockableDevice Usage_i8(0x12)
+#define Usage_GD_CallStateManagementControl Usage_i8(0x13)
+#define Usage_GD_X Usage_i8(0x30)
+#define Usage_GD_Y Usage_i8(0x31)
+#define Usage_GD_Z Usage_i8(0x32)
+#define Usage_GD_Rx Usage_i8(0x33)
+#define Usage_GD_Ry Usage_i8(0x34)
+#define Usage_GD_Rz Usage_i8(0x35)
+#define Usage_GD_Slider Usage_i8(0x36)
+#define Usage_GD_Dial Usage_i8(0x37)
+#define Usage_GD_Wheel Usage_i8(0x38)
+#define Usage_GD_HatSwitch Usage_i8(0x39)
+#define Usage_GD_CountedBuffer Usage_i8(0x3a)
+#define Usage_GD_ByteCount Usage_i8(0x3b)
+#define Usage_GD_MotionWakeup Usage_i8(0x3c)
+#define Usage_GD_Start Usage_i8(0x3d)
+#define Usage_GD_Select Usage_i8(0x3e)
+#define Usage_GD_Vx Usage_i8(0x40)
+#define Usage_GD_Vy Usage_i8(0x41)
+#define Usage_GD_Vz Usage_i8(0x42)
+#define Usage_GD_Vbrx Usage_i8(0x43)
+#define Usage_GD_Vbry Usage_i8(0x44)
+#define Usage_GD_Vbrz Usage_i8(0x45)
+#define Usage_GD_Vno Usage_i8(0x46)
+#define Usage_GD_FeatureNotification Usage_i8(0x47)
+#define Usage_GD_ResolutionMultiplier Usage_i8(0x48)
+#define Usage_GD_Qx Usage_i8(0x49)
+#define Usage_GD_Qy Usage_i8(0x4a)
+#define Usage_GD_Qz Usage_i8(0x4b)
+#define Usage_GD_Qw Usage_i8(0x4c)
+#define Usage_GD_SystemControl Usage_i8(0x80)
+#define Usage_GD_SystemPowerDown Usage_i8(0x81)
+#define Usage_GD_SystemSleep Usage_i8(0x82)
+#define Usage_GD_SystemWakeUp Usage_i8(0x83)
+#define Usage_GD_SystemContextMenu Usage_i8(0x84)
+#define Usage_GD_SystemMainMenu Usage_i8(0x85)
+#define Usage_GD_SystemAppMenu Usage_i8(0x86)
+#define Usage_GD_SystemMenuHelp Usage_i8(0x87)
+#define Usage_GD_SystemMenuExit Usage_i8(0x88)
+#define Usage_GD_SystemMenuSelect Usage_i8(0x89)
+#define Usage_GD_SystemMenuRight Usage_i8(0x8a)
+#define Usage_GD_SystemMenuLeft Usage_i8(0x8b)
+#define Usage_GD_SystemMenuUp Usage_i8(0x8c)
+#define Usage_GD_SystemMenuDown Usage_i8(0x8d)
+#define Usage_GD_SystemColdRestart Usage_i8(0x8e)
+#define Usage_GD_SystemWarmRestart Usage_i8(0x8f)
+#define Usage_GD_DpadUp Usage_i8(0x90)
+#define Usage_GD_DpadDown Usage_i8(0x91)
+#define Usage_GD_DpadRight Usage_i8(0x92)
+#define Usage_GD_DpadLeft Usage_i8(0x93)
+#define Usage_GD_IndexTrigger Usage_i8(0x94)
+#define Usage_GD_PalmTrigger Usage_i8(0x95)
+#define Usage_GD_Thumbstick Usage_i8(0x96)
+#define Usage_GD_SystemFunctionShift Usage_i8(0x97)
+#define Usage_GD_SystemFunctionShiftLock Usage_i8(0x98)
+#define Usage_GD_SystemFunctionShiftLockIndicator Usage_i8(0x99)
+#define Usage_GD_SystemDismissNotification Usage_i8(0x9a)
+#define Usage_GD_SystemDoNotDisturb Usage_i8(0x9b)
+#define Usage_GD_SystemDock Usage_i8(0xa0)
+#define Usage_GD_SystemUndock Usage_i8(0xa1)
+#define Usage_GD_SystemSetup Usage_i8(0xa2)
+#define Usage_GD_SystemBreak Usage_i8(0xa3)
+#define Usage_GD_SystemDebuggerBreak Usage_i8(0xa4)
+#define Usage_GD_ApplicationBreak Usage_i8(0xa5)
+#define Usage_GD_ApplicationDebuggerBreak Usage_i8(0xa6)
+#define Usage_GD_SystemSpeakerMute Usage_i8(0xa7)
+#define Usage_GD_SystemHibernate Usage_i8(0xa8)
+#define Usage_GD_SystemMicrophoneMute Usage_i8(0xa9)
+#define Usage_GD_SystemAccessibilityBinding Usage_i8(0xaa)
+#define Usage_GD_SystemDisplayInvert Usage_i8(0xb0)
+#define Usage_GD_SystemDisplayInternal Usage_i8(0xb1)
+#define Usage_GD_SystemDisplayExternal Usage_i8(0xb2)
+#define Usage_GD_SystemDisplayBoth Usage_i8(0xb3)
+#define Usage_GD_SystemDisplayDual Usage_i8(0xb4)
+#define Usage_GD_SystemDisplayToggleIntExtMode Usage_i8(0xb5)
+#define Usage_GD_SystemDisplaySwapPrimarySecondary Usage_i8(0xb6)
+#define Usage_GD_SystemDisplayToggleLCDAutoscale Usage_i8(0xb7)
+#define Usage_GD_SensorZone Usage_i8(0xc0)
+#define Usage_GD_RPM Usage_i8(0xc1)
+#define Usage_GD_CoolantLevel Usage_i8(0xc2)
+#define Usage_GD_CoolantCriticalLevel Usage_i8(0xc3)
+#define Usage_GD_CoolantPump Usage_i8(0xc4)
+#define Usage_GD_ChassisEnclosure Usage_i8(0xc5)
+#define Usage_GD_WirelessRadioButton Usage_i8(0xc6)
+#define Usage_GD_WirelessRadioLED Usage_i8(0xc7)
+#define Usage_GD_WirelessRadioSliderSwitch Usage_i8(0xc8)
+#define Usage_GD_SystemDisplayRotationLockButton Usage_i8(0xc9)
+#define Usage_GD_SystemDisplayRotationLockSliderSwitch Usage_i8(0xca)
+#define Usage_GD_ControlEnable Usage_i8(0xcb)
+#define Usage_GD_DockableDeviceUniqueID Usage_i8(0xd0)
+#define Usage_GD_DockableDeviceVendorID Usage_i8(0xd1)
+#define Usage_GD_DockableDevicePrimaryUsagePage Usage_i8(0xd2)
+#define Usage_GD_DockableDevicePrimaryUsageID Usage_i8(0xd3)
+#define Usage_GD_DockableDeviceDockingState Usage_i8(0xd4)
+#define Usage_GD_DockableDeviceDisplayOcclusion Usage_i8(0xd5)
+#define Usage_GD_DockableDeviceObjectType Usage_i8(0xd6)
+#define Usage_GD_CallActiveLED Usage_i8(0xe0)
+#define Usage_GD_CallMuteToggle Usage_i8(0xe1)
+#define Usage_GD_CallMuteLED Usage_i8(0xe2)
+#define Usage_SC_FlightSimulationDevice Usage_i8(0x1)
+#define Usage_SC_AutomobileSimulationDevice Usage_i8(0x2)
+#define Usage_SC_TankSimulationDevice Usage_i8(0x3)
+#define Usage_SC_SpaceshipSimulationDevice Usage_i8(0x4)
+#define Usage_SC_SubmarineSimulationDevice Usage_i8(0x5)
+#define Usage_SC_SailingSimulationDevice Usage_i8(0x6)
+#define Usage_SC_MotorcycleSimulationDevice Usage_i8(0x7)
+#define Usage_SC_SportsSimulationDevice Usage_i8(0x8)
+#define Usage_SC_AirplaneSimulationDevice Usage_i8(0x9)
+#define Usage_SC_HelicopterSimulationDevice Usage_i8(0xa)
+#define Usage_SC_MagicCarpetSimulationDevice Usage_i8(0xb)
+#define Usage_SC_BicycleSimulationDevice Usage_i8(0xc)
+#define Usage_SC_FlightControlStick Usage_i8(0x20)
+#define Usage_SC_FlightStick Usage_i8(0x21)
+#define Usage_SC_CyclicControl Usage_i8(0x22)
+#define Usage_SC_CyclicTrim Usage_i8(0x23)
+#define Usage_SC_FlightYoke Usage_i8(0x24)
+#define Usage_SC_TrackControl Usage_i8(0x25)
+#define Usage_SC_Aileron Usage_i8(0xb0)
+#define Usage_SC_AileronTrim Usage_i8(0xb1)
+#define Usage_SC_AntiTorqueControl Usage_i8(0xb2)
+#define Usage_SC_AutopilotEnable Usage_i8(0xb3)
+#define Usage_SC_ChaffRelease Usage_i8(0xb4)
+#define Usage_SC_CollectiveControl Usage_i8(0xb5)
+#define Usage_SC_DiveBrake Usage_i8(0xb6)
+#define Usage_SC_ElectronicCountermeasures Usage_i8(0xb7)
+#define Usage_SC_Elevator Usage_i8(0xb8)
+#define Usage_SC_ElevatorTrim Usage_i8(0xb9)
+#define Usage_SC_Rudder Usage_i8(0xba)
+#define Usage_SC_Throttle Usage_i8(0xbb)
+#define Usage_SC_FlightCommunications Usage_i8(0xbc)
+#define Usage_SC_FlareRelease Usage_i8(0xbd)
+#define Usage_SC_LandingGear Usage_i8(0xbe)
+#define Usage_SC_ToeBrake Usage_i8(0xbf)
+#define Usage_SC_Trigger Usage_i8(0xc0)
+#define Usage_SC_WeaponsArm Usage_i8(0xc1)
+#define Usage_SC_WeaponsSelect Usage_i8(0xc2)
+#define Usage_SC_WingFlaps Usage_i8(0xc3)
+#define Usage_SC_Accelerator Usage_i8(0xc4)
+#define Usage_SC_Brake Usage_i8(0xc5)
+#define Usage_SC_Clutch Usage_i8(0xc6)
+#define Usage_SC_Shifter Usage_i8(0xc7)
+#define Usage_SC_Steering Usage_i8(0xc8)
+#define Usage_SC_TurretDirection Usage_i8(0xc9)
+#define Usage_SC_BarrelElevation Usage_i8(0xca)
+#define Usage_SC_DivePlane Usage_i8(0xcb)
+#define Usage_SC_Ballast Usage_i8(0xcc)
+#define Usage_SC_BicycleCrank Usage_i8(0xcd)
+#define Usage_SC_HandleBars Usage_i8(0xce)
+#define Usage_SC_FrontBrake Usage_i8(0xcf)
+#define Usage_SC_RearBrake Usage_i8(0xd0)
+#define Usage_VRC_Belt Usage_i8(0x1)
+#define Usage_VRC_BodySuit Usage_i8(0x2)
+#define Usage_VRC_Flexor Usage_i8(0x3)
+#define Usage_VRC_Glove Usage_i8(0x4)
+#define Usage_VRC_HeadTracker Usage_i8(0x5)
+#define Usage_VRC_HeadMountedDisplay Usage_i8(0x6)
+#define Usage_VRC_HandTracker Usage_i8(0x7)
+#define Usage_VRC_Oculometer Usage_i8(0x8)
+#define Usage_VRC_Vest Usage_i8(0x9)
+#define Usage_VRC_AnimatronicDevice Usage_i8(0xa)
+#define Usage_VRC_StereoEnable Usage_i8(0x20)
+#define Usage_VRC_DisplayEnable Usage_i8(0x21)
+#define Usage_SC_BaseballBat Usage_i8(0x1)
+#define Usage_SC_GolfClub Usage_i8(0x2)
+#define Usage_SC_RowingMachine Usage_i8(0x3)
+#define Usage_SC_Treadmill Usage_i8(0x4)
+#define Usage_SC_Oar Usage_i8(0x30)
+#define Usage_SC_Slope Usage_i8(0x31)
+#define Usage_SC_Rate Usage_i8(0x32)
+#define Usage_SC_StickSpeed Usage_i8(0x33)
+#define Usage_SC_StickFaceAngle Usage_i8(0x34)
+#define Usage_SC_StickHeelToe Usage_i8(0x35)
+#define Usage_SC_StickFollowThrough Usage_i8(0x36)
+#define Usage_SC_StickTempo Usage_i8(0x37)
+#define Usage_SC_StickType Usage_i8(0x38)
+#define Usage_SC_StickHeight Usage_i8(0x39)
+#define Usage_SC_Putter Usage_i8(0x50)
+#define Usage_SC_OneIron Usage_i8(0x51)
+#define Usage_SC_TwoIron Usage_i8(0x52)
+#define Usage_SC_ThreeIron Usage_i8(0x53)
+#define Usage_SC_FourIron Usage_i8(0x54)
+#define Usage_SC_FiveIron Usage_i8(0x55)
+#define Usage_SC_SixIron Usage_i8(0x56)
+#define Usage_SC_SevenIron Usage_i8(0x57)
+#define Usage_SC_EightIron Usage_i8(0x58)
+#define Usage_SC_NineIron Usage_i8(0x59)
+#define Usage_SC_One0Iron Usage_i8(0x5a)
+#define Usage_SC_One1Iron Usage_i8(0x5b)
+#define Usage_SC_SandWedge Usage_i8(0x5c)
+#define Usage_SC_LoftWedge Usage_i8(0x5d)
+#define Usage_SC_PowerWedge Usage_i8(0x5e)
+#define Usage_SC_OneWood Usage_i8(0x5f)
+#define Usage_SC_ThreeWood Usage_i8(0x60)
+#define Usage_SC_FiveWood Usage_i8(0x61)
+#define Usage_SC_SevenWood Usage_i8(0x62)
+#define Usage_SC_NineWood Usage_i8(0x63)
+#define Usage_GC_ThreeDGameController Usage_i8(0x1)
+#define Usage_GC_PinballDevice Usage_i8(0x2)
+#define Usage_GC_GunDevice Usage_i8(0x3)
+#define Usage_GC_PointofView Usage_i8(0x20)
+#define Usage_GC_TurnRightLeft Usage_i8(0x21)
+#define Usage_GC_PitchForwardBackward Usage_i8(0x22)
+#define Usage_GC_RollRightLeft Usage_i8(0x23)
+#define Usage_GC_MoveRightLeft Usage_i8(0x24)
+#define Usage_GC_MoveForwardBackward Usage_i8(0x25)
+#define Usage_GC_MoveUpDown Usage_i8(0x26)
+#define Usage_GC_LeanRightLeft Usage_i8(0x27)
+#define Usage_GC_LeanForwardBackward Usage_i8(0x28)
+#define Usage_GC_HeightofPOV Usage_i8(0x29)
+#define Usage_GC_Flipper Usage_i8(0x2a)
+#define Usage_GC_SecondaryFlipper Usage_i8(0x2b)
+#define Usage_GC_Bump Usage_i8(0x2c)
+#define Usage_GC_NewGame Usage_i8(0x2d)
+#define Usage_GC_ShootBall Usage_i8(0x2e)
+#define Usage_GC_Player Usage_i8(0x2f)
+#define Usage_GC_GunBolt Usage_i8(0x30)
+#define Usage_GC_GunClip Usage_i8(0x31)
+#define Usage_GC_GunSelector Usage_i8(0x32)
+#define Usage_GC_GunSingleShot Usage_i8(0x33)
+#define Usage_GC_GunBurst Usage_i8(0x34)
+#define Usage_GC_GunAutomatic Usage_i8(0x35)
+#define Usage_GC_GunSafety Usage_i8(0x36)
+#define Usage_GC_GamepadFireJump Usage_i8(0x37)
+#define Usage_GC_GamepadTrigger Usage_i8(0x39)
+#define Usage_GC_FormfittingGamepad Usage_i8(0x3a)
+#define Usage_GDC_BackgroundNonuserControls Usage_i8(0x1)
+#define Usage_GDC_BatteryStrength Usage_i8(0x20)
+#define Usage_GDC_WirelessChannel Usage_i8(0x21)
+#define Usage_GDC_WirelessID Usage_i8(0x22)
+#define Usage_GDC_DiscoverWirelessControl Usage_i8(0x23)
+#define Usage_GDC_SecurityCodeCharacterEntered Usage_i8(0x24)
+#define Usage_GDC_SecurityCodeCharacterErased Usage_i8(0x25)
+#define Usage_GDC_SecurityCodeCleared Usage_i8(0x26)
+#define Usage_GDC_SequenceID Usage_i8(0x27)
+#define Usage_GDC_SequenceIDReset Usage_i8(0x28)
+#define Usage_GDC_RFSignalStrength Usage_i8(0x29)
+#define Usage_GDC_SoftwareVersion Usage_i8(0x2a)
+#define Usage_GDC_ProtocolVersion Usage_i8(0x2b)
+#define Usage_GDC_HardwareVersion Usage_i8(0x2c)
+#define Usage_GDC_Major Usage_i8(0x2d)
+#define Usage_GDC_Minor Usage_i8(0x2e)
+#define Usage_GDC_Revision Usage_i8(0x2f)
+#define Usage_GDC_Handedness Usage_i8(0x30)
+#define Usage_GDC_EitherHand Usage_i8(0x31)
+#define Usage_GDC_LeftHand Usage_i8(0x32)
+#define Usage_GDC_RightHand Usage_i8(0x33)
+#define Usage_GDC_BothHands Usage_i8(0x34)
+#define Usage_GDC_GripPoseOffset Usage_i8(0x40)
+#define Usage_GDC_PointerPoseOffset Usage_i8(0x41)
+#define Usage_KK_ErrorRollOver Usage_i8(0x1)
+#define Usage_KK_POSTFail Usage_i8(0x2)
+#define Usage_KK_ErrorUndefined Usage_i8(0x3)
+#define Usage_KK_KeyboardA Usage_i8(0x4)
+#define Usage_KK_KeyboardB Usage_i8(0x5)
+#define Usage_KK_KeyboardC Usage_i8(0x6)
+#define Usage_KK_KeyboardD Usage_i8(0x7)
+#define Usage_KK_KeyboardE Usage_i8(0x8)
+#define Usage_KK_KeyboardF Usage_i8(0x9)
+#define Usage_KK_KeyboardG Usage_i8(0xa)
+#define Usage_KK_KeyboardH Usage_i8(0xb)
+#define Usage_KK_KeyboardI Usage_i8(0xc)
+#define Usage_KK_KeyboardJ Usage_i8(0xd)
+#define Usage_KK_KeyboardK Usage_i8(0xe)
+#define Usage_KK_KeyboardL Usage_i8(0xf)
+#define Usage_KK_KeyboardM Usage_i8(0x10)
+#define Usage_KK_KeyboardN Usage_i8(0x11)
+#define Usage_KK_KeyboardO Usage_i8(0x12)
+#define Usage_KK_KeyboardP Usage_i8(0x13)
+#define Usage_KK_KeyboardQ Usage_i8(0x14)
+#define Usage_KK_KeyboardR Usage_i8(0x15)
+#define Usage_KK_KeyboardS Usage_i8(0x16)
+#define Usage_KK_KeyboardT Usage_i8(0x17)
+#define Usage_KK_KeyboardU Usage_i8(0x18)
+#define Usage_KK_KeyboardV Usage_i8(0x19)
+#define Usage_KK_KeyboardW Usage_i8(0x1a)
+#define Usage_KK_KeyboardX Usage_i8(0x1b)
+#define Usage_KK_KeyboardY Usage_i8(0x1c)
+#define Usage_KK_KeyboardZ Usage_i8(0x1d)
+#define Usage_KK_Keyboard1andBang Usage_i8(0x1e)
+#define Usage_KK_Keyboard2andAt Usage_i8(0x1f)
+#define Usage_KK_Keyboard3andHash Usage_i8(0x20)
+#define Usage_KK_Keyboard4andDollar Usage_i8(0x21)
+#define Usage_KK_Keyboard5andPercent Usage_i8(0x22)
+#define Usage_KK_Keyboard6andCaret Usage_i8(0x23)
+#define Usage_KK_Keyboard7andAmpersand Usage_i8(0x24)
+#define Usage_KK_Keyboard8andStar Usage_i8(0x25)
+#define Usage_KK_Keyboard9andLeftBracket Usage_i8(0x26)
+#define Usage_KK_Keyboard0andRightBracket Usage_i8(0x27)
+#define Usage_KK_KeyboardReturnEnter Usage_i8(0x28)
+#define Usage_KK_KeyboardEscape Usage_i8(0x29)
+#define Usage_KK_KeyboardDelete Usage_i8(0x2a)
+#define Usage_KK_KeyboardTab Usage_i8(0x2b)
+#define Usage_KK_KeyboardSpacebar Usage_i8(0x2c)
+#define Usage_KK_KeyboardDashandUnderscore Usage_i8(0x2d)
+#define Usage_KK_KeyboardEqualsandPlus Usage_i8(0x2e)
+#define Usage_KK_KeyboardLeftBrace Usage_i8(0x2f)
+#define Usage_KK_KeyboardRightBrace Usage_i8(0x30)
+#define Usage_KK_KeyboardBackslashandPipe Usage_i8(0x31)
+#define Usage_KK_KeyboardNonUSHashandTilde Usage_i8(0x32)
+#define Usage_KK_KeyboardSemiColonandColon Usage_i8(0x33)
+#define Usage_KK_KeyboardLeftAposandDouble Usage_i8(0x34)
+#define Usage_KK_KeyboardGraveAccentandTilde Usage_i8(0x35)
+#define Usage_KK_KeyboardCommaandLessThan Usage_i8(0x36)
+#define Usage_KK_KeyboardPeriodandGreaterThan Usage_i8(0x37)
+#define Usage_KK_KeyboardForwardSlashandQuestionMark Usage_i8(0x38)
+#define Usage_KK_KeyboardCapsLock Usage_i8(0x39)
+#define Usage_KK_KeyboardF1 Usage_i8(0x3a)
+#define Usage_KK_KeyboardF2 Usage_i8(0x3b)
+#define Usage_KK_KeyboardF3 Usage_i8(0x3c)
+#define Usage_KK_KeyboardF4 Usage_i8(0x3d)
+#define Usage_KK_KeyboardF5 Usage_i8(0x3e)
+#define Usage_KK_KeyboardF6 Usage_i8(0x3f)
+#define Usage_KK_KeyboardF7 Usage_i8(0x40)
+#define Usage_KK_KeyboardF8 Usage_i8(0x41)
+#define Usage_KK_KeyboardF9 Usage_i8(0x42)
+#define Usage_KK_KeyboardF10 Usage_i8(0x43)
+#define Usage_KK_KeyboardF11 Usage_i8(0x44)
+#define Usage_KK_KeyboardF12 Usage_i8(0x45)
+#define Usage_KK_KeyboardPrintScreen Usage_i8(0x46)
+#define Usage_KK_KeyboardScrollLock Usage_i8(0x47)
+#define Usage_KK_KeyboardPause Usage_i8(0x48)
+#define Usage_KK_KeyboardInsert Usage_i8(0x49)
+#define Usage_KK_KeyboardHome Usage_i8(0x4a)
+#define Usage_KK_KeyboardPageUp Usage_i8(0x4b)
+#define Usage_KK_KeyboardDeleteForward Usage_i8(0x4c)
+#define Usage_KK_KeyboardEnd Usage_i8(0x4d)
+#define Usage_KK_KeyboardPageDown Usage_i8(0x4e)
+#define Usage_KK_KeyboardRightArrow Usage_i8(0x4f)
+#define Usage_KK_KeyboardLeftArrow Usage_i8(0x50)
+#define Usage_KK_KeyboardDownArrow Usage_i8(0x51)
+#define Usage_KK_KeyboardUpArrow Usage_i8(0x52)
+#define Usage_KK_KeypadNumLockandClear Usage_i8(0x53)
+#define Usage_KK_KeypadForwardSlash Usage_i8(0x54)
+#define Usage_KK_KeypadStar Usage_i8(0x55)
+#define Usage_KK_KeypadDash Usage_i8(0x56)
+#define Usage_KK_KeypadPlus Usage_i8(0x57)
+#define Usage_KK_KeypadENTER Usage_i8(0x58)
+#define Usage_KK_Keypad1andEnd Usage_i8(0x59)
+#define Usage_KK_Keypad2andDownArrow Usage_i8(0x5a)
+#define Usage_KK_Keypad3andPageDn Usage_i8(0x5b)
+#define Usage_KK_Keypad4andLeftArrow Usage_i8(0x5c)
+#define Usage_KK_Keypad5 Usage_i8(0x5d)
+#define Usage_KK_Keypad6andRightArrow Usage_i8(0x5e)
+#define Usage_KK_Keypad7andHome Usage_i8(0x5f)
+#define Usage_KK_Keypad8andUpArrow Usage_i8(0x60)
+#define Usage_KK_Keypad9andPageUp Usage_i8(0x61)
+#define Usage_KK_Keypad0andInsert Usage_i8(0x62)
+#define Usage_KK_KeypadPeriodandDelete Usage_i8(0x63)
+#define Usage_KK_KeyboardNonUSBackslashandPipe Usage_i8(0x64)
+#define Usage_KK_KeyboardApplication Usage_i8(0x65)
+#define Usage_KK_KeyboardPower Usage_i8(0x66)
+#define Usage_KK_KeypadEquals Usage_i8(0x67)
+#define Usage_KK_KeyboardF13 Usage_i8(0x68)
+#define Usage_KK_KeyboardF14 Usage_i8(0x69)
+#define Usage_KK_KeyboardF15 Usage_i8(0x6a)
+#define Usage_KK_KeyboardF16 Usage_i8(0x6b)
+#define Usage_KK_KeyboardF17 Usage_i8(0x6c)
+#define Usage_KK_KeyboardF18 Usage_i8(0x6d)
+#define Usage_KK_KeyboardF19 Usage_i8(0x6e)
+#define Usage_KK_KeyboardF20 Usage_i8(0x6f)
+#define Usage_KK_KeyboardF21 Usage_i8(0x70)
+#define Usage_KK_KeyboardF22 Usage_i8(0x71)
+#define Usage_KK_KeyboardF23 Usage_i8(0x72)
+#define Usage_KK_KeyboardF24 Usage_i8(0x73)
+#define Usage_KK_KeyboardExecute Usage_i8(0x74)
+#define Usage_KK_KeyboardHelp Usage_i8(0x75)
+#define Usage_KK_KeyboardMenu Usage_i8(0x76)
+#define Usage_KK_KeyboardSelect Usage_i8(0x77)
+#define Usage_KK_KeyboardStop Usage_i8(0x78)
+#define Usage_KK_KeyboardAgain Usage_i8(0x79)
+#define Usage_KK_KeyboardUndo Usage_i8(0x7a)
+#define Usage_KK_KeyboardCut Usage_i8(0x7b)
+#define Usage_KK_KeyboardCopy Usage_i8(0x7c)
+#define Usage_KK_KeyboardPaste Usage_i8(0x7d)
+#define Usage_KK_KeyboardFind Usage_i8(0x7e)
+#define Usage_KK_KeyboardMute Usage_i8(0x7f)
+#define Usage_KK_KeyboardVolumeUp Usage_i8(0x80)
+#define Usage_KK_KeyboardVolumeDown Usage_i8(0x81)
+#define Usage_KK_KeyboardLockingCapsLock Usage_i8(0x82)
+#define Usage_KK_KeyboardLockingNumLock Usage_i8(0x83)
+#define Usage_KK_KeyboardLockingScrollLock Usage_i8(0x84)
+#define Usage_KK_KeypadComma Usage_i8(0x85)
+#define Usage_KK_KeypadEqualSign Usage_i8(0x86)
+#define Usage_KK_KeyboardInternational1 Usage_i8(0x87)
+#define Usage_KK_KeyboardInternational2 Usage_i8(0x88)
+#define Usage_KK_KeyboardInternational3 Usage_i8(0x89)
+#define Usage_KK_KeyboardInternational4 Usage_i8(0x8a)
+#define Usage_KK_KeyboardInternational5 Usage_i8(0x8b)
+#define Usage_KK_KeyboardInternational6 Usage_i8(0x8c)
+#define Usage_KK_KeyboardInternational7 Usage_i8(0x8d)
+#define Usage_KK_KeyboardInternational8 Usage_i8(0x8e)
+#define Usage_KK_KeyboardInternational9 Usage_i8(0x8f)
+#define Usage_KK_KeyboardLANG1 Usage_i8(0x90)
+#define Usage_KK_KeyboardLANG2 Usage_i8(0x91)
+#define Usage_KK_KeyboardLANG3 Usage_i8(0x92)
+#define Usage_KK_KeyboardLANG4 Usage_i8(0x93)
+#define Usage_KK_KeyboardLANG5 Usage_i8(0x94)
+#define Usage_KK_KeyboardLANG6 Usage_i8(0x95)
+#define Usage_KK_KeyboardLANG7 Usage_i8(0x96)
+#define Usage_KK_KeyboardLANG8 Usage_i8(0x97)
+#define Usage_KK_KeyboardLANG9 Usage_i8(0x98)
+#define Usage_KK_KeyboardAlternateErase Usage_i8(0x99)
+#define Usage_KK_KeyboardSysReqAttention Usage_i8(0x9a)
+#define Usage_KK_KeyboardCancel Usage_i8(0x9b)
+#define Usage_KK_KeyboardClear Usage_i8(0x9c)
+#define Usage_KK_KeyboardPrior Usage_i8(0x9d)
+#define Usage_KK_KeyboardReturn Usage_i8(0x9e)
+#define Usage_KK_KeyboardSeparator Usage_i8(0x9f)
+#define Usage_KK_KeyboardOut Usage_i8(0xa0)
+#define Usage_KK_KeyboardOper Usage_i8(0xa1)
+#define Usage_KK_KeyboardClearAgain Usage_i8(0xa2)
+#define Usage_KK_KeyboardCrSelProps Usage_i8(0xa3)
+#define Usage_KK_KeyboardExSel Usage_i8(0xa4)
+#define Usage_KK_KeypadDouble0 Usage_i8(0xb0)
+#define Usage_KK_KeypadTriple0 Usage_i8(0xb1)
+#define Usage_KK_ThousandsSeparator Usage_i8(0xb2)
+#define Usage_KK_DecimalSeparator Usage_i8(0xb3)
+#define Usage_KK_CurrencyUnit Usage_i8(0xb4)
+#define Usage_KK_CurrencySubunit Usage_i8(0xb5)
+#define Usage_KK_KeypadLeftBracket Usage_i8(0xb6)
+#define Usage_KK_KeypadRightBracket Usage_i8(0xb7)
+#define Usage_KK_KeypadLeftBrace Usage_i8(0xb8)
+#define Usage_KK_KeypadRightBrace Usage_i8(0xb9)
+#define Usage_KK_KeypadTab Usage_i8(0xba)
+#define Usage_KK_KeypadBackspace Usage_i8(0xbb)
+#define Usage_KK_KeypadA Usage_i8(0xbc)
+#define Usage_KK_KeypadB Usage_i8(0xbd)
+#define Usage_KK_KeypadC Usage_i8(0xbe)
+#define Usage_KK_KeypadD Usage_i8(0xbf)
+#define Usage_KK_KeypadE Usage_i8(0xc0)
+#define Usage_KK_KeypadF Usage_i8(0xc1)
+#define Usage_KK_KeypadXOR Usage_i8(0xc2)
+#define Usage_KK_KeypadCaret Usage_i8(0xc3)
+#define Usage_KK_KeypadPercentage Usage_i8(0xc4)
+#define Usage_KK_KeypadLess Usage_i8(0xc5)
+#define Usage_KK_KeypadGreater Usage_i8(0xc6)
+#define Usage_KK_KeypadAmpersand Usage_i8(0xc7)
+#define Usage_KK_KeypadDoubleAmpersand Usage_i8(0xc8)
+#define Usage_KK_KeypadBar Usage_i8(0xc9)
+#define Usage_KK_KeypadDoubleBar Usage_i8(0xca)
+#define Usage_KK_KeypadColon Usage_i8(0xcb)
+#define Usage_KK_KeypadHash Usage_i8(0xcc)
+#define Usage_KK_KeypadSpace Usage_i8(0xcd)
+#define Usage_KK_KeypadAt Usage_i8(0xce)
+#define Usage_KK_KeypadBang Usage_i8(0xcf)
+#define Usage_KK_KeypadMemoryStore Usage_i8(0xd0)
+#define Usage_KK_KeypadMemoryRecall Usage_i8(0xd1)
+#define Usage_KK_KeypadMemoryClear Usage_i8(0xd2)
+#define Usage_KK_KeypadMemoryAdd Usage_i8(0xd3)
+#define Usage_KK_KeypadMemorySubtract Usage_i8(0xd4)
+#define Usage_KK_KeypadMemoryMultiply Usage_i8(0xd5)
+#define Usage_KK_KeypadMemoryDivide Usage_i8(0xd6)
+#define Usage_KK_KeypadPlusMinus Usage_i8(0xd7)
+#define Usage_KK_KeypadClear Usage_i8(0xd8)
+#define Usage_KK_KeypadClearEntry Usage_i8(0xd9)
+#define Usage_KK_KeypadBinary Usage_i8(0xda)
+#define Usage_KK_KeypadOctal Usage_i8(0xdb)
+#define Usage_KK_KeypadDecimal Usage_i8(0xdc)
+#define Usage_KK_KeypadHexadecimal Usage_i8(0xdd)
+#define Usage_KK_KeyboardLeftControl Usage_i8(0xe0)
+#define Usage_KK_KeyboardLeftShift Usage_i8(0xe1)
+#define Usage_KK_KeyboardLeftAlt Usage_i8(0xe2)
+#define Usage_KK_KeyboardLeftGUI Usage_i8(0xe3)
+#define Usage_KK_KeyboardRightControl Usage_i8(0xe4)
+#define Usage_KK_KeyboardRightShift Usage_i8(0xe5)
+#define Usage_KK_KeyboardRightAlt Usage_i8(0xe6)
+#define Usage_KK_KeyboardRightGUI Usage_i8(0xe7)
+#define Usage_LED_NumLock Usage_i8(0x1)
+#define Usage_LED_CapsLock Usage_i8(0x2)
+#define Usage_LED_ScrollLock Usage_i8(0x3)
+#define Usage_LED_Compose Usage_i8(0x4)
+#define Usage_LED_Kana Usage_i8(0x5)
+#define Usage_LED_Power Usage_i8(0x6)
+#define Usage_LED_Shift Usage_i8(0x7)
+#define Usage_LED_DoNotDisturb Usage_i8(0x8)
+#define Usage_LED_Mute Usage_i8(0x9)
+#define Usage_LED_ToneEnable Usage_i8(0xa)
+#define Usage_LED_HighCutFilter Usage_i8(0xb)
+#define Usage_LED_LowCutFilter Usage_i8(0xc)
+#define Usage_LED_EqualizerEnable Usage_i8(0xd)
+#define Usage_LED_SoundFieldOn Usage_i8(0xe)
+#define Usage_LED_SurroundOn Usage_i8(0xf)
+#define Usage_LED_Repeat Usage_i8(0x10)
+#define Usage_LED_Stereo Usage_i8(0x11)
+#define Usage_LED_SamplingRateDetect Usage_i8(0x12)
+#define Usage_LED_Spinning Usage_i8(0x13)
+#define Usage_LED_CAV Usage_i8(0x14)
+#define Usage_LED_CLV Usage_i8(0x15)
+#define Usage_LED_RecordingFormatDetect Usage_i8(0x16)
+#define Usage_LED_OffHook Usage_i8(0x17)
+#define Usage_LED_Ring Usage_i8(0x18)
+#define Usage_LED_MessageWaiting Usage_i8(0x19)
+#define Usage_LED_DataMode Usage_i8(0x1a)
+#define Usage_LED_BatteryOperation Usage_i8(0x1b)
+#define Usage_LED_BatteryOK Usage_i8(0x1c)
+#define Usage_LED_BatteryLow Usage_i8(0x1d)
+#define Usage_LED_Speaker Usage_i8(0x1e)
+#define Usage_LED_Headset Usage_i8(0x1f)
+#define Usage_LED_Hold Usage_i8(0x20)
+#define Usage_LED_Microphone Usage_i8(0x21)
+#define Usage_LED_Coverage Usage_i8(0x22)
+#define Usage_LED_NightMode Usage_i8(0x23)
+#define Usage_LED_SendCalls Usage_i8(0x24)
+#define Usage_LED_CallPickup Usage_i8(0x25)
+#define Usage_LED_Conference Usage_i8(0x26)
+#define Usage_LED_Standby Usage_i8(0x27)
+#define Usage_LED_CameraOn Usage_i8(0x28)
+#define Usage_LED_CameraOff Usage_i8(0x29)
+#define Usage_LED_OnLine Usage_i8(0x2a)
+#define Usage_LED_OffLine Usage_i8(0x2b)
+#define Usage_LED_Busy Usage_i8(0x2c)
+#define Usage_LED_Ready Usage_i8(0x2d)
+#define Usage_LED_PaperOut Usage_i8(0x2e)
+#define Usage_LED_PaperJam Usage_i8(0x2f)
+#define Usage_LED_Remote Usage_i8(0x30)
+#define Usage_LED_Forward Usage_i8(0x31)
+#define Usage_LED_Reverse Usage_i8(0x32)
+#define Usage_LED_Stop Usage_i8(0x33)
+#define Usage_LED_Rewind Usage_i8(0x34)
+#define Usage_LED_FastForward Usage_i8(0x35)
+#define Usage_LED_Play Usage_i8(0x36)
+#define Usage_LED_Pause Usage_i8(0x37)
+#define Usage_LED_Record Usage_i8(0x38)
+#define Usage_LED_Error Usage_i8(0x39)
+#define Usage_LED_UsageSelectedIndicator Usage_i8(0x3a)
+#define Usage_LED_UsageInUseIndicator Usage_i8(0x3b)
+#define Usage_LED_UsageMultiModeIndicator Usage_i8(0x3c)
+#define Usage_LED_IndicatorOn Usage_i8(0x3d)
+#define Usage_LED_IndicatorFlash Usage_i8(0x3e)
+#define Usage_LED_IndicatorSlowBlink Usage_i8(0x3f)
+#define Usage_LED_IndicatorFastBlink Usage_i8(0x40)
+#define Usage_LED_IndicatorOff Usage_i8(0x41)
+#define Usage_LED_FlashOnTime Usage_i8(0x42)
+#define Usage_LED_SlowBlinkOnTime Usage_i8(0x43)
+#define Usage_LED_SlowBlinkOffTime Usage_i8(0x44)
+#define Usage_LED_FastBlinkOnTime Usage_i8(0x45)
+#define Usage_LED_FastBlinkOffTime Usage_i8(0x46)
+#define Usage_LED_UsageIndicatorColor Usage_i8(0x47)
+#define Usage_LED_IndicatorRed Usage_i8(0x48)
+#define Usage_LED_IndicatorGreen Usage_i8(0x49)
+#define Usage_LED_IndicatorAmber Usage_i8(0x4a)
+#define Usage_LED_GenericIndicator Usage_i8(0x4b)
+#define Usage_LED_SystemSuspend Usage_i8(0x4c)
+#define Usage_LED_ExternalPowerConnected Usage_i8(0x4d)
+#define Usage_LED_IndicatorBlue Usage_i8(0x4e)
+#define Usage_LED_IndicatorOrange Usage_i8(0x4f)
+#define Usage_LED_GoodStatus Usage_i8(0x50)
+#define Usage_LED_WarningStatus Usage_i8(0x51)
+#define Usage_LED_RGBLED Usage_i8(0x52)
+#define Usage_LED_RedLEDChannel Usage_i8(0x53)
+#define Usage_LED_BlueLEDChannel Usage_i8(0x54)
+#define Usage_LED_GreenLEDChannel Usage_i8(0x55)
+#define Usage_LED_LEDIntensity Usage_i8(0x56)
+#define Usage_LED_SystemMicrophoneMute Usage_i8(0x57)
+#define Usage_LED_PlayerIndicator Usage_i8(0x60)
+#define Usage_LED_Player1 Usage_i8(0x61)
+#define Usage_LED_Player2 Usage_i8(0x62)
+#define Usage_LED_Player3 Usage_i8(0x63)
+#define Usage_LED_Player4 Usage_i8(0x64)
+#define Usage_LED_Player5 Usage_i8(0x65)
+#define Usage_LED_Player6 Usage_i8(0x66)
+#define Usage_LED_Player7 Usage_i8(0x67)
+#define Usage_LED_Player8 Usage_i8(0x68)
+#define Usage_TD_Phone Usage_i8(0x1)
+#define Usage_TD_AnsweringMachine Usage_i8(0x2)
+#define Usage_TD_MessageControls Usage_i8(0x3)
+#define Usage_TD_Handset Usage_i8(0x4)
+#define Usage_TD_Headset Usage_i8(0x5)
+#define Usage_TD_TelephonyKeyPad Usage_i8(0x6)
+#define Usage_TD_ProgrammableButton Usage_i8(0x7)
+#define Usage_TD_HookSwitch Usage_i8(0x20)
+#define Usage_TD_Flash Usage_i8(0x21)
+#define Usage_TD_Feature Usage_i8(0x22)
+#define Usage_TD_Hold Usage_i8(0x23)
+#define Usage_TD_Redial Usage_i8(0x24)
+#define Usage_TD_Transfer Usage_i8(0x25)
+#define Usage_TD_Drop Usage_i8(0x26)
+#define Usage_TD_Park Usage_i8(0x27)
+#define Usage_TD_ForwardCalls Usage_i8(0x28)
+#define Usage_TD_AlternateFunction Usage_i8(0x29)
+#define Usage_TD_Line Usage_i8(0x2a)
+#define Usage_TD_SpeakerPhone Usage_i8(0x2b)
+#define Usage_TD_Conference Usage_i8(0x2c)
+#define Usage_TD_RingEnable Usage_i8(0x2d)
+#define Usage_TD_RingSelect Usage_i8(0x2e)
+#define Usage_TD_PhoneMute Usage_i8(0x2f)
+#define Usage_TD_CallerID Usage_i8(0x30)
+#define Usage_TD_Send Usage_i8(0x31)
+#define Usage_TD_SpeedDial Usage_i8(0x50)
+#define Usage_TD_StoreNumber Usage_i8(0x51)
+#define Usage_TD_RecallNumber Usage_i8(0x52)
+#define Usage_TD_PhoneDirectory Usage_i8(0x53)
+#define Usage_TD_VoiceMail Usage_i8(0x70)
+#define Usage_TD_ScreenCalls Usage_i8(0x71)
+#define Usage_TD_DoNotDisturb Usage_i8(0x72)
+#define Usage_TD_Message Usage_i8(0x73)
+#define Usage_TD_AnswerOnOff Usage_i8(0x74)
+#define Usage_TD_InsideDialTone Usage_i8(0x90)
+#define Usage_TD_OutsideDialTone Usage_i8(0x91)
+#define Usage_TD_InsideRingTone Usage_i8(0x92)
+#define Usage_TD_OutsideRingTone Usage_i8(0x93)
+#define Usage_TD_PriorityRingTone Usage_i8(0x94)
+#define Usage_TD_InsideRingback Usage_i8(0x95)
+#define Usage_TD_PriorityRingback Usage_i8(0x96)
+#define Usage_TD_LineBusyTone Usage_i8(0x97)
+#define Usage_TD_ReorderTone Usage_i8(0x98)
+#define Usage_TD_CallWaitingTone Usage_i8(0x99)
+#define Usage_TD_ConfirmationTone1 Usage_i8(0x9a)
+#define Usage_TD_ConfirmationTone2 Usage_i8(0x9b)
+#define Usage_TD_TonesOff Usage_i8(0x9c)
+#define Usage_TD_OutsideRingback Usage_i8(0x9d)
+#define Usage_TD_Ringer Usage_i8(0x9e)
+#define Usage_TD_PhoneKey0 Usage_i8(0xb0)
+#define Usage_TD_PhoneKey1 Usage_i8(0xb1)
+#define Usage_TD_PhoneKey2 Usage_i8(0xb2)
+#define Usage_TD_PhoneKey3 Usage_i8(0xb3)
+#define Usage_TD_PhoneKey4 Usage_i8(0xb4)
+#define Usage_TD_PhoneKey5 Usage_i8(0xb5)
+#define Usage_TD_PhoneKey6 Usage_i8(0xb6)
+#define Usage_TD_PhoneKey7 Usage_i8(0xb7)
+#define Usage_TD_PhoneKey8 Usage_i8(0xb8)
+#define Usage_TD_PhoneKey9 Usage_i8(0xb9)
+#define Usage_TD_PhoneKeyStar Usage_i8(0xba)
+#define Usage_TD_PhoneKeyPound Usage_i8(0xbb)
+#define Usage_TD_PhoneKeyA Usage_i8(0xbc)
+#define Usage_TD_PhoneKeyB Usage_i8(0xbd)
+#define Usage_TD_PhoneKeyC Usage_i8(0xbe)
+#define Usage_TD_PhoneKeyD Usage_i8(0xbf)
+#define Usage_TD_PhoneCallHistoryKey Usage_i8(0xc0)
+#define Usage_TD_PhoneCallerIDKey Usage_i8(0xc1)
+#define Usage_TD_PhoneSettingsKey Usage_i8(0xc2)
+#define Usage_TD_HostControl Usage_i8(0xf0)
+#define Usage_TD_HostAvailable Usage_i8(0xf1)
+#define Usage_TD_HostCallActive Usage_i8(0xf2)
+#define Usage_TD_ActivateHandsetAudio Usage_i8(0xf3)
+#define Usage_TD_RingType Usage_i8(0xf4)
+#define Usage_TD_RedialablePhoneNumber Usage_i8(0xf5)
+#define Usage_TD_StopRingTone Usage_i8(0xf8)
+#define Usage_TD_PSTNRingTone Usage_i8(0xf9)
+#define Usage_TD_HostRingTone Usage_i8(0xfa)
+#define Usage_TD_AlertSoundError Usage_i8(0xfb)
+#define Usage_TD_AlertSoundConfirm Usage_i8(0xfc)
+#define Usage_TD_AlertSoundNotification Usage_i8(0xfd)
+#define Usage_TD_SilentRing Usage_i8(0xfe)
+#define Usage_TD_EmailMessageWaiting Usage_i16(0x108)
+#define Usage_TD_VoicemailMessageWaiting Usage_i16(0x109)
+#define Usage_TD_HostHold Usage_i16(0x10a)
+#define Usage_TD_IncomingCallHistoryCount Usage_i16(0x110)
+#define Usage_TD_OutgoingCallHistoryCount Usage_i16(0x111)
+#define Usage_TD_IncomingCallHistory Usage_i16(0x112)
+#define Usage_TD_OutgoingCallHistory Usage_i16(0x113)
+#define Usage_TD_PhoneLocale Usage_i16(0x114)
+#define Usage_TD_PhoneTimeSecond Usage_i16(0x140)
+#define Usage_TD_PhoneTimeMinute Usage_i16(0x141)
+#define Usage_TD_PhoneTimeHour Usage_i16(0x142)
+#define Usage_TD_PhoneDateDay Usage_i16(0x143)
+#define Usage_TD_PhoneDateMonth Usage_i16(0x144)
+#define Usage_TD_PhoneDateYear Usage_i16(0x145)
+#define Usage_TD_HandsetNickname Usage_i16(0x146)
+#define Usage_TD_AddressBookID Usage_i16(0x147)
+#define Usage_TD_CallDuration Usage_i16(0x14a)
+#define Usage_TD_DualModePhone Usage_i16(0x14b)
+#define Usage_Con_ConsumerControl Usage_i8(0x1)
+#define Usage_Con_NumericKeyPad Usage_i8(0x2)
+#define Usage_Con_ProgrammableButtons Usage_i8(0x3)
+#define Usage_Con_Microphone Usage_i8(0x4)
+#define Usage_Con_Headphone Usage_i8(0x5)
+#define Usage_Con_GraphicEqualizer Usage_i8(0x6)
+#define Usage_Con_Plus10 Usage_i8(0x20)
+#define Usage_Con_Plus100 Usage_i8(0x21)
+#define Usage_Con_AMPM Usage_i8(0x22)
+#define Usage_Con_Power Usage_i8(0x30)
+#define Usage_Con_Reset Usage_i8(0x31)
+#define Usage_Con_Sleep Usage_i8(0x32)
+#define Usage_Con_SleepAfter Usage_i8(0x33)
+#define Usage_Con_SleepMode Usage_i8(0x34)
+#define Usage_Con_Illumination Usage_i8(0x35)
+#define Usage_Con_FunctionButtons Usage_i8(0x36)
+#define Usage_Con_Menu Usage_i8(0x40)
+#define Usage_Con_MenuPick Usage_i8(0x41)
+#define Usage_Con_MenuUp Usage_i8(0x42)
+#define Usage_Con_MenuDown Usage_i8(0x43)
+#define Usage_Con_MenuLeft Usage_i8(0x44)
+#define Usage_Con_MenuRight Usage_i8(0x45)
+#define Usage_Con_MenuEscape Usage_i8(0x46)
+#define Usage_Con_MenuValueIncrease Usage_i8(0x47)
+#define Usage_Con_MenuValueDecrease Usage_i8(0x48)
+#define Usage_Con_DataOnScreen Usage_i8(0x60)
+#define Usage_Con_ClosedCaption Usage_i8(0x61)
+#define Usage_Con_ClosedCaptionSelect Usage_i8(0x62)
+#define Usage_Con_VCRTV Usage_i8(0x63)
+#define Usage_Con_BroadcastMode Usage_i8(0x64)
+#define Usage_Con_Snapshot Usage_i8(0x65)
+#define Usage_Con_Still Usage_i8(0x66)
+#define Usage_Con_PictureinPictureToggle Usage_i8(0x67)
+#define Usage_Con_PictureinPictureSwap Usage_i8(0x68)
+#define Usage_Con_RedMenuButton Usage_i8(0x69)
+#define Usage_Con_GreenMenuButton Usage_i8(0x6a)
+#define Usage_Con_BlueMenuButton Usage_i8(0x6b)
+#define Usage_Con_YellowMenuButton Usage_i8(0x6c)
+#define Usage_Con_Aspect Usage_i8(0x6d)
+#define Usage_Con_ThreeDModeSelect Usage_i8(0x6e)
+#define Usage_Con_DisplayBrightnessIncrement Usage_i8(0x6f)
+#define Usage_Con_DisplayBrightnessDecrement Usage_i8(0x70)
+#define Usage_Con_DisplayBrightness Usage_i8(0x71)
+#define Usage_Con_DisplayBacklightToggle Usage_i8(0x72)
+#define Usage_Con_DisplaySetBrightnesstoMinimum Usage_i8(0x73)
+#define Usage_Con_DisplaySetBrightnesstoMaximum Usage_i8(0x74)
+#define Usage_Con_DisplaySetAutoBrightness Usage_i8(0x75)
+#define Usage_Con_CameraAccessEnabled Usage_i8(0x76)
+#define Usage_Con_CameraAccessDisabled Usage_i8(0x77)
+#define Usage_Con_CameraAccessToggle Usage_i8(0x78)
+#define Usage_Con_KeyboardBrightnessIncrement Usage_i8(0x79)
+#define Usage_Con_KeyboardBrightnessDecrement Usage_i8(0x7a)
+#define Usage_Con_KeyboardBacklightSetLevel Usage_i8(0x7b)
+#define Usage_Con_KeyboardBacklightOOC Usage_i8(0x7c)
+#define Usage_Con_KeyboardBacklightSetMinimum Usage_i8(0x7d)
+#define Usage_Con_KeyboardBacklightSetMaximum Usage_i8(0x7e)
+#define Usage_Con_KeyboardBacklightAuto Usage_i8(0x7f)
+#define Usage_Con_Selection Usage_i8(0x80)
+#define Usage_Con_AssignSelection Usage_i8(0x81)
+#define Usage_Con_ModeStep Usage_i8(0x82)
+#define Usage_Con_RecallLast Usage_i8(0x83)
+#define Usage_Con_EnterChannel Usage_i8(0x84)
+#define Usage_Con_OrderMovie Usage_i8(0x85)
+#define Usage_Con_Channel Usage_i8(0x86)
+#define Usage_Con_MediaSelection Usage_i8(0x87)
+#define Usage_Con_MediaSelectComputer Usage_i8(0x88)
+#define Usage_Con_MediaSelectTV Usage_i8(0x89)
+#define Usage_Con_MediaSelectWWW Usage_i8(0x8a)
+#define Usage_Con_MediaSelectDVD Usage_i8(0x8b)
+#define Usage_Con_MediaSelectTelephone Usage_i8(0x8c)
+#define Usage_Con_MediaSelectProgramGuide Usage_i8(0x8d)
+#define Usage_Con_MediaSelectVideoPhone Usage_i8(0x8e)
+#define Usage_Con_MediaSelectGames Usage_i8(0x8f)
+#define Usage_Con_MediaSelectMessages Usage_i8(0x90)
+#define Usage_Con_MediaSelectCD Usage_i8(0x91)
+#define Usage_Con_MediaSelectVCR Usage_i8(0x92)
+#define Usage_Con_MediaSelectTuner Usage_i8(0x93)
+#define Usage_Con_Quit Usage_i8(0x94)
+#define Usage_Con_Help Usage_i8(0x95)
+#define Usage_Con_MediaSelectTape Usage_i8(0x96)
+#define Usage_Con_MediaSelectCable Usage_i8(0x97)
+#define Usage_Con_MediaSelectSatellite Usage_i8(0x98)
+#define Usage_Con_MediaSelectSecurity Usage_i8(0x99)
+#define Usage_Con_MediaSelectHome Usage_i8(0x9a)
+#define Usage_Con_MediaSelectCall Usage_i8(0x9b)
+#define Usage_Con_ChannelIncrement Usage_i8(0x9c)
+#define Usage_Con_ChannelDecrement Usage_i8(0x9d)
+#define Usage_Con_MediaSelectSAP Usage_i8(0x9e)
+#define Usage_Con_VCRPlus Usage_i8(0xa0)
+#define Usage_Con_Once Usage_i8(0xa1)
+#define Usage_Con_Daily Usage_i8(0xa2)
+#define Usage_Con_Weekly Usage_i8(0xa3)
+#define Usage_Con_Monthly Usage_i8(0xa4)
+#define Usage_Con_Play Usage_i8(0xb0)
+#define Usage_Con_Pause Usage_i8(0xb1)
+#define Usage_Con_Record Usage_i8(0xb2)
+#define Usage_Con_FastForward Usage_i8(0xb3)
+#define Usage_Con_Rewind Usage_i8(0xb4)
+#define Usage_Con_ScanNextTrack Usage_i8(0xb5)
+#define Usage_Con_ScanPreviousTrack Usage_i8(0xb6)
+#define Usage_Con_Stop Usage_i8(0xb7)
+#define Usage_Con_Eject Usage_i8(0xb8)
+#define Usage_Con_RandomPlay Usage_i8(0xb9)
+#define Usage_Con_SelectDisc Usage_i8(0xba)
+#define Usage_Con_EnterDisc Usage_i8(0xbb)
+#define Usage_Con_Repeat Usage_i8(0xbc)
+#define Usage_Con_Tracking Usage_i8(0xbd)
+#define Usage_Con_TrackNormal Usage_i8(0xbe)
+#define Usage_Con_SlowTracking Usage_i8(0xbf)
+#define Usage_Con_FrameForward Usage_i8(0xc0)
+#define Usage_Con_FrameBack Usage_i8(0xc1)
+#define Usage_Con_Mark Usage_i8(0xc2)
+#define Usage_Con_ClearMark Usage_i8(0xc3)
+#define Usage_Con_RepeatFromMark Usage_i8(0xc4)
+#define Usage_Con_ReturnToMark Usage_i8(0xc5)
+#define Usage_Con_SearchMarkForward Usage_i8(0xc6)
+#define Usage_Con_SearchMarkBackwards Usage_i8(0xc7)
+#define Usage_Con_CounterReset Usage_i8(0xc8)
+#define Usage_Con_ShowCounter Usage_i8(0xc9)
+#define Usage_Con_TrackingIncrement Usage_i8(0xca)
+#define Usage_Con_TrackingDecrement Usage_i8(0xcb)
+#define Usage_Con_StopEject Usage_i8(0xcc)
+#define Usage_Con_PlayPause Usage_i8(0xcd)
+#define Usage_Con_PlaySkip Usage_i8(0xce)
+#define Usage_Con_VoiceCommand Usage_i8(0xcf)
+#define Usage_Con_InvokeCaptureInterface Usage_i8(0xd0)
+#define Usage_Con_StartorStopGameRecording Usage_i8(0xd1)
+#define Usage_Con_HistoricalGameCapture Usage_i8(0xd2)
+#define Usage_Con_CaptureGameScreenshot Usage_i8(0xd3)
+#define Usage_Con_ShoworHideRecordingIndicator Usage_i8(0xd4)
+#define Usage_Con_StartorStopMicrophoneCapture Usage_i8(0xd5)
+#define Usage_Con_StartorStopCameraCapture Usage_i8(0xd6)
+#define Usage_Con_StartorStopGameBroadcast Usage_i8(0xd7)
+#define Usage_Con_StartorStopVoiceDictationSession Usage_i8(0xd8)
+#define Usage_Con_InvokeDismissEmojiPicker Usage_i8(0xd9)
+#define Usage_Con_Volume Usage_i8(0xe0)
+#define Usage_Con_Balance Usage_i8(0xe1)
+#define Usage_Con_Mute Usage_i8(0xe2)
+#define Usage_Con_Bass Usage_i8(0xe3)
+#define Usage_Con_Treble Usage_i8(0xe4)
+#define Usage_Con_BassBoost Usage_i8(0xe5)
+#define Usage_Con_SurroundMode Usage_i8(0xe6)
+#define Usage_Con_Loudness Usage_i8(0xe7)
+#define Usage_Con_MPX Usage_i8(0xe8)
+#define Usage_Con_VolumeIncrement Usage_i8(0xe9)
+#define Usage_Con_VolumeDecrement Usage_i8(0xea)
+#define Usage_Con_SpeedSelect Usage_i8(0xf0)
+#define Usage_Con_PlaybackSpeed Usage_i8(0xf1)
+#define Usage_Con_StandardPlay Usage_i8(0xf2)
+#define Usage_Con_LongPlay Usage_i8(0xf3)
+#define Usage_Con_ExtendedPlay Usage_i8(0xf4)
+#define Usage_Con_Slow Usage_i8(0xf5)
+#define Usage_Con_FanEnable Usage_i16(0x100)
+#define Usage_Con_FanSpeed Usage_i16(0x101)
+#define Usage_Con_LightEnable Usage_i16(0x102)
+#define Usage_Con_LightIlluminationLevel Usage_i16(0x103)
+#define Usage_Con_ClimateControlEnable Usage_i16(0x104)
+#define Usage_Con_RoomTemperature Usage_i16(0x105)
+#define Usage_Con_SecurityEnable Usage_i16(0x106)
+#define Usage_Con_FireAlarm Usage_i16(0x107)
+#define Usage_Con_PoliceAlarm Usage_i16(0x108)
+#define Usage_Con_Proximity Usage_i16(0x109)
+#define Usage_Con_Motion Usage_i16(0x10a)
+#define Usage_Con_DuressAlarm Usage_i16(0x10b)
+#define Usage_Con_HoldupAlarm Usage_i16(0x10c)
+#define Usage_Con_MedicalAlarm Usage_i16(0x10d)
+#define Usage_Con_BalanceRight Usage_i16(0x150)
+#define Usage_Con_BalanceLeft Usage_i16(0x151)
+#define Usage_Con_BassIncrement Usage_i16(0x152)
+#define Usage_Con_BassDecrement Usage_i16(0x153)
+#define Usage_Con_TrebleIncrement Usage_i16(0x154)
+#define Usage_Con_TrebleDecrement Usage_i16(0x155)
+#define Usage_Con_SpeakerSystem Usage_i16(0x160)
+#define Usage_Con_ChannelLeft Usage_i16(0x161)
+#define Usage_Con_ChannelRight Usage_i16(0x162)
+#define Usage_Con_ChannelCenter Usage_i16(0x163)
+#define Usage_Con_ChannelFront Usage_i16(0x164)
+#define Usage_Con_ChannelCenterFront Usage_i16(0x165)
+#define Usage_Con_ChannelSide Usage_i16(0x166)
+#define Usage_Con_ChannelSurround Usage_i16(0x167)
+#define Usage_Con_ChannelLowFrequencyEnhancement Usage_i16(0x168)
+#define Usage_Con_ChannelTop Usage_i16(0x169)
+#define Usage_Con_ChannelUnknown Usage_i16(0x16a)
+#define Usage_Con_Subchannel Usage_i16(0x170)
+#define Usage_Con_SubchannelIncrement Usage_i16(0x171)
+#define Usage_Con_SubchannelDecrement Usage_i16(0x172)
+#define Usage_Con_AlternateAudioIncrement Usage_i16(0x173)
+#define Usage_Con_AlternateAudioDecrement Usage_i16(0x174)
+#define Usage_Con_ApplicationLaunchButtons Usage_i16(0x180)
+#define Usage_Con_ALLaunchButtonConfigurationTool Usage_i16(0x181)
+#define Usage_Con_ALProgrammableButtonConfiguration Usage_i16(0x182)
+#define Usage_Con_ALConsumerControlConfiguration Usage_i16(0x183)
+#define Usage_Con_ALWordProcessor Usage_i16(0x184)
+#define Usage_Con_ALTextEditor Usage_i16(0x185)
+#define Usage_Con_ALSpreadsheet Usage_i16(0x186)
+#define Usage_Con_ALGraphicsEditor Usage_i16(0x187)
+#define Usage_Con_ALPresentationApp Usage_i16(0x188)
+#define Usage_Con_ALDatabaseApp Usage_i16(0x189)
+#define Usage_Con_ALEmailReader Usage_i16(0x18a)
+#define Usage_Con_ALNewsreader Usage_i16(0x18b)
+#define Usage_Con_ALVoicemail Usage_i16(0x18c)
+#define Usage_Con_ALContactsAddressBook Usage_i16(0x18d)
+#define Usage_Con_ALCalendarSchedule Usage_i16(0x18e)
+#define Usage_Con_ALTaskProjectManager Usage_i16(0x18f)
+#define Usage_Con_ALLogJournalTimecard Usage_i16(0x190)
+#define Usage_Con_ALCheckbookFinance Usage_i16(0x191)
+#define Usage_Con_ALCalculator Usage_i16(0x192)
+#define Usage_Con_ALAVCapturePlayback Usage_i16(0x193)
+#define Usage_Con_ALLocalMachineBrowser Usage_i16(0x194)
+#define Usage_Con_ALLANWANBrowser Usage_i16(0x195)
+#define Usage_Con_ALInternetBrowser Usage_i16(0x196)
+#define Usage_Con_ALRemoteNetworkingISPConnect Usage_i16(0x197)
+#define Usage_Con_ALNetworkConference Usage_i16(0x198)
+#define Usage_Con_ALNetworkChat Usage_i16(0x199)
+#define Usage_Con_ALTelephonyDialer Usage_i16(0x19a)
+#define Usage_Con_ALLogon Usage_i16(0x19b)
+#define Usage_Con_ALLogoff Usage_i16(0x19c)
+#define Usage_Con_ALLogonLogoff Usage_i16(0x19d)
+#define Usage_Con_ALTerminalLockScreensaver Usage_i16(0x19e)
+#define Usage_Con_ALControlPanel Usage_i16(0x19f)
+#define Usage_Con_ALCommandLineProcessorRun Usage_i16(0x1a0)
+#define Usage_Con_ALProcessTaskManager Usage_i16(0x1a1)
+#define Usage_Con_ALSelectTaskApplication Usage_i16(0x1a2)
+#define Usage_Con_ALNextTaskApplication Usage_i16(0x1a3)
+#define Usage_Con_ALPreviousTaskApplication Usage_i16(0x1a4)
+#define Usage_Con_ALPreemptiveHaltTaskApplication Usage_i16(0x1a5)
+#define Usage_Con_ALIntegratedHelpCenter Usage_i16(0x1a6)
+#define Usage_Con_ALDocuments Usage_i16(0x1a7)
+#define Usage_Con_ALThesaurus Usage_i16(0x1a8)
+#define Usage_Con_ALDictionary Usage_i16(0x1a9)
+#define Usage_Con_ALDesktop Usage_i16(0x1aa)
+#define Usage_Con_ALSpellCheck Usage_i16(0x1ab)
+#define Usage_Con_ALGrammarCheck Usage_i16(0x1ac)
+#define Usage_Con_ALWirelessStatus Usage_i16(0x1ad)
+#define Usage_Con_ALKeyboardLayout Usage_i16(0x1ae)
+#define Usage_Con_ALVirusProtection Usage_i16(0x1af)
+#define Usage_Con_ALEncryption Usage_i16(0x1b0)
+#define Usage_Con_ALScreenSaver Usage_i16(0x1b1)
+#define Usage_Con_ALAlarms Usage_i16(0x1b2)
+#define Usage_Con_ALClock Usage_i16(0x1b3)
+#define Usage_Con_ALFileBrowser Usage_i16(0x1b4)
+#define Usage_Con_ALPowerStatus Usage_i16(0x1b5)
+#define Usage_Con_ALImageBrowser Usage_i16(0x1b6)
+#define Usage_Con_ALAudioBrowser Usage_i16(0x1b7)
+#define Usage_Con_ALMovieBrowser Usage_i16(0x1b8)
+#define Usage_Con_ALDigitalRightsManager Usage_i16(0x1b9)
+#define Usage_Con_ALDigitalWallet Usage_i16(0x1ba)
+#define Usage_Con_ALInstantMessaging Usage_i16(0x1bc)
+#define Usage_Con_ALOEMFeaturesTipsTutorialBrowser Usage_i16(0x1bd)
+#define Usage_Con_ALOEMHelp Usage_i16(0x1be)
+#define Usage_Con_ALOnlineCommunity Usage_i16(0x1bf)
+#define Usage_Con_ALEntertainmentContentBrowser Usage_i16(0x1c0)
+#define Usage_Con_ALOnlineShoppingBrowser Usage_i16(0x1c1)
+#define Usage_Con_ALSmartCardInformationHelp Usage_i16(0x1c2)
+#define Usage_Con_ALMarketMonitorFinanceBrowser Usage_i16(0x1c3)
+#define Usage_Con_ALCustomizedCorporateNewsBrowser Usage_i16(0x1c4)
+#define Usage_Con_ALOnlineActivityBrowser Usage_i16(0x1c5)
+#define Usage_Con_ALResearchSearchBrowser Usage_i16(0x1c6)
+#define Usage_Con_ALAudioPlayer Usage_i16(0x1c7)
+#define Usage_Con_ALMessageStatus Usage_i16(0x1c8)
+#define Usage_Con_ALContactSync Usage_i16(0x1c9)
+#define Usage_Con_ALNavigation Usage_i16(0x1ca)
+#define Usage_Con_ALContextawareDesktopAssistant Usage_i16(0x1cb)
+#define Usage_Con_GenericGUIApplicationControls Usage_i16(0x200)
+#define Usage_Con_ACNew Usage_i16(0x201)
+#define Usage_Con_ACOpen Usage_i16(0x202)
+#define Usage_Con_ACClose Usage_i16(0x203)
+#define Usage_Con_ACExit Usage_i16(0x204)
+#define Usage_Con_ACMaximize Usage_i16(0x205)
+#define Usage_Con_ACMinimize Usage_i16(0x206)
+#define Usage_Con_ACSave Usage_i16(0x207)
+#define Usage_Con_ACPrint Usage_i16(0x208)
+#define Usage_Con_ACProperties Usage_i16(0x209)
+#define Usage_Con_ACUndo Usage_i16(0x21a)
+#define Usage_Con_ACCopy Usage_i16(0x21b)
+#define Usage_Con_ACCut Usage_i16(0x21c)
+#define Usage_Con_ACPaste Usage_i16(0x21d)
+#define Usage_Con_ACSelectAll Usage_i16(0x21e)
+#define Usage_Con_ACFind Usage_i16(0x21f)
+#define Usage_Con_ACFindandReplace Usage_i16(0x220)
+#define Usage_Con_ACSearch Usage_i16(0x221)
+#define Usage_Con_ACGoTo Usage_i16(0x222)
+#define Usage_Con_ACHome Usage_i16(0x223)
+#define Usage_Con_ACBack Usage_i16(0x224)
+#define Usage_Con_ACForward Usage_i16(0x225)
+#define Usage_Con_ACStop Usage_i16(0x226)
+#define Usage_Con_ACRefresh Usage_i16(0x227)
+#define Usage_Con_ACPreviousLink Usage_i16(0x228)
+#define Usage_Con_ACNextLink Usage_i16(0x229)
+#define Usage_Con_ACBookmarks Usage_i16(0x22a)
+#define Usage_Con_ACHistory Usage_i16(0x22b)
+#define Usage_Con_ACSubscriptions Usage_i16(0x22c)
+#define Usage_Con_ACZoomIn Usage_i16(0x22d)
+#define Usage_Con_ACZoomOut Usage_i16(0x22e)
+#define Usage_Con_ACZoom Usage_i16(0x22f)
+#define Usage_Con_ACFullScreenView Usage_i16(0x230)
+#define Usage_Con_ACNormalView Usage_i16(0x231)
+#define Usage_Con_ACViewToggle Usage_i16(0x232)
+#define Usage_Con_ACScrollUp Usage_i16(0x233)
+#define Usage_Con_ACScrollDown Usage_i16(0x234)
+#define Usage_Con_ACScroll Usage_i16(0x235)
+#define Usage_Con_ACPanLeft Usage_i16(0x236)
+#define Usage_Con_ACPanRight Usage_i16(0x237)
+#define Usage_Con_ACPan Usage_i16(0x238)
+#define Usage_Con_ACNewWindow Usage_i16(0x239)
+#define Usage_Con_ACTileHorizontally Usage_i16(0x23a)
+#define Usage_Con_ACTileVertically Usage_i16(0x23b)
+#define Usage_Con_ACFormat Usage_i16(0x23c)
+#define Usage_Con_ACEdit Usage_i16(0x23d)
+#define Usage_Con_ACBold Usage_i16(0x23e)
+#define Usage_Con_ACItalics Usage_i16(0x23f)
+#define Usage_Con_ACUnderline Usage_i16(0x240)
+#define Usage_Con_ACStrikethrough Usage_i16(0x241)
+#define Usage_Con_ACSubscript Usage_i16(0x242)
+#define Usage_Con_ACSuperscript Usage_i16(0x243)
+#define Usage_Con_ACAllCaps Usage_i16(0x244)
+#define Usage_Con_ACRotate Usage_i16(0x245)
+#define Usage_Con_ACResize Usage_i16(0x246)
+#define Usage_Con_ACFlipHorizontal Usage_i16(0x247)
+#define Usage_Con_ACFlipVertical Usage_i16(0x248)
+#define Usage_Con_ACMirrorHorizontal Usage_i16(0x249)
+#define Usage_Con_ACMirrorVertical Usage_i16(0x24a)
+#define Usage_Con_ACFontSelect Usage_i16(0x24b)
+#define Usage_Con_ACFontColor Usage_i16(0x24c)
+#define Usage_Con_ACFontSize Usage_i16(0x24d)
+#define Usage_Con_ACJustifyLeft Usage_i16(0x24e)
+#define Usage_Con_ACJustifyCenterH Usage_i16(0x24f)
+#define Usage_Con_ACJustifyRight Usage_i16(0x250)
+#define Usage_Con_ACJustifyBlockH Usage_i16(0x251)
+#define Usage_Con_ACJustifyTop Usage_i16(0x252)
+#define Usage_Con_ACJustifyCenterV Usage_i16(0x253)
+#define Usage_Con_ACJustifyBottom Usage_i16(0x254)
+#define Usage_Con_ACJustifyBlockV Usage_i16(0x255)
+#define Usage_Con_ACIndentDecrease Usage_i16(0x256)
+#define Usage_Con_ACIndentIncrease Usage_i16(0x257)
+#define Usage_Con_ACNumberedList Usage_i16(0x258)
+#define Usage_Con_ACRestartNumbering Usage_i16(0x259)
+#define Usage_Con_ACBulletedList Usage_i16(0x25a)
+#define Usage_Con_ACPromote Usage_i16(0x25b)
+#define Usage_Con_ACDemote Usage_i16(0x25c)
+#define Usage_Con_ACYes Usage_i16(0x25d)
+#define Usage_Con_ACNo Usage_i16(0x25e)
+#define Usage_Con_ACCancel Usage_i16(0x25f)
+#define Usage_Con_ACCatalog Usage_i16(0x260)
+#define Usage_Con_ACBuyCheckout Usage_i16(0x261)
+#define Usage_Con_ACAddtoCart Usage_i16(0x262)
+#define Usage_Con_ACExpand Usage_i16(0x263)
+#define Usage_Con_ACExpandAll Usage_i16(0x264)
+#define Usage_Con_ACCollapse Usage_i16(0x265)
+#define Usage_Con_ACCollapseAll Usage_i16(0x266)
+#define Usage_Con_ACPrintPreview Usage_i16(0x267)
+#define Usage_Con_ACPasteSpecial Usage_i16(0x268)
+#define Usage_Con_ACInsertMode Usage_i16(0x269)
+#define Usage_Con_ACDelete Usage_i16(0x26a)
+#define Usage_Con_ACLock Usage_i16(0x26b)
+#define Usage_Con_ACUnlock Usage_i16(0x26c)
+#define Usage_Con_ACProtect Usage_i16(0x26d)
+#define Usage_Con_ACUnprotect Usage_i16(0x26e)
+#define Usage_Con_ACAttachComment Usage_i16(0x26f)
+#define Usage_Con_ACDeleteComment Usage_i16(0x270)
+#define Usage_Con_ACViewComment Usage_i16(0x271)
+#define Usage_Con_ACSelectWord Usage_i16(0x272)
+#define Usage_Con_ACSelectSentence Usage_i16(0x273)
+#define Usage_Con_ACSelectParagraph Usage_i16(0x274)
+#define Usage_Con_ACSelectColumn Usage_i16(0x275)
+#define Usage_Con_ACSelectRow Usage_i16(0x276)
+#define Usage_Con_ACSelectTable Usage_i16(0x277)
+#define Usage_Con_ACSelectObject Usage_i16(0x278)
+#define Usage_Con_ACRedoRepeat Usage_i16(0x279)
+#define Usage_Con_ACSort Usage_i16(0x27a)
+#define Usage_Con_ACSortAscending Usage_i16(0x27b)
+#define Usage_Con_ACSortDescending Usage_i16(0x27c)
+#define Usage_Con_ACFilter Usage_i16(0x27d)
+#define Usage_Con_ACSetClock Usage_i16(0x27e)
+#define Usage_Con_ACViewClock Usage_i16(0x27f)
+#define Usage_Con_ACSelectTimeZone Usage_i16(0x280)
+#define Usage_Con_ACEditTimeZones Usage_i16(0x281)
+#define Usage_Con_ACSetAlarm Usage_i16(0x282)
+#define Usage_Con_ACClearAlarm Usage_i16(0x283)
+#define Usage_Con_ACSnoozeAlarm Usage_i16(0x284)
+#define Usage_Con_ACResetAlarm Usage_i16(0x285)
+#define Usage_Con_ACSynchronize Usage_i16(0x286)
+#define Usage_Con_ACSendReceive Usage_i16(0x287)
+#define Usage_Con_ACSendTo Usage_i16(0x288)
+#define Usage_Con_ACReply Usage_i16(0x289)
+#define Usage_Con_ACReplyAll Usage_i16(0x28a)
+#define Usage_Con_ACForwardMsg Usage_i16(0x28b)
+#define Usage_Con_ACSend Usage_i16(0x28c)
+#define Usage_Con_ACAttachFile Usage_i16(0x28d)
+#define Usage_Con_ACUpload Usage_i16(0x28e)
+#define Usage_Con_ACDownloadSaveTargetAs Usage_i16(0x28f)
+#define Usage_Con_ACSetBorders Usage_i16(0x290)
+#define Usage_Con_ACInsertRow Usage_i16(0x291)
+#define Usage_Con_ACInsertColumn Usage_i16(0x292)
+#define Usage_Con_ACInsertFile Usage_i16(0x293)
+#define Usage_Con_ACInsertPicture Usage_i16(0x294)
+#define Usage_Con_ACInsertObject Usage_i16(0x295)
+#define Usage_Con_ACInsertSymbol Usage_i16(0x296)
+#define Usage_Con_ACSaveandClose Usage_i16(0x297)
+#define Usage_Con_ACRename Usage_i16(0x298)
+#define Usage_Con_ACMerge Usage_i16(0x299)
+#define Usage_Con_ACSplit Usage_i16(0x29a)
+#define Usage_Con_ACDisributeHorizontally Usage_i16(0x29b)
+#define Usage_Con_ACDistributeVertically Usage_i16(0x29c)
+#define Usage_Con_ACNextKeyboardLayoutSelect Usage_i16(0x29d)
+#define Usage_Con_ACNavigationGuidance Usage_i16(0x29e)
+#define Usage_Con_ACDesktopShowAllWindows Usage_i16(0x29f)
+#define Usage_Con_ACSoftKeyLeft Usage_i16(0x2a0)
+#define Usage_Con_ACSoftKeyRight Usage_i16(0x2a1)
+#define Usage_Con_ACDesktopShowAllApplications Usage_i16(0x2a2)
+#define Usage_Con_ACIdleKeepAlive Usage_i16(0x2b0)
+#define Usage_Con_ExtendedKeyboardAttributesCollection Usage_i16(0x2c0)
+#define Usage_Con_KeyboardFormFactor Usage_i16(0x2c1)
+#define Usage_Con_KeyboardKeyType Usage_i16(0x2c2)
+#define Usage_Con_KeyboardPhysicalLayout Usage_i16(0x2c3)
+#define Usage_Con_VendorSpecificKeyboardPhysicalLayout Usage_i16(0x2c4)
+#define Usage_Con_KeyboardIETFLanguageTagIndex Usage_i16(0x2c5)
+#define Usage_Con_ImplementedKeyboardInputAssistControls Usage_i16(0x2c6)
+#define Usage_Con_KeyboardInputAssistPrevious Usage_i16(0x2c7)
+#define Usage_Con_KeyboardInputAssistNext Usage_i16(0x2c8)
+#define Usage_Con_KeyboardInputAssistPreviousGroup Usage_i16(0x2c9)
+#define Usage_Con_KeyboardInputAssistNextGroup Usage_i16(0x2ca)
+#define Usage_Con_KeyboardInputAssistAccept Usage_i16(0x2cb)
+#define Usage_Con_KeyboardInputAssistCancel Usage_i16(0x2cc)
+#define Usage_Con_PrivacyScreenToggle Usage_i16(0x2d0)
+#define Usage_Con_PrivacyScreenLevelDecrement Usage_i16(0x2d1)
+#define Usage_Con_PrivacyScreenLevelIncrement Usage_i16(0x2d2)
+#define Usage_Con_PrivacyScreenLevelMinimum Usage_i16(0x2d3)
+#define Usage_Con_PrivacyScreenLevelMaximum Usage_i16(0x2d4)
+#define Usage_Con_ContactEdited Usage_i16(0x500)
+#define Usage_Con_ContactAdded Usage_i16(0x501)
+#define Usage_Con_ContactRecordActive Usage_i16(0x502)
+#define Usage_Con_ContactIndex Usage_i16(0x503)
+#define Usage_Con_ContactNickname Usage_i16(0x504)
+#define Usage_Con_ContactFirstName Usage_i16(0x505)
+#define Usage_Con_ContactLastName Usage_i16(0x506)
+#define Usage_Con_ContactFullName Usage_i16(0x507)
+#define Usage_Con_ContactPhoneNumberPersonal Usage_i16(0x508)
+#define Usage_Con_ContactPhoneNumberBusiness Usage_i16(0x509)
+#define Usage_Con_ContactPhoneNumberMobile Usage_i16(0x50a)
+#define Usage_Con_ContactPhoneNumberPager Usage_i16(0x50b)
+#define Usage_Con_ContactPhoneNumberFax Usage_i16(0x50c)
+#define Usage_Con_ContactPhoneNumberOther Usage_i16(0x50d)
+#define Usage_Con_ContactEmailPersonal Usage_i16(0x50e)
+#define Usage_Con_ContactEmailBusiness Usage_i16(0x50f)
+#define Usage_Con_ContactEmailOther Usage_i16(0x510)
+#define Usage_Con_ContactEmailMain Usage_i16(0x511)
+#define Usage_Con_ContactSpeedDialNumber Usage_i16(0x512)
+#define Usage_Con_ContactStatusFlag Usage_i16(0x513)
+#define Usage_Con_ContactMisc Usage_i16(0x514)
+#define Usage_Dig_Digitizer Usage_i8(0x1)
+#define Usage_Dig_Pen Usage_i8(0x2)
+#define Usage_Dig_LightPen Usage_i8(0x3)
+#define Usage_Dig_TouchScreen Usage_i8(0x4)
+#define Usage_Dig_TouchPad Usage_i8(0x5)
+#define Usage_Dig_Whiteboard Usage_i8(0x6)
+#define Usage_Dig_CoordinateMeasuringMachine Usage_i8(0x7)
+#define Usage_Dig_ThreeDDigitizer Usage_i8(0x8)
+#define Usage_Dig_StereoPlotter Usage_i8(0x9)
+#define Usage_Dig_ArticulatedArm Usage_i8(0xa)
+#define Usage_Dig_Armature Usage_i8(0xb)
+#define Usage_Dig_MultiplePointDigitizer Usage_i8(0xc)
+#define Usage_Dig_FreeSpaceWand Usage_i8(0xd)
+#define Usage_Dig_DeviceConfiguration Usage_i8(0xe)
+#define Usage_Dig_CapacitiveHeatMapDigitizer Usage_i8(0xf)
+#define Usage_Dig_Stylus Usage_i8(0x20)
+#define Usage_Dig_Puck Usage_i8(0x21)
+#define Usage_Dig_Finger Usage_i8(0x22)
+#define Usage_Dig_Devicesettings Usage_i8(0x23)
+#define Usage_Dig_CharacterGesture Usage_i8(0x24)
+#define Usage_Dig_TipPressure Usage_i8(0x30)
+#define Usage_Dig_BarrelPressure Usage_i8(0x31)
+#define Usage_Dig_InRange Usage_i8(0x32)
+#define Usage_Dig_Touch Usage_i8(0x33)
+#define Usage_Dig_Untouch Usage_i8(0x34)
+#define Usage_Dig_Tap Usage_i8(0x35)
+#define Usage_Dig_Quality Usage_i8(0x36)
+#define Usage_Dig_DataValid Usage_i8(0x37)
+#define Usage_Dig_TransducerIndex Usage_i8(0x38)
+#define Usage_Dig_TabletFunctionKeys Usage_i8(0x39)
+#define Usage_Dig_ProgramChangeKeys Usage_i8(0x3a)
+#define Usage_Dig_BatteryStrength Usage_i8(0x3b)
+#define Usage_Dig_Invert Usage_i8(0x3c)
+#define Usage_Dig_XTilt Usage_i8(0x3d)
+#define Usage_Dig_YTilt Usage_i8(0x3e)
+#define Usage_Dig_Azimuth Usage_i8(0x3f)
+#define Usage_Dig_Altitude Usage_i8(0x40)
+#define Usage_Dig_Twist Usage_i8(0x41)
+#define Usage_Dig_TipSwitch Usage_i8(0x42)
+#define Usage_Dig_SecondaryTipSwitch Usage_i8(0x43)
+#define Usage_Dig_BarrelSwitch Usage_i8(0x44)
+#define Usage_Dig_Eraser Usage_i8(0x45)
+#define Usage_Dig_TabletPick Usage_i8(0x46)
+#define Usage_Dig_TouchValid Usage_i8(0x47)
+#define Usage_Dig_Width Usage_i8(0x48)
+#define Usage_Dig_Height Usage_i8(0x49)
+#define Usage_Dig_ContactIdentifier Usage_i8(0x51)
+#define Usage_Dig_DeviceMode Usage_i8(0x52)
+#define Usage_Dig_DeviceIdentifier Usage_i8(0x53)
+#define Usage_Dig_ContactCount Usage_i8(0x54)
+#define Usage_Dig_ContactCountMaximum Usage_i8(0x55)
+#define Usage_Dig_ScanTime Usage_i8(0x56)
+#define Usage_Dig_SurfaceSwitch Usage_i8(0x57)
+#define Usage_Dig_ButtonSwitch Usage_i8(0x58)
+#define Usage_Dig_PadType Usage_i8(0x59)
+#define Usage_Dig_SecondaryBarrelSwitch Usage_i8(0x5a)
+#define Usage_Dig_TransducerSerialNumber Usage_i8(0x5b)
+#define Usage_Dig_PreferredColor Usage_i8(0x5c)
+#define Usage_Dig_PreferredColorisLocked Usage_i8(0x5d)
+#define Usage_Dig_PreferredLineWidth Usage_i8(0x5e)
+#define Usage_Dig_PreferredLineWidthisLocked Usage_i8(0x5f)
+#define Usage_Dig_LatencyMode Usage_i8(0x60)
+#define Usage_Dig_GestureCharacterQuality Usage_i8(0x61)
+#define Usage_Dig_CharacterGestureDataLength Usage_i8(0x62)
+#define Usage_Dig_CharacterGestureData Usage_i8(0x63)
+#define Usage_Dig_GestureCharacterEncoding Usage_i8(0x64)
+#define Usage_Dig_UTF8CharacterGestureEncoding Usage_i8(0x65)
+#define Usage_Dig_UTF16LittleEndianCharacterGestureEncoding Usage_i8(0x66)
+#define Usage_Dig_UTF16BigEndianCharacterGestureEncoding Usage_i8(0x67)
+#define Usage_Dig_UTF32LittleEndianCharacterGestureEncoding Usage_i8(0x68)
+#define Usage_Dig_UTF32BigEndianCharacterGestureEncoding Usage_i8(0x69)
+#define Usage_Dig_CapacitiveHeatMapProtocolVendorID Usage_i8(0x6a)
+#define Usage_Dig_CapacitiveHeatMapProtocolVersion Usage_i8(0x6b)
+#define Usage_Dig_CapacitiveHeatMapFrameData Usage_i8(0x6c)
+#define Usage_Dig_GestureCharacterEnable Usage_i8(0x6d)
+#define Usage_Dig_TransducerSerialNumberPart2 Usage_i8(0x6e)
+#define Usage_Dig_NoPreferredColor Usage_i8(0x6f)
+#define Usage_Dig_PreferredLineStyle Usage_i8(0x70)
+#define Usage_Dig_PreferredLineStyleisLocked Usage_i8(0x71)
+#define Usage_Dig_Ink Usage_i8(0x72)
+#define Usage_Dig_Pencil Usage_i8(0x73)
+#define Usage_Dig_Highlighter Usage_i8(0x74)
+#define Usage_Dig_ChiselMarker Usage_i8(0x75)
+#define Usage_Dig_Brush Usage_i8(0x76)
+#define Usage_Dig_NoPreference Usage_i8(0x77)
+#define Usage_Dig_DigitizerDiagnostic Usage_i8(0x80)
+#define Usage_Dig_DigitizerError Usage_i8(0x81)
+#define Usage_Dig_ErrNormalStatus Usage_i8(0x82)
+#define Usage_Dig_ErrTransducersExceeded Usage_i8(0x83)
+#define Usage_Dig_ErrFullTransFeaturesUnavailable Usage_i8(0x84)
+#define Usage_Dig_ErrChargeLow Usage_i8(0x85)
+#define Usage_Dig_TransducerSoftwareInfo Usage_i8(0x90)
+#define Usage_Dig_TransducerVendorId Usage_i8(0x91)
+#define Usage_Dig_TransducerProductId Usage_i8(0x92)
+#define Usage_Dig_DeviceSupportedProtocols Usage_i8(0x93)
+#define Usage_Dig_TransducerSupportedProtocols Usage_i8(0x94)
+#define Usage_Dig_NoProtocol Usage_i8(0x95)
+#define Usage_Dig_WacomAESProtocol Usage_i8(0x96)
+#define Usage_Dig_USIProtocol Usage_i8(0x97)
+#define Usage_Dig_MicrosoftPenProtocol Usage_i8(0x98)
+#define Usage_Dig_SupportedReportRates Usage_i8(0xa0)
+#define Usage_Dig_ReportRate Usage_i8(0xa1)
+#define Usage_Dig_TransducerConnected Usage_i8(0xa2)
+#define Usage_Dig_SwitchDisabled Usage_i8(0xa3)
+#define Usage_Dig_SwitchUnimplemented Usage_i8(0xa4)
+#define Usage_Dig_TransducerSwitches Usage_i8(0xa5)
+#define Usage_Dig_TransducerIndexSelector Usage_i8(0xa6)
+#define Usage_Dig_ButtonPressThreshold Usage_i8(0xb0)
+#define Usage_Hap_SimpleHapticController Usage_i8(0x1)
+#define Usage_Hap_WaveformList Usage_i8(0x10)
+#define Usage_Hap_DurationList Usage_i8(0x11)
+#define Usage_Hap_AutoTrigger Usage_i8(0x20)
+#define Usage_Hap_ManualTrigger Usage_i8(0x21)
+#define Usage_Hap_AutoTriggerAssociatedControl Usage_i8(0x22)
+#define Usage_Hap_Intensity Usage_i8(0x23)
+#define Usage_Hap_RepeatCount Usage_i8(0x24)
+#define Usage_Hap_RetriggerPeriod Usage_i8(0x25)
+#define Usage_Hap_WaveformVendorPage Usage_i8(0x26)
+#define Usage_Hap_WaveformVendorID Usage_i8(0x27)
+#define Usage_Hap_WaveformCutoffTime Usage_i8(0x28)
+#define Usage_Hap_WaveformNone Usage_i16(0x1001)
+#define Usage_Hap_WaveformStop Usage_i16(0x1002)
+#define Usage_Hap_WaveformClick Usage_i16(0x1003)
+#define Usage_Hap_WaveformBuzzContinuous Usage_i16(0x1004)
+#define Usage_Hap_WaveformRumbleContinuous Usage_i16(0x1005)
+#define Usage_Hap_WaveformPress Usage_i16(0x1006)
+#define Usage_Hap_WaveformRelease Usage_i16(0x1007)
+#define Usage_Hap_WaveformHover Usage_i16(0x1008)
+#define Usage_Hap_WaveformSuccess Usage_i16(0x1009)
+#define Usage_Hap_WaveformError Usage_i16(0x100a)
+#define Usage_Hap_WaveformInkContinuous Usage_i16(0x100b)
+#define Usage_Hap_WaveformPencilContinuous Usage_i16(0x100c)
+#define Usage_Hap_WaveformMarkerContinuous Usage_i16(0x100d)
+#define Usage_Hap_WaveformChiselMarkerContinuous Usage_i16(0x100e)
+#define Usage_Hap_WaveformBrushContinuous Usage_i16(0x100f)
+#define Usage_Hap_WaveformEraserContinuous Usage_i16(0x1010)
+#define Usage_Hap_WaveformSparkleContinuous Usage_i16(0x1011)
+#define Usage_PID_PhysicalInputDevice Usage_i8(0x1)
+#define Usage_PID_Normal Usage_i8(0x20)
+#define Usage_PID_SetEffectReport Usage_i8(0x21)
+#define Usage_PID_EffectParameterBlockIndex Usage_i8(0x22)
+#define Usage_PID_ParameterBlockOffset Usage_i8(0x23)
+#define Usage_PID_ROMFlag Usage_i8(0x24)
+#define Usage_PID_EffectType Usage_i8(0x25)
+#define Usage_PID_ETConstantForce Usage_i8(0x26)
+#define Usage_PID_ETRamp Usage_i8(0x27)
+#define Usage_PID_ETCustomForce Usage_i8(0x28)
+#define Usage_PID_ETSquare Usage_i8(0x30)
+#define Usage_PID_ETSine Usage_i8(0x31)
+#define Usage_PID_ETTriangle Usage_i8(0x32)
+#define Usage_PID_ETSawtoothUp Usage_i8(0x33)
+#define Usage_PID_ETSawtoothDown Usage_i8(0x34)
+#define Usage_PID_ETSpring Usage_i8(0x40)
+#define Usage_PID_ETDamper Usage_i8(0x41)
+#define Usage_PID_ETInertia Usage_i8(0x42)
+#define Usage_PID_ETFriction Usage_i8(0x43)
+#define Usage_PID_Duration Usage_i8(0x50)
+#define Usage_PID_SamplePeriod Usage_i8(0x51)
+#define Usage_PID_Gain Usage_i8(0x52)
+#define Usage_PID_TriggerButton Usage_i8(0x53)
+#define Usage_PID_TriggerRepeatInterval Usage_i8(0x54)
+#define Usage_PID_AxesEnable Usage_i8(0x55)
+#define Usage_PID_DirectionEnable Usage_i8(0x56)
+#define Usage_PID_Direction Usage_i8(0x57)
+#define Usage_PID_TypeSpecificBlockOffset Usage_i8(0x58)
+#define Usage_PID_BlockType Usage_i8(0x59)
+#define Usage_PID_SetEnvelopeReport Usage_i8(0x5a)
+#define Usage_PID_AttackLevel Usage_i8(0x5b)
+#define Usage_PID_AttackTime Usage_i8(0x5c)
+#define Usage_PID_FadeLevel Usage_i8(0x5d)
+#define Usage_PID_FadeTime Usage_i8(0x5e)
+#define Usage_PID_SetConditionReport Usage_i8(0x5f)
+#define Usage_PID_CenterPointOffset Usage_i8(0x60)
+#define Usage_PID_PositiveCoefficient Usage_i8(0x61)
+#define Usage_PID_NegativeCoefficient Usage_i8(0x62)
+#define Usage_PID_PositiveSaturation Usage_i8(0x63)
+#define Usage_PID_NegativeSaturation Usage_i8(0x64)
+#define Usage_PID_DeadBand Usage_i8(0x65)
+#define Usage_PID_DownloadForceSample Usage_i8(0x66)
+#define Usage_PID_IsochCustomForceEnable Usage_i8(0x67)
+#define Usage_PID_CustomForceDataReport Usage_i8(0x68)
+#define Usage_PID_CustomForceData Usage_i8(0x69)
+#define Usage_PID_CustomForceVendorDefinedData Usage_i8(0x6a)
+#define Usage_PID_SetCustomForceReport Usage_i8(0x6b)
+#define Usage_PID_CustomForceDataOffset Usage_i8(0x6c)
+#define Usage_PID_SampleCount Usage_i8(0x6d)
+#define Usage_PID_SetPeriodicReport Usage_i8(0x6e)
+#define Usage_PID_Offset Usage_i8(0x6f)
+#define Usage_PID_Magnitude Usage_i8(0x70)
+#define Usage_PID_Phase Usage_i8(0x71)
+#define Usage_PID_Period Usage_i8(0x72)
+#define Usage_PID_SetConstantForceReport Usage_i8(0x73)
+#define Usage_PID_SetRampForceReport Usage_i8(0x74)
+#define Usage_PID_RampStart Usage_i8(0x75)
+#define Usage_PID_RampEnd Usage_i8(0x76)
+#define Usage_PID_EffectOperationReport Usage_i8(0x77)
+#define Usage_PID_EffectOperation Usage_i8(0x78)
+#define Usage_PID_OpEffectStart Usage_i8(0x79)
+#define Usage_PID_OpEffectStartSolo Usage_i8(0x7a)
+#define Usage_PID_OpEffectStop Usage_i8(0x7b)
+#define Usage_PID_LoopCount Usage_i8(0x7c)
+#define Usage_PID_DeviceGainReport Usage_i8(0x7d)
+#define Usage_PID_DeviceGain Usage_i8(0x7e)
+#define Usage_PID_ParameterBlockPoolsReport Usage_i8(0x7f)
+#define Usage_PID_RAMPoolSize Usage_i8(0x80)
+#define Usage_PID_ROMPoolSize Usage_i8(0x81)
+#define Usage_PID_ROMEffectBlockCount Usage_i8(0x82)
+#define Usage_PID_SimultaneousEffectsMax Usage_i8(0x83)
+#define Usage_PID_PoolAlignment Usage_i8(0x84)
+#define Usage_PID_ParameterBlockMoveReport Usage_i8(0x85)
+#define Usage_PID_MoveSource Usage_i8(0x86)
+#define Usage_PID_MoveDestination Usage_i8(0x87)
+#define Usage_PID_MoveLength Usage_i8(0x88)
+#define Usage_PID_EffectParameterBlockLoadReport Usage_i8(0x89)
+#define Usage_PID_EffectParameterBlockLoadStatus Usage_i8(0x8b)
+#define Usage_PID_BlockLoadSuccess Usage_i8(0x8c)
+#define Usage_PID_BlockLoadFull Usage_i8(0x8d)
+#define Usage_PID_BlockLoadError Usage_i8(0x8e)
+#define Usage_PID_BlockHandle Usage_i8(0x8f)
+#define Usage_PID_EffectParameterBlockFreeReport Usage_i8(0x90)
+#define Usage_PID_TypeSpecificBlockHandle Usage_i8(0x91)
+#define Usage_PID_PIDStateReport Usage_i8(0x92)
+#define Usage_PID_EffectPlaying Usage_i8(0x94)
+#define Usage_PID_PIDDeviceControlReport Usage_i8(0x95)
+#define Usage_PID_PIDDeviceControl Usage_i8(0x96)
+#define Usage_PID_DCEnableActuators Usage_i8(0x97)
+#define Usage_PID_DCDisableActuators Usage_i8(0x98)
+#define Usage_PID_DCStopAllEffects Usage_i8(0x99)
+#define Usage_PID_DCReset Usage_i8(0x9a)
+#define Usage_PID_DCPause Usage_i8(0x9b)
+#define Usage_PID_DCContinue Usage_i8(0x9c)
+#define Usage_PID_DevicePaused Usage_i8(0x9f)
+#define Usage_PID_ActuatorsEnabled Usage_i8(0xa0)
+#define Usage_PID_SafetySwitch Usage_i8(0xa4)
+#define Usage_PID_ActuatorOverrideSwitch Usage_i8(0xa5)
+#define Usage_PID_ActuatorPower Usage_i8(0xa6)
+#define Usage_PID_StartDelay Usage_i8(0xa7)
+#define Usage_PID_ParameterBlockSize Usage_i8(0xa8)
+#define Usage_PID_DeviceManagedPool Usage_i8(0xa9)
+#define Usage_PID_SharedParameterBlocks Usage_i8(0xaa)
+#define Usage_PID_CreateNewEffectParameterBlockReport Usage_i8(0xab)
+#define Usage_PID_RAMPoolAvailable Usage_i8(0xac)
+#define Usage_SC_SocControl Usage_i8(0x1)
+#define Usage_SC_FirmwareTransfer Usage_i8(0x2)
+#define Usage_SC_FirmwareFileId Usage_i8(0x3)
+#define Usage_SC_FileOffsetInBytes Usage_i8(0x4)
+#define Usage_SC_FileTransferSizeMaxInBytes Usage_i8(0x5)
+#define Usage_SC_FilePayload Usage_i8(0x6)
+#define Usage_SC_FilePayloadSizeInBytes Usage_i8(0x7)
+#define Usage_SC_FilePayloadContainsLastBytes Usage_i8(0x8)
+#define Usage_SC_FileTransferStop Usage_i8(0x9)
+#define Usage_SC_FileTransferTillEnd Usage_i8(0xa)
+#define Usage_EHT_EyeTracker Usage_i8(0x1)
+#define Usage_EHT_HeadTracker Usage_i8(0x2)
+#define Usage_EHT_TrackingData Usage_i8(0x10)
+#define Usage_EHT_Capabilities Usage_i8(0x11)
+#define Usage_EHT_Configuration Usage_i8(0x12)
+#define Usage_EHT_Status Usage_i8(0x13)
+#define Usage_EHT_Control Usage_i8(0x14)
+#define Usage_EHT_SensorTimestamp Usage_i8(0x20)
+#define Usage_EHT_PositionX Usage_i8(0x21)
+#define Usage_EHT_PositionY Usage_i8(0x22)
+#define Usage_EHT_PositionZ Usage_i8(0x23)
+#define Usage_EHT_GazePoint Usage_i8(0x24)
+#define Usage_EHT_LeftEyePosition Usage_i8(0x25)
+#define Usage_EHT_RightEyePosition Usage_i8(0x26)
+#define Usage_EHT_HeadPosition Usage_i8(0x27)
+#define Usage_EHT_HeadDirectionPoint Usage_i8(0x28)
+#define Usage_EHT_RotationaboutXaxis Usage_i8(0x29)
+#define Usage_EHT_RotationaboutYaxis Usage_i8(0x2a)
+#define Usage_EHT_RotationaboutZaxis Usage_i8(0x2b)
+#define Usage_EHT_TrackerQuality Usage_i16(0x100)
+#define Usage_EHT_MinimumTrackingDistance Usage_i16(0x101)
+#define Usage_EHT_OptimumTrackingDistance Usage_i16(0x102)
+#define Usage_EHT_MaximumTrackingDistance Usage_i16(0x103)
+#define Usage_EHT_MaximumScreenPlaneWidth Usage_i16(0x104)
+#define Usage_EHT_MaximumScreenPlaneHeight Usage_i16(0x105)
+#define Usage_EHT_DisplayManufacturerID Usage_i16(0x200)
+#define Usage_EHT_DisplayProductID Usage_i16(0x201)
+#define Usage_EHT_DisplaySerialNumber Usage_i16(0x202)
+#define Usage_EHT_DisplayManufacturerDate Usage_i16(0x203)
+#define Usage_EHT_CalibratedScreenWidth Usage_i16(0x204)
+#define Usage_EHT_CalibratedScreenHeight Usage_i16(0x205)
+#define Usage_EHT_SamplingFrequency Usage_i16(0x300)
+#define Usage_EHT_ConfigurationStatus Usage_i16(0x301)
+#define Usage_EHT_DeviceModeRequest Usage_i16(0x400)
+#define Usage_AD_AlphanumericDisplay Usage_i8(0x1)
+#define Usage_AD_AuxiliaryDisplay Usage_i8(0x2)
+#define Usage_AD_DisplayAttributesReport Usage_i8(0x20)
+#define Usage_AD_ASCIICharacterSet Usage_i8(0x21)
+#define Usage_AD_DataReadBack Usage_i8(0x22)
+#define Usage_AD_FontReadBack Usage_i8(0x23)
+#define Usage_AD_DisplayControlReport Usage_i8(0x24)
+#define Usage_AD_ClearDisplay Usage_i8(0x25)
+#define Usage_AD_DisplayEnable Usage_i8(0x26)
+#define Usage_AD_ScreenSaverDelay Usage_i8(0x27)
+#define Usage_AD_ScreenSaverEnable Usage_i8(0x28)
+#define Usage_AD_VerticalScroll Usage_i8(0x29)
+#define Usage_AD_HorizontalScroll Usage_i8(0x2a)
+#define Usage_AD_CharacterReport Usage_i8(0x2b)
+#define Usage_AD_DisplayData Usage_i8(0x2c)
+#define Usage_AD_DisplayStatus Usage_i8(0x2d)
+#define Usage_AD_StatNotReady Usage_i8(0x2e)
+#define Usage_AD_StatReady Usage_i8(0x2f)
+#define Usage_AD_ErrNotaloadablecharacter Usage_i8(0x30)
+#define Usage_AD_ErrFontdatacannotberead Usage_i8(0x31)
+#define Usage_AD_CursorPositionReport Usage_i8(0x32)
+#define Usage_AD_Row Usage_i8(0x33)
+#define Usage_AD_Column Usage_i8(0x34)
+#define Usage_AD_Rows Usage_i8(0x35)
+#define Usage_AD_Columns Usage_i8(0x36)
+#define Usage_AD_CursorPixelPositioning Usage_i8(0x37)
+#define Usage_AD_CursorMode Usage_i8(0x38)
+#define Usage_AD_CursorEnable Usage_i8(0x39)
+#define Usage_AD_CursorBlink Usage_i8(0x3a)
+#define Usage_AD_FontReport Usage_i8(0x3b)
+#define Usage_AD_FontData Usage_i8(0x3c)
+#define Usage_AD_CharacterWidth Usage_i8(0x3d)
+#define Usage_AD_CharacterHeight Usage_i8(0x3e)
+#define Usage_AD_CharacterSpacingHorizontal Usage_i8(0x3f)
+#define Usage_AD_CharacterSpacingVertical Usage_i8(0x40)
+#define Usage_AD_UnicodeCharacterSet Usage_i8(0x41)
+#define Usage_AD_Font7Segment Usage_i8(0x42)
+#define Usage_AD_SevenSegmentDirectMap Usage_i8(0x43)
+#define Usage_AD_Font14Segment Usage_i8(0x44)
+#define Usage_AD_One4SegmentDirectMap Usage_i8(0x45)
+#define Usage_AD_DisplayBrightness Usage_i8(0x46)
+#define Usage_AD_DisplayContrast Usage_i8(0x47)
+#define Usage_AD_CharacterAttribute Usage_i8(0x48)
+#define Usage_AD_AttributeReadback Usage_i8(0x49)
+#define Usage_AD_AttributeData Usage_i8(0x4a)
+#define Usage_AD_CharAttrEnhance Usage_i8(0x4b)
+#define Usage_AD_CharAttrUnderline Usage_i8(0x4c)
+#define Usage_AD_CharAttrBlink Usage_i8(0x4d)
+#define Usage_AD_BitmapSizeX Usage_i8(0x80)
+#define Usage_AD_BitmapSizeY Usage_i8(0x81)
+#define Usage_AD_MaxBlitSize Usage_i8(0x82)
+#define Usage_AD_BitDepthFormat Usage_i8(0x83)
+#define Usage_AD_DisplayOrientation Usage_i8(0x84)
+#define Usage_AD_PaletteReport Usage_i8(0x85)
+#define Usage_AD_PaletteDataSize Usage_i8(0x86)
+#define Usage_AD_PaletteDataOffset Usage_i8(0x87)
+#define Usage_AD_PaletteData Usage_i8(0x88)
+#define Usage_AD_BlitReport Usage_i8(0x8a)
+#define Usage_AD_BlitRectangleX1 Usage_i8(0x8b)
+#define Usage_AD_BlitRectangleY1 Usage_i8(0x8c)
+#define Usage_AD_BlitRectangleX2 Usage_i8(0x8d)
+#define Usage_AD_BlitRectangleY2 Usage_i8(0x8e)
+#define Usage_AD_BlitData Usage_i8(0x8f)
+#define Usage_AD_SoftButton Usage_i8(0x90)
+#define Usage_AD_SoftButtonID Usage_i8(0x91)
+#define Usage_AD_SoftButtonSide Usage_i8(0x92)
+#define Usage_AD_SoftButtonOffset1 Usage_i8(0x93)
+#define Usage_AD_SoftButtonOffset2 Usage_i8(0x94)
+#define Usage_AD_SoftButtonReport Usage_i8(0x95)
+#define Usage_AD_SoftKeys Usage_i8(0xc2)
+#define Usage_AD_DisplayDataExtensions Usage_i8(0xcc)
+#define Usage_AD_CharacterMapping Usage_i8(0xcf)
+#define Usage_AD_UnicodeEquivalent Usage_i8(0xdd)
+#define Usage_AD_CharacterPageMapping Usage_i8(0xdf)
+#define Usage_AD_RequestReport Usage_i16(0xff)
+#define Usage_Sen_Sensor Usage_i8(0x1)
+#define Usage_Sen_Biometric Usage_i8(0x10)
+#define Usage_Sen_BiometricHumanPresence Usage_i8(0x11)
+#define Usage_Sen_BiometricHumanProximity Usage_i8(0x12)
+#define Usage_Sen_BiometricHumanTouch Usage_i8(0x13)
+#define Usage_Sen_BiometricBloodPressure Usage_i8(0x14)
+#define Usage_Sen_BiometricBodyTemperature Usage_i8(0x15)
+#define Usage_Sen_BiometricHeartRate Usage_i8(0x16)
+#define Usage_Sen_BiometricHeartRateVariability Usage_i8(0x17)
+#define Usage_Sen_BiometricPeripheralOxygenSaturation Usage_i8(0x18)
+#define Usage_Sen_BiometricRespiratoryRate Usage_i8(0x19)
+#define Usage_Sen_Electrical Usage_i8(0x20)
+#define Usage_Sen_ElectricalCapacitance Usage_i8(0x21)
+#define Usage_Sen_ElectricalCurrent Usage_i8(0x22)
+#define Usage_Sen_ElectricalPower Usage_i8(0x23)
+#define Usage_Sen_ElectricalInductance Usage_i8(0x24)
+#define Usage_Sen_ElectricalResistance Usage_i8(0x25)
+#define Usage_Sen_ElectricalVoltage Usage_i8(0x26)
+#define Usage_Sen_ElectricalPotentiometer Usage_i8(0x27)
+#define Usage_Sen_ElectricalFrequency Usage_i8(0x28)
+#define Usage_Sen_ElectricalPeriod Usage_i8(0x29)
+#define Usage_Sen_Environmental Usage_i8(0x30)
+#define Usage_Sen_EnvironmentalAtmosphericPressure Usage_i8(0x31)
+#define Usage_Sen_EnvironmentalHumidity Usage_i8(0x32)
+#define Usage_Sen_EnvironmentalTemperature Usage_i8(0x33)
+#define Usage_Sen_EnvironmentalWindDirection Usage_i8(0x34)
+#define Usage_Sen_EnvironmentalWindSpeed Usage_i8(0x35)
+#define Usage_Sen_EnvironmentalAirQuality Usage_i8(0x36)
+#define Usage_Sen_EnvironmentalHeatIndex Usage_i8(0x37)
+#define Usage_Sen_EnvironmentalSurfaceTemperature Usage_i8(0x38)
+#define Usage_Sen_EnvironmentalVolatileOrganicCompounds Usage_i8(0x39)
+#define Usage_Sen_EnvironmentalObjectPresence Usage_i8(0x3a)
+#define Usage_Sen_EnvironmentalObjectProximity Usage_i8(0x3b)
+#define Usage_Sen_Light Usage_i8(0x40)
+#define Usage_Sen_LightAmbientLight Usage_i8(0x41)
+#define Usage_Sen_LightConsumerInfrared Usage_i8(0x42)
+#define Usage_Sen_LightInfraredLight Usage_i8(0x43)
+#define Usage_Sen_LightVisibleLight Usage_i8(0x44)
+#define Usage_Sen_LightUltravioletLight Usage_i8(0x45)
+#define Usage_Sen_Location Usage_i8(0x50)
+#define Usage_Sen_LocationBroadcast Usage_i8(0x51)
+#define Usage_Sen_LocationDeadReckoning Usage_i8(0x52)
+#define Usage_Sen_LocationGPSGlobalPositioningSystem Usage_i8(0x53)
+#define Usage_Sen_LocationLookup Usage_i8(0x54)
+#define Usage_Sen_LocationOther Usage_i8(0x55)
+#define Usage_Sen_LocationStatic Usage_i8(0x56)
+#define Usage_Sen_LocationTriangulation Usage_i8(0x57)
+#define Usage_Sen_Mechanical Usage_i8(0x60)
+#define Usage_Sen_MechanicalBooleanSwitch Usage_i8(0x61)
+#define Usage_Sen_MechanicalBooleanSwitchArray Usage_i8(0x62)
+#define Usage_Sen_MechanicalMultivalueSwitch Usage_i8(0x63)
+#define Usage_Sen_MechanicalForce Usage_i8(0x64)
+#define Usage_Sen_MechanicalPressure Usage_i8(0x65)
+#define Usage_Sen_MechanicalStrain Usage_i8(0x66)
+#define Usage_Sen_MechanicalWeight Usage_i8(0x67)
+#define Usage_Sen_MechanicalHapticVibrator Usage_i8(0x68)
+#define Usage_Sen_MechanicalHallEffectSwitch Usage_i8(0x69)
+#define Usage_Sen_Motion Usage_i8(0x70)
+#define Usage_Sen_MotionAccelerometer1D Usage_i8(0x71)
+#define Usage_Sen_MotionAccelerometer2D Usage_i8(0x72)
+#define Usage_Sen_MotionAccelerometer3D Usage_i8(0x73)
+#define Usage_Sen_MotionGyrometer1D Usage_i8(0x74)
+#define Usage_Sen_MotionGyrometer2D Usage_i8(0x75)
+#define Usage_Sen_MotionGyrometer3D Usage_i8(0x76)
+#define Usage_Sen_MotionMotionDetector Usage_i8(0x77)
+#define Usage_Sen_MotionSpeedometer Usage_i8(0x78)
+#define Usage_Sen_MotionAccelerometer Usage_i8(0x79)
+#define Usage_Sen_MotionGyrometer Usage_i8(0x7a)
+#define Usage_Sen_MotionGravityVector Usage_i8(0x7b)
+#define Usage_Sen_MotionLinearAccelerometer Usage_i8(0x7c)
+#define Usage_Sen_Orientation Usage_i8(0x80)
+#define Usage_Sen_OrientationCompass1D Usage_i8(0x81)
+#define Usage_Sen_OrientationCompass2D Usage_i8(0x82)
+#define Usage_Sen_OrientationCompass3D Usage_i8(0x83)
+#define Usage_Sen_OrientationInclinometer1D Usage_i8(0x84)
+#define Usage_Sen_OrientationInclinometer2D Usage_i8(0x85)
+#define Usage_Sen_OrientationInclinometer3D Usage_i8(0x86)
+#define Usage_Sen_OrientationDistance1D Usage_i8(0x87)
+#define Usage_Sen_OrientationDistance2D Usage_i8(0x88)
+#define Usage_Sen_OrientationDistance3D Usage_i8(0x89)
+#define Usage_Sen_OrientationDeviceOrientation Usage_i8(0x8a)
+#define Usage_Sen_OrientationCompass Usage_i8(0x8b)
+#define Usage_Sen_OrientationInclinometer Usage_i8(0x8c)
+#define Usage_Sen_OrientationDistance Usage_i8(0x8d)
+#define Usage_Sen_OrientationRelativeOrientation Usage_i8(0x8e)
+#define Usage_Sen_OrientationSimpleOrientation Usage_i8(0x8f)
+#define Usage_Sen_Scanner Usage_i8(0x90)
+#define Usage_Sen_ScannerBarcode Usage_i8(0x91)
+#define Usage_Sen_ScannerRFID Usage_i8(0x92)
+#define Usage_Sen_ScannerNFC Usage_i8(0x93)
+#define Usage_Sen_Time Usage_i8(0xa0)
+#define Usage_Sen_TimeAlarmTimer Usage_i8(0xa1)
+#define Usage_Sen_TimeRealTimeClock Usage_i8(0xa2)
+#define Usage_Sen_PersonalActivity Usage_i8(0xb0)
+#define Usage_Sen_PersonalActivityActivityDetection Usage_i8(0xb1)
+#define Usage_Sen_PersonalActivityDevicePosition Usage_i8(0xb2)
+#define Usage_Sen_PersonalActivityFloorTracker Usage_i8(0xb3)
+#define Usage_Sen_PersonalActivityPedometer Usage_i8(0xb4)
+#define Usage_Sen_PersonalActivityStepDetection Usage_i8(0xb5)
+#define Usage_Sen_OrientationExtended Usage_i8(0xc0)
+#define Usage_Sen_OrientationExtendedGeomagneticOrientation Usage_i8(0xc1)
+#define Usage_Sen_OrientationExtendedMagnetometer Usage_i8(0xc2)
+#define Usage_Sen_Gesture Usage_i8(0xd0)
+#define Usage_Sen_GestureChassisFlipGesture Usage_i8(0xd1)
+#define Usage_Sen_GestureHingeFoldGesture Usage_i8(0xd2)
+#define Usage_Sen_Other Usage_i8(0xe0)
+#define Usage_Sen_OtherCustom Usage_i8(0xe1)
+#define Usage_Sen_OtherGeneric Usage_i8(0xe2)
+#define Usage_Sen_OtherGenericEnumerator Usage_i8(0xe3)
+#define Usage_Sen_OtherHingeAngle Usage_i8(0xe4)
+#define Usage_Sen_VendorReserved1 Usage_i8(0xf0)
+#define Usage_Sen_VendorReserved2 Usage_i8(0xf1)
+#define Usage_Sen_VendorReserved3 Usage_i8(0xf2)
+#define Usage_Sen_VendorReserved4 Usage_i8(0xf3)
+#define Usage_Sen_VendorReserved5 Usage_i8(0xf4)
+#define Usage_Sen_VendorReserved6 Usage_i8(0xf5)
+#define Usage_Sen_VendorReserved7 Usage_i8(0xf6)
+#define Usage_Sen_VendorReserved8 Usage_i8(0xf7)
+#define Usage_Sen_VendorReserved9 Usage_i8(0xf8)
+#define Usage_Sen_VendorReserved10 Usage_i8(0xf9)
+#define Usage_Sen_VendorReserved11 Usage_i8(0xfa)
+#define Usage_Sen_VendorReserved12 Usage_i8(0xfb)
+#define Usage_Sen_VendorReserved13 Usage_i8(0xfc)
+#define Usage_Sen_VendorReserved14 Usage_i8(0xfd)
+#define Usage_Sen_VendorReserved15 Usage_i8(0xfe)
+#define Usage_Sen_VendorReserved16 Usage_i16(0xff)
+#define Usage_Sen_Event Usage_i16(0x200)
+#define Usage_Sen_EventSensorState Usage_i16(0x201)
+#define Usage_Sen_EventSensorEvent Usage_i16(0x202)
+#define Usage_Sen_Property Usage_i16(0x300)
+#define Usage_Sen_PropertyFriendlyName Usage_i16(0x301)
+#define Usage_Sen_PropertyPersistentUniqueID Usage_i16(0x302)
+#define Usage_Sen_PropertySensorStatus Usage_i16(0x303)
+#define Usage_Sen_PropertyMinimumReportInterval Usage_i16(0x304)
+#define Usage_Sen_PropertySensorManufacturer Usage_i16(0x305)
+#define Usage_Sen_PropertySensorModel Usage_i16(0x306)
+#define Usage_Sen_PropertySensorSerialNumber Usage_i16(0x307)
+#define Usage_Sen_PropertySensorDescription Usage_i16(0x308)
+#define Usage_Sen_PropertySensorConnectionType Usage_i16(0x309)
+#define Usage_Sen_PropertySensorDevicePath Usage_i16(0x30a)
+#define Usage_Sen_PropertyHardwareRevision Usage_i16(0x30b)
+#define Usage_Sen_PropertyFirmwareVersion Usage_i16(0x30c)
+#define Usage_Sen_PropertyReleaseDate Usage_i16(0x30d)
+#define Usage_Sen_PropertyReportInterval Usage_i16(0x30e)
+#define Usage_Sen_PropertyChangeSensitivityAbsolute Usage_i16(0x30f)
+#define Usage_Sen_PropertyChangeSensitivityPercentofRange Usage_i16(0x310)
+#define Usage_Sen_PropertyChangeSensitivityPercentRelative Usage_i16(0x311)
+#define Usage_Sen_PropertyAccuracy Usage_i16(0x312)
+#define Usage_Sen_PropertyResolution Usage_i16(0x313)
+#define Usage_Sen_PropertyMaximum Usage_i16(0x314)
+#define Usage_Sen_PropertyMinimum Usage_i16(0x315)
+#define Usage_Sen_PropertyReportingState Usage_i16(0x316)
+#define Usage_Sen_PropertySamplingRate Usage_i16(0x317)
+#define Usage_Sen_PropertyResponseCurve Usage_i16(0x318)
+#define Usage_Sen_PropertyPowerState Usage_i16(0x319)
+#define Usage_Sen_PropertyMaximumFIFOEvents Usage_i16(0x31a)
+#define Usage_Sen_PropertyReportLatency Usage_i16(0x31b)
+#define Usage_Sen_PropertyFlushFIFOEvents Usage_i16(0x31c)
+#define Usage_Sen_PropertyMaximumPowerConsumption Usage_i16(0x31d)
+#define Usage_Sen_PropertyIsPrimary Usage_i16(0x31e)
+#define Usage_Sen_PropertyHumanPresenceDetectionType Usage_i16(0x31f)
+#define Usage_Sen_DataFieldLocation Usage_i16(0x400)
+#define Usage_Sen_DataFieldAltitudeAntennaSeaLevel Usage_i16(0x402)
+#define Usage_Sen_DataFieldDifferentialReferenceStationID Usage_i16(0x403)
+#define Usage_Sen_DataFieldAltitudeEllipsoidError Usage_i16(0x404)
+#define Usage_Sen_DataFieldAltitudeEllipsoid Usage_i16(0x405)
+#define Usage_Sen_DataFieldAltitudeSeaLevelError Usage_i16(0x406)
+#define Usage_Sen_DataFieldAltitudeSeaLevel Usage_i16(0x407)
+#define Usage_Sen_DataFieldDifferentialGPSDataAge Usage_i16(0x408)
+#define Usage_Sen_DataFieldErrorRadius Usage_i16(0x409)
+#define Usage_Sen_DataFieldFixQuality Usage_i16(0x40a)
+#define Usage_Sen_DataFieldFixType Usage_i16(0x40b)
+#define Usage_Sen_DataFieldGeoidalSeparation Usage_i16(0x40c)
+#define Usage_Sen_DataFieldGPSOperationMode Usage_i16(0x40d)
+#define Usage_Sen_DataFieldGPSSelectionMode Usage_i16(0x40e)
+#define Usage_Sen_DataFieldGPSStatus Usage_i16(0x40f)
+#define Usage_Sen_DataFieldPositionDilutionofPrecision Usage_i16(0x410)
+#define Usage_Sen_DataFieldHorizontalDilutionofPrecision Usage_i16(0x411)
+#define Usage_Sen_DataFieldVerticalDilutionofPrecision Usage_i16(0x412)
+#define Usage_Sen_DataFieldLatitude Usage_i16(0x413)
+#define Usage_Sen_DataFieldLongitude Usage_i16(0x414)
+#define Usage_Sen_DataFieldTrueHeading Usage_i16(0x415)
+#define Usage_Sen_DataFieldMagneticHeading Usage_i16(0x416)
+#define Usage_Sen_DataFieldMagneticVariation Usage_i16(0x417)
+#define Usage_Sen_DataFieldSpeed Usage_i16(0x418)
+#define Usage_Sen_DataFieldSatellitesinView Usage_i16(0x419)
+#define Usage_Sen_DataFieldSatellitesinViewAzimuth Usage_i16(0x41a)
+#define Usage_Sen_DataFieldSatellitesinViewElevation Usage_i16(0x41b)
+#define Usage_Sen_DataFieldSatellitesinViewIDs Usage_i16(0x41c)
+#define Usage_Sen_DataFieldSatellitesinViewPRNs Usage_i16(0x41d)
+#define Usage_Sen_DataFieldSatellitesinViewSNRatios Usage_i16(0x41e)
+#define Usage_Sen_DataFieldSatellitesUsedCount Usage_i16(0x41f)
+#define Usage_Sen_DataFieldSatellitesUsedPRNs Usage_i16(0x420)
+#define Usage_Sen_DataFieldNMEASentence Usage_i16(0x421)
+#define Usage_Sen_DataFieldAddressLine1 Usage_i16(0x422)
+#define Usage_Sen_DataFieldAddressLine2 Usage_i16(0x423)
+#define Usage_Sen_DataFieldCity Usage_i16(0x424)
+#define Usage_Sen_DataFieldStateorProvince Usage_i16(0x425)
+#define Usage_Sen_DataFieldCountryorRegion Usage_i16(0x426)
+#define Usage_Sen_DataFieldPostalCode Usage_i16(0x427)
+#define Usage_Sen_PropertyLocation Usage_i16(0x42a)
+#define Usage_Sen_PropertyLocationDesiredAccuracy Usage_i16(0x42b)
+#define Usage_Sen_DataFieldEnvironmental Usage_i16(0x430)
+#define Usage_Sen_DataFieldAtmosphericPressure Usage_i16(0x431)
+#define Usage_Sen_DataFieldRelativeHumidity Usage_i16(0x433)
+#define Usage_Sen_DataFieldTemperature Usage_i16(0x434)
+#define Usage_Sen_DataFieldWindDirection Usage_i16(0x435)
+#define Usage_Sen_DataFieldWindSpeed Usage_i16(0x436)
+#define Usage_Sen_DataFieldAirQualityIndex Usage_i16(0x437)
+#define Usage_Sen_DataFieldEquivalentCO2 Usage_i16(0x438)
+#define Usage_Sen_DataFieldVolatileOrganicCompoundConcentration Usage_i16(0x439)
+#define Usage_Sen_DataFieldObjectPresence Usage_i16(0x43a)
+#define Usage_Sen_DataFieldObjectProximityRange Usage_i16(0x43b)
+#define Usage_Sen_DataFieldObjectProximityOutofRange Usage_i16(0x43c)
+#define Usage_Sen_PropertyEnvironmental Usage_i16(0x440)
+#define Usage_Sen_PropertyReferencePressure Usage_i16(0x441)
+#define Usage_Sen_DataFieldMotion Usage_i16(0x450)
+#define Usage_Sen_DataFieldMotionState Usage_i16(0x451)
+#define Usage_Sen_DataFieldAcceleration Usage_i16(0x452)
+#define Usage_Sen_DataFieldAccelerationAxisX Usage_i16(0x453)
+#define Usage_Sen_DataFieldAccelerationAxisY Usage_i16(0x454)
+#define Usage_Sen_DataFieldAccelerationAxisZ Usage_i16(0x455)
+#define Usage_Sen_DataFieldAngularVelocity Usage_i16(0x456)
+#define Usage_Sen_DataFieldAngularVelocityaboutXAxis Usage_i16(0x457)
+#define Usage_Sen_DataFieldAngularVelocityaboutYAxis Usage_i16(0x458)
+#define Usage_Sen_DataFieldAngularVelocityaboutZAxis Usage_i16(0x459)
+#define Usage_Sen_DataFieldAngularPosition Usage_i16(0x45a)
+#define Usage_Sen_DataFieldAngularPositionaboutXAxis Usage_i16(0x45b)
+#define Usage_Sen_DataFieldAngularPositionaboutYAxis Usage_i16(0x45c)
+#define Usage_Sen_DataFieldAngularPositionaboutZAxis Usage_i16(0x45d)
+#define Usage_Sen_DataFieldMotionSpeed Usage_i16(0x45e)
+#define Usage_Sen_DataFieldMotionIntensity Usage_i16(0x45f)
+#define Usage_Sen_DataFieldOrientation Usage_i16(0x470)
+#define Usage_Sen_DataFieldHeading Usage_i16(0x471)
+#define Usage_Sen_DataFieldHeadingXAxis Usage_i16(0x472)
+#define Usage_Sen_DataFieldHeadingYAxis Usage_i16(0x473)
+#define Usage_Sen_DataFieldHeadingZAxis Usage_i16(0x474)
+#define Usage_Sen_DataFieldHeadingCompensatedMagneticNorth Usage_i16(0x475)
+#define Usage_Sen_DataFieldHeadingCompensatedTrueNorth Usage_i16(0x476)
+#define Usage_Sen_DataFieldHeadingMagneticNorth Usage_i16(0x477)
+#define Usage_Sen_DataFieldHeadingTrueNorth Usage_i16(0x478)
+#define Usage_Sen_DataFieldDistance Usage_i16(0x479)
+#define Usage_Sen_DataFieldDistanceXAxis Usage_i16(0x47a)
+#define Usage_Sen_DataFieldDistanceYAxis Usage_i16(0x47b)
+#define Usage_Sen_DataFieldDistanceZAxis Usage_i16(0x47c)
+#define Usage_Sen_DataFieldDistanceOutofRange Usage_i16(0x47d)
+#define Usage_Sen_DataFieldTilt Usage_i16(0x47e)
+#define Usage_Sen_DataFieldTiltXAxis Usage_i16(0x47f)
+#define Usage_Sen_DataFieldTiltYAxis Usage_i16(0x480)
+#define Usage_Sen_DataFieldTiltZAxis Usage_i16(0x481)
+#define Usage_Sen_DataFieldRotationMatrix Usage_i16(0x482)
+#define Usage_Sen_DataFieldQuaternion Usage_i16(0x483)
+#define Usage_Sen_DataFieldMagneticFlux Usage_i16(0x484)
+#define Usage_Sen_DataFieldMagneticFluxXAxis Usage_i16(0x485)
+#define Usage_Sen_DataFieldMagneticFluxYAxis Usage_i16(0x486)
+#define Usage_Sen_DataFieldMagneticFluxZAxis Usage_i16(0x487)
+#define Usage_Sen_DataFieldMagnetometerAccuracy Usage_i16(0x488)
+#define Usage_Sen_DataFieldSimpleOrientationDirection Usage_i16(0x489)
+#define Usage_Sen_DataFieldMechanical Usage_i16(0x490)
+#define Usage_Sen_DataFieldBooleanSwitchState Usage_i16(0x491)
+#define Usage_Sen_DataFieldBooleanSwitchArrayStates Usage_i16(0x492)
+#define Usage_Sen_DataFieldMultivalueSwitchValue Usage_i16(0x493)
+#define Usage_Sen_DataFieldForce Usage_i16(0x494)
+#define Usage_Sen_DataFieldAbsolutePressure Usage_i16(0x495)
+#define Usage_Sen_DataFieldGaugePressure Usage_i16(0x496)
+#define Usage_Sen_DataFieldStrain Usage_i16(0x497)
+#define Usage_Sen_DataFieldWeight Usage_i16(0x498)
+#define Usage_Sen_PropertyMechanical Usage_i16(0x4a0)
+#define Usage_Sen_PropertyVibrationState Usage_i16(0x4a1)
+#define Usage_Sen_PropertyForwardVibrationSpeed Usage_i16(0x4a2)
+#define Usage_Sen_PropertyBackwardVibrationSpeed Usage_i16(0x4a3)
+#define Usage_Sen_DataFieldBiometric Usage_i16(0x4b0)
+#define Usage_Sen_DataFieldHumanPresence Usage_i16(0x4b1)
+#define Usage_Sen_DataFieldHumanProximityRange Usage_i16(0x4b2)
+#define Usage_Sen_DataFieldHumanProximityOutofRange Usage_i16(0x4b3)
+#define Usage_Sen_DataFieldHumanTouchState Usage_i16(0x4b4)
+#define Usage_Sen_DataFieldBloodPressure Usage_i16(0x4b5)
+#define Usage_Sen_DataFieldBloodPressureDiastolic Usage_i16(0x4b6)
+#define Usage_Sen_DataFieldBloodPressureSystolic Usage_i16(0x4b7)
+#define Usage_Sen_DataFieldHeartRate Usage_i16(0x4b8)
+#define Usage_Sen_DataFieldRestingHeartRate Usage_i16(0x4b9)
+#define Usage_Sen_DataFieldHeartbeatInterval Usage_i16(0x4ba)
+#define Usage_Sen_DataFieldRespiratoryRate Usage_i16(0x4bb)
+#define Usage_Sen_DataFieldSpO2 Usage_i16(0x4bc)
+#define Usage_Sen_DataFieldHumanAttentionDetected Usage_i16(0x4bd)
+#define Usage_Sen_DataFieldHumanHeadAzimuth Usage_i16(0x4be)
+#define Usage_Sen_DataFieldHumanHeadAltitude Usage_i16(0x4bf)
+#define Usage_Sen_DataFieldHumanHeadRoll Usage_i16(0x4c0)
+#define Usage_Sen_DataFieldHumanHeadPitch Usage_i16(0x4c1)
+#define Usage_Sen_DataFieldHumanHeadYaw Usage_i16(0x4c2)
+#define Usage_Sen_DataFieldHumanCorrelationId Usage_i16(0x4c3)
+#define Usage_Sen_DataFieldLight Usage_i16(0x4d0)
+#define Usage_Sen_DataFieldIlluminance Usage_i16(0x4d1)
+#define Usage_Sen_DataFieldColorTemperature Usage_i16(0x4d2)
+#define Usage_Sen_DataFieldChromaticity Usage_i16(0x4d3)
+#define Usage_Sen_DataFieldChromaticityX Usage_i16(0x4d4)
+#define Usage_Sen_DataFieldChromaticityY Usage_i16(0x4d5)
+#define Usage_Sen_DataFieldConsumerIRSentenceReceive Usage_i16(0x4d6)
+#define Usage_Sen_DataFieldInfraredLight Usage_i16(0x4d7)
+#define Usage_Sen_DataFieldRedLight Usage_i16(0x4d8)
+#define Usage_Sen_DataFieldGreenLight Usage_i16(0x4d9)
+#define Usage_Sen_DataFieldBlueLight Usage_i16(0x4da)
+#define Usage_Sen_DataFieldUltravioletALight Usage_i16(0x4db)
+#define Usage_Sen_DataFieldUltravioletBLight Usage_i16(0x4dc)
+#define Usage_Sen_DataFieldUltravioletIndex Usage_i16(0x4dd)
+#define Usage_Sen_DataFieldNearInfraredLight Usage_i16(0x4de)
+#define Usage_Sen_PropertyLight Usage_i16(0x4df)
+#define Usage_Sen_PropertyConsumerIRSentenceSend Usage_i16(0x4e0)
+#define Usage_Sen_PropertyAutoBrightnessPreferred Usage_i16(0x4e2)
+#define Usage_Sen_PropertyAutoColorPreferred Usage_i16(0x4e3)
+#define Usage_Sen_DataFieldScanner Usage_i16(0x4f0)
+#define Usage_Sen_DataFieldRFIDTag40Bit Usage_i16(0x4f1)
+#define Usage_Sen_DataFieldNFCSentenceReceive Usage_i16(0x4f2)
+#define Usage_Sen_PropertyScanner Usage_i16(0x4f8)
+#define Usage_Sen_PropertyNFCSentenceSend Usage_i16(0x4f9)
+#define Usage_Sen_DataFieldElectrical Usage_i16(0x500)
+#define Usage_Sen_DataFieldCapacitance Usage_i16(0x501)
+#define Usage_Sen_DataFieldCurrent Usage_i16(0x502)
+#define Usage_Sen_DataFieldElectricalPower Usage_i16(0x503)
+#define Usage_Sen_DataFieldInductance Usage_i16(0x504)
+#define Usage_Sen_DataFieldResistance Usage_i16(0x505)
+#define Usage_Sen_DataFieldVoltage Usage_i16(0x506)
+#define Usage_Sen_DataFieldFrequency Usage_i16(0x507)
+#define Usage_Sen_DataFieldPeriod Usage_i16(0x508)
+#define Usage_Sen_DataFieldPercentofRange Usage_i16(0x509)
+#define Usage_Sen_DataFieldTime Usage_i16(0x520)
+#define Usage_Sen_DataFieldYear Usage_i16(0x521)
+#define Usage_Sen_DataFieldMonth Usage_i16(0x522)
+#define Usage_Sen_DataFieldDay Usage_i16(0x523)
+#define Usage_Sen_DataFieldDayofWeek Usage_i16(0x524)
+#define Usage_Sen_DataFieldHour Usage_i16(0x525)
+#define Usage_Sen_DataFieldMinute Usage_i16(0x526)
+#define Usage_Sen_DataFieldSecond Usage_i16(0x527)
+#define Usage_Sen_DataFieldMillisecond Usage_i16(0x528)
+#define Usage_Sen_DataFieldTimestamp Usage_i16(0x529)
+#define Usage_Sen_DataFieldJulianDayofYear Usage_i16(0x52a)
+#define Usage_Sen_DataFieldTimeSinceSystemBoot Usage_i16(0x52b)
+#define Usage_Sen_PropertyTime Usage_i16(0x530)
+#define Usage_Sen_PropertyTimeZoneOffsetfromUTC Usage_i16(0x531)
+#define Usage_Sen_PropertyTimeZoneName Usage_i16(0x532)
+#define Usage_Sen_PropertyDaylightSavingsTimeObserved Usage_i16(0x533)
+#define Usage_Sen_PropertyTimeTrimAdjustment Usage_i16(0x534)
+#define Usage_Sen_PropertyArmAlarm Usage_i16(0x535)
+#define Usage_Sen_DataFieldCustom Usage_i16(0x540)
+#define Usage_Sen_DataFieldCustomUsage Usage_i16(0x541)
+#define Usage_Sen_DataFieldCustomBooleanArray Usage_i16(0x542)
+#define Usage_Sen_DataFieldCustomValue Usage_i16(0x543)
+#define Usage_Sen_DataFieldCustomValue1 Usage_i16(0x544)
+#define Usage_Sen_DataFieldCustomValue2 Usage_i16(0x545)
+#define Usage_Sen_DataFieldCustomValue3 Usage_i16(0x546)
+#define Usage_Sen_DataFieldCustomValue4 Usage_i16(0x547)
+#define Usage_Sen_DataFieldCustomValue5 Usage_i16(0x548)
+#define Usage_Sen_DataFieldCustomValue6 Usage_i16(0x549)
+#define Usage_Sen_DataFieldCustomValue7 Usage_i16(0x54a)
+#define Usage_Sen_DataFieldCustomValue8 Usage_i16(0x54b)
+#define Usage_Sen_DataFieldCustomValue9 Usage_i16(0x54c)
+#define Usage_Sen_DataFieldCustomValue10 Usage_i16(0x54d)
+#define Usage_Sen_DataFieldCustomValue11 Usage_i16(0x54e)
+#define Usage_Sen_DataFieldCustomValue12 Usage_i16(0x54f)
+#define Usage_Sen_DataFieldCustomValue13 Usage_i16(0x550)
+#define Usage_Sen_DataFieldCustomValue14 Usage_i16(0x551)
+#define Usage_Sen_DataFieldCustomValue15 Usage_i16(0x552)
+#define Usage_Sen_DataFieldCustomValue16 Usage_i16(0x553)
+#define Usage_Sen_DataFieldCustomValue17 Usage_i16(0x554)
+#define Usage_Sen_DataFieldCustomValue18 Usage_i16(0x555)
+#define Usage_Sen_DataFieldCustomValue19 Usage_i16(0x556)
+#define Usage_Sen_DataFieldCustomValue20 Usage_i16(0x557)
+#define Usage_Sen_DataFieldCustomValue21 Usage_i16(0x558)
+#define Usage_Sen_DataFieldCustomValue22 Usage_i16(0x559)
+#define Usage_Sen_DataFieldCustomValue23 Usage_i16(0x55a)
+#define Usage_Sen_DataFieldCustomValue24 Usage_i16(0x55b)
+#define Usage_Sen_DataFieldCustomValue25 Usage_i16(0x55c)
+#define Usage_Sen_DataFieldCustomValue26 Usage_i16(0x55d)
+#define Usage_Sen_DataFieldCustomValue27 Usage_i16(0x55e)
+#define Usage_Sen_DataFieldCustomValue28 Usage_i16(0x55f)
+#define Usage_Sen_DataFieldGeneric Usage_i16(0x560)
+#define Usage_Sen_DataFieldGenericGUIDorPROPERTYKEY Usage_i16(0x561)
+#define Usage_Sen_DataFieldGenericCategoryGUID Usage_i16(0x562)
+#define Usage_Sen_DataFieldGenericTypeGUID Usage_i16(0x563)
+#define Usage_Sen_DataFieldGenericEventPROPERTYKEY Usage_i16(0x564)
+#define Usage_Sen_DataFieldGenericPropertyPROPERTYKEY Usage_i16(0x565)
+#define Usage_Sen_DataFieldGenericDataFieldPROPERTYKEY Usage_i16(0x566)
+#define Usage_Sen_DataFieldGenericEvent Usage_i16(0x567)
+#define Usage_Sen_DataFieldGenericProperty Usage_i16(0x568)
+#define Usage_Sen_DataFieldGenericDataField Usage_i16(0x569)
+#define Usage_Sen_DataFieldEnumeratorTableRowIndex Usage_i16(0x56a)
+#define Usage_Sen_DataFieldEnumeratorTableRowCount Usage_i16(0x56b)
+#define Usage_Sen_DataFieldGenericGUIDorPROPERTYKEYkind Usage_i16(0x56c)
+#define Usage_Sen_DataFieldGenericGUID Usage_i16(0x56d)
+#define Usage_Sen_DataFieldGenericPROPERTYKEY Usage_i16(0x56e)
+#define Usage_Sen_DataFieldGenericTopLevelCollectionID Usage_i16(0x56f)
+#define Usage_Sen_DataFieldGenericReportID Usage_i16(0x570)
+#define Usage_Sen_DataFieldGenericReportItemPositionIndex Usage_i16(0x571)
+#define Usage_Sen_DataFieldGenericFirmwareVARTYPE Usage_i16(0x572)
+#define Usage_Sen_DataFieldGenericUnitofMeasure Usage_i16(0x573)
+#define Usage_Sen_DataFieldGenericUnitExponent Usage_i16(0x574)
+#define Usage_Sen_DataFieldGenericReportSize Usage_i16(0x575)
+#define Usage_Sen_DataFieldGenericReportCount Usage_i16(0x576)
+#define Usage_Sen_PropertyGeneric Usage_i16(0x580)
+#define Usage_Sen_PropertyEnumeratorTableRowIndex Usage_i16(0x581)
+#define Usage_Sen_PropertyEnumeratorTableRowCount Usage_i16(0x582)
+#define Usage_Sen_DataFieldPersonalActivity Usage_i16(0x590)
+#define Usage_Sen_DataFieldActivityType Usage_i16(0x591)
+#define Usage_Sen_DataFieldActivityState Usage_i16(0x592)
+#define Usage_Sen_DataFieldDevicePosition Usage_i16(0x593)
+#define Usage_Sen_DataFieldStepCount Usage_i16(0x594)
+#define Usage_Sen_DataFieldStepCountReset Usage_i16(0x595)
+#define Usage_Sen_DataFieldStepDuration Usage_i16(0x596)
+#define Usage_Sen_DataFieldStepType Usage_i16(0x597)
+#define Usage_Sen_PropertyMinimumActivityDetectionInterval Usage_i16(0x5a0)
+#define Usage_Sen_PropertySupportedActivityTypes Usage_i16(0x5a1)
+#define Usage_Sen_PropertySubscribedActivityTypes Usage_i16(0x5a2)
+#define Usage_Sen_PropertySupportedStepTypes Usage_i16(0x5a3)
+#define Usage_Sen_PropertySubscribedStepTypes Usage_i16(0x5a4)
+#define Usage_Sen_PropertyFloorHeight Usage_i16(0x5a5)
+#define Usage_Sen_DataFieldCustomTypeID Usage_i16(0x5b0)
+#define Usage_Sen_PropertyCustom Usage_i16(0x5c0)
+#define Usage_Sen_PropertyCustomValue1 Usage_i16(0x5c1)
+#define Usage_Sen_PropertyCustomValue2 Usage_i16(0x5c2)
+#define Usage_Sen_PropertyCustomValue3 Usage_i16(0x5c3)
+#define Usage_Sen_PropertyCustomValue4 Usage_i16(0x5c4)
+#define Usage_Sen_PropertyCustomValue5 Usage_i16(0x5c5)
+#define Usage_Sen_PropertyCustomValue6 Usage_i16(0x5c6)
+#define Usage_Sen_PropertyCustomValue7 Usage_i16(0x5c7)
+#define Usage_Sen_PropertyCustomValue8 Usage_i16(0x5c8)
+#define Usage_Sen_PropertyCustomValue9 Usage_i16(0x5c9)
+#define Usage_Sen_PropertyCustomValue10 Usage_i16(0x5ca)
+#define Usage_Sen_PropertyCustomValue11 Usage_i16(0x5cb)
+#define Usage_Sen_PropertyCustomValue12 Usage_i16(0x5cc)
+#define Usage_Sen_PropertyCustomValue13 Usage_i16(0x5cd)
+#define Usage_Sen_PropertyCustomValue14 Usage_i16(0x5ce)
+#define Usage_Sen_PropertyCustomValue15 Usage_i16(0x5cf)
+#define Usage_Sen_PropertyCustomValue16 Usage_i16(0x5d0)
+#define Usage_Sen_DataFieldHinge Usage_i16(0x5e0)
+#define Usage_Sen_DataFieldHingeAngle Usage_i16(0x5e1)
+#define Usage_Sen_DataFieldGestureSensor Usage_i16(0x5f0)
+#define Usage_Sen_DataFieldGestureState Usage_i16(0x5f1)
+#define Usage_Sen_DataFieldHingeFoldInitialAngle Usage_i16(0x5f2)
+#define Usage_Sen_DataFieldHingeFoldFinalAngle Usage_i16(0x5f3)
+#define Usage_Sen_DataFieldHingeFoldContributingPanel Usage_i16(0x5f4)
+#define Usage_Sen_DataFieldHingeFoldType Usage_i16(0x5f5)
+#define Usage_Sen_SensorStateUndefined Usage_i16(0x800)
+#define Usage_Sen_SensorStateReady Usage_i16(0x801)
+#define Usage_Sen_SensorStateNotAvailable Usage_i16(0x802)
+#define Usage_Sen_SensorStateNoData Usage_i16(0x803)
+#define Usage_Sen_SensorStateInitializing Usage_i16(0x804)
+#define Usage_Sen_SensorStateAccessDenied Usage_i16(0x805)
+#define Usage_Sen_SensorStateError Usage_i16(0x806)
+#define Usage_Sen_SensorEventUnknown Usage_i16(0x810)
+#define Usage_Sen_SensorEventStateChanged Usage_i16(0x811)
+#define Usage_Sen_SensorEventPropertyChanged Usage_i16(0x812)
+#define Usage_Sen_SensorEventDataUpdated Usage_i16(0x813)
+#define Usage_Sen_SensorEventPollResponse Usage_i16(0x814)
+#define Usage_Sen_SensorEventChangeSensitivity Usage_i16(0x815)
+#define Usage_Sen_SensorEventRangeMaximumReached Usage_i16(0x816)
+#define Usage_Sen_SensorEventRangeMinimumReached Usage_i16(0x817)
+#define Usage_Sen_SensorEventHighThresholdCrossUpward Usage_i16(0x818)
+#define Usage_Sen_SensorEventHighThresholdCrossDownward Usage_i16(0x819)
+#define Usage_Sen_SensorEventLowThresholdCrossUpward Usage_i16(0x81a)
+#define Usage_Sen_SensorEventLowThresholdCrossDownward Usage_i16(0x81b)
+#define Usage_Sen_SensorEventZeroThresholdCrossUpward Usage_i16(0x81c)
+#define Usage_Sen_SensorEventZeroThresholdCrossDownward Usage_i16(0x81d)
+#define Usage_Sen_SensorEventPeriodExceeded Usage_i16(0x81e)
+#define Usage_Sen_SensorEventFrequencyExceeded Usage_i16(0x81f)
+#define Usage_Sen_SensorEventComplexTrigger Usage_i16(0x820)
+#define Usage_Sen_ConnectionTypePCIntegrated Usage_i16(0x830)
+#define Usage_Sen_ConnectionTypePCAttached Usage_i16(0x831)
+#define Usage_Sen_ConnectionTypePCExternal Usage_i16(0x832)
+#define Usage_Sen_ReportingStateReportNoEvents Usage_i16(0x840)
+#define Usage_Sen_ReportingStateReportAllEvents Usage_i16(0x841)
+#define Usage_Sen_ReportingStateReportThresholdEvents Usage_i16(0x842)
+#define Usage_Sen_ReportingStateWakeOnNoEvents Usage_i16(0x843)
+#define Usage_Sen_ReportingStateWakeOnAllEvents Usage_i16(0x844)
+#define Usage_Sen_ReportingStateWakeOnThresholdEvents Usage_i16(0x845)
+#define Usage_Sen_ReportingStateAnytime Usage_i16(0x846)
+#define Usage_Sen_PowerStateUndefined Usage_i16(0x850)
+#define Usage_Sen_PowerStateD0FullPower Usage_i16(0x851)
+#define Usage_Sen_PowerStateD1LowPower Usage_i16(0x852)
+#define Usage_Sen_PowerStateD2StandbyPowerwithWakeup Usage_i16(0x853)
+#define Usage_Sen_PowerStateD3SleepwithWakeup Usage_i16(0x854)
+#define Usage_Sen_PowerStateD4PowerOff Usage_i16(0x855)
+#define Usage_Sen_AccuracyDefault Usage_i16(0x860)
+#define Usage_Sen_AccuracyHigh Usage_i16(0x861)
+#define Usage_Sen_AccuracyMedium Usage_i16(0x862)
+#define Usage_Sen_AccuracyLow Usage_i16(0x863)
+#define Usage_Sen_FixQualityNoFix Usage_i16(0x870)
+#define Usage_Sen_FixQualityGPS Usage_i16(0x871)
+#define Usage_Sen_FixQualityDGPS Usage_i16(0x872)
+#define Usage_Sen_FixTypeNoFix Usage_i16(0x880)
+#define Usage_Sen_FixTypeGPSSPSModeFixValid Usage_i16(0x881)
+#define Usage_Sen_FixTypeDGPSSPSModeFixValid Usage_i16(0x882)
+#define Usage_Sen_FixTypeGPSPPSModeFixValid Usage_i16(0x883)
+#define Usage_Sen_FixTypeRealTimeKinematic Usage_i16(0x884)
+#define Usage_Sen_FixTypeFloatRTK Usage_i16(0x885)
+#define Usage_Sen_FixTypeEstimateddeadreckoned Usage_i16(0x886)
+#define Usage_Sen_FixTypeManualInputMode Usage_i16(0x887)
+#define Usage_Sen_FixTypeSimulatorMode Usage_i16(0x888)
+#define Usage_Sen_GPSOperationModeManual Usage_i16(0x890)
+#define Usage_Sen_GPSOperationModeAutomatic Usage_i16(0x891)
+#define Usage_Sen_GPSSelectionModeAutonomous Usage_i16(0x8a0)
+#define Usage_Sen_GPSSelectionModeDGPS Usage_i16(0x8a1)
+#define Usage_Sen_GPSSelectionModeEstimateddeadreckoned Usage_i16(0x8a2)
+#define Usage_Sen_GPSSelectionModeManualInput Usage_i16(0x8a3)
+#define Usage_Sen_GPSSelectionModeSimulator Usage_i16(0x8a4)
+#define Usage_Sen_GPSSelectionModeDataNotValid Usage_i16(0x8a5)
+#define Usage_Sen_GPSStatusDataValid Usage_i16(0x8b0)
+#define Usage_Sen_GPSStatusDataNotValid Usage_i16(0x8b1)
+#define Usage_Sen_DayofWeekSunday Usage_i16(0x8c0)
+#define Usage_Sen_DayofWeekMonday Usage_i16(0x8c1)
+#define Usage_Sen_DayofWeekTuesday Usage_i16(0x8c2)
+#define Usage_Sen_DayofWeekWednesday Usage_i16(0x8c3)
+#define Usage_Sen_DayofWeekThursday Usage_i16(0x8c4)
+#define Usage_Sen_DayofWeekFriday Usage_i16(0x8c5)
+#define Usage_Sen_DayofWeekSaturday Usage_i16(0x8c6)
+#define Usage_Sen_KindCategory Usage_i16(0x8d0)
+#define Usage_Sen_KindType Usage_i16(0x8d1)
+#define Usage_Sen_KindEvent Usage_i16(0x8d2)
+#define Usage_Sen_KindProperty Usage_i16(0x8d3)
+#define Usage_Sen_KindDataField Usage_i16(0x8d4)
+#define Usage_Sen_MagnetometerAccuracyLow Usage_i16(0x8e0)
+#define Usage_Sen_MagnetometerAccuracyMedium Usage_i16(0x8e1)
+#define Usage_Sen_MagnetometerAccuracyHigh Usage_i16(0x8e2)
+#define Usage_Sen_SimpleOrientationDirectionNotRotated Usage_i16(0x8f0)
+#define Usage_Sen_SimpleOrientationDirectionRotated90DegreesCCW Usage_i16(0x8f1)
+#define Usage_Sen_SimpleOrientationDirectionRotated180DegreesCCW Usage_i16(0x8f2)
+#define Usage_Sen_SimpleOrientationDirectionRotated270DegreesCCW Usage_i16(0x8f3)
+#define Usage_Sen_SimpleOrientationDirectionFaceUp Usage_i16(0x8f4)
+#define Usage_Sen_SimpleOrientationDirectionFaceDown Usage_i16(0x8f5)
+#define Usage_Sen_VT_NULL Usage_i16(0x900)
+#define Usage_Sen_VT_BOOL Usage_i16(0x901)
+#define Usage_Sen_VT_UI1 Usage_i16(0x902)
+#define Usage_Sen_VT_I1 Usage_i16(0x903)
+#define Usage_Sen_VT_UI2 Usage_i16(0x904)
+#define Usage_Sen_VT_I2 Usage_i16(0x905)
+#define Usage_Sen_VT_UI4 Usage_i16(0x906)
+#define Usage_Sen_VT_I4 Usage_i16(0x907)
+#define Usage_Sen_VT_UI8 Usage_i16(0x908)
+#define Usage_Sen_VT_I8 Usage_i16(0x909)
+#define Usage_Sen_VT_R4 Usage_i16(0x90a)
+#define Usage_Sen_VT_R8 Usage_i16(0x90b)
+#define Usage_Sen_VT_WSTR Usage_i16(0x90c)
+#define Usage_Sen_VT_STR Usage_i16(0x90d)
+#define Usage_Sen_VT_CLSID Usage_i16(0x90e)
+#define Usage_Sen_VT_VECTORVT_UI1 Usage_i16(0x90f)
+#define Usage_Sen_VT_F16E0 Usage_i16(0x910)
+#define Usage_Sen_VT_F16E1 Usage_i16(0x911)
+#define Usage_Sen_VT_F16E2 Usage_i16(0x912)
+#define Usage_Sen_VT_F16E3 Usage_i16(0x913)
+#define Usage_Sen_VT_F16E4 Usage_i16(0x914)
+#define Usage_Sen_VT_F16E5 Usage_i16(0x915)
+#define Usage_Sen_VT_F16E6 Usage_i16(0x916)
+#define Usage_Sen_VT_F16E7 Usage_i16(0x917)
+#define Usage_Sen_VT_F16E8 Usage_i16(0x918)
+#define Usage_Sen_VT_F16E9 Usage_i16(0x919)
+#define Usage_Sen_VT_F16EA Usage_i16(0x91a)
+#define Usage_Sen_VT_F16EB Usage_i16(0x91b)
+#define Usage_Sen_VT_F16EC Usage_i16(0x91c)
+#define Usage_Sen_VT_F16ED Usage_i16(0x91d)
+#define Usage_Sen_VT_F16EE Usage_i16(0x91e)
+#define Usage_Sen_VT_F16EF Usage_i16(0x91f)
+#define Usage_Sen_VT_F32E0 Usage_i16(0x920)
+#define Usage_Sen_VT_F32E1 Usage_i16(0x921)
+#define Usage_Sen_VT_F32E2 Usage_i16(0x922)
+#define Usage_Sen_VT_F32E3 Usage_i16(0x923)
+#define Usage_Sen_VT_F32E4 Usage_i16(0x924)
+#define Usage_Sen_VT_F32E5 Usage_i16(0x925)
+#define Usage_Sen_VT_F32E6 Usage_i16(0x926)
+#define Usage_Sen_VT_F32E7 Usage_i16(0x927)
+#define Usage_Sen_VT_F32E8 Usage_i16(0x928)
+#define Usage_Sen_VT_F32E9 Usage_i16(0x929)
+#define Usage_Sen_VT_F32EA Usage_i16(0x92a)
+#define Usage_Sen_VT_F32EB Usage_i16(0x92b)
+#define Usage_Sen_VT_F32EC Usage_i16(0x92c)
+#define Usage_Sen_VT_F32ED Usage_i16(0x92d)
+#define Usage_Sen_VT_F32EE Usage_i16(0x92e)
+#define Usage_Sen_VT_F32EF Usage_i16(0x92f)
+#define Usage_Sen_ActivityTypeUnknown Usage_i16(0x930)
+#define Usage_Sen_ActivityTypeStationary Usage_i16(0x931)
+#define Usage_Sen_ActivityTypeFidgeting Usage_i16(0x932)
+#define Usage_Sen_ActivityTypeWalking Usage_i16(0x933)
+#define Usage_Sen_ActivityTypeRunning Usage_i16(0x934)
+#define Usage_Sen_ActivityTypeInVehicle Usage_i16(0x935)
+#define Usage_Sen_ActivityTypeBiking Usage_i16(0x936)
+#define Usage_Sen_ActivityTypeIdle Usage_i16(0x937)
+#define Usage_Sen_UnitNotSpecified Usage_i16(0x940)
+#define Usage_Sen_UnitLux Usage_i16(0x941)
+#define Usage_Sen_UnitDegreesKelvin Usage_i16(0x942)
+#define Usage_Sen_UnitDegreesCelsius Usage_i16(0x943)
+#define Usage_Sen_UnitPascal Usage_i16(0x944)
+#define Usage_Sen_UnitNewton Usage_i16(0x945)
+#define Usage_Sen_UnitMetersSecond Usage_i16(0x946)
+#define Usage_Sen_UnitKilogram Usage_i16(0x947)
+#define Usage_Sen_UnitMeter Usage_i16(0x948)
+#define Usage_Sen_UnitMetersSecondSecond Usage_i16(0x949)
+#define Usage_Sen_UnitFarad Usage_i16(0x94a)
+#define Usage_Sen_UnitAmpere Usage_i16(0x94b)
+#define Usage_Sen_UnitWatt Usage_i16(0x94c)
+#define Usage_Sen_UnitHenry Usage_i16(0x94d)
+#define Usage_Sen_UnitOhm Usage_i16(0x94e)
+#define Usage_Sen_UnitVolt Usage_i16(0x94f)
+#define Usage_Sen_UnitHertz Usage_i16(0x950)
+#define Usage_Sen_UnitBar Usage_i16(0x951)
+#define Usage_Sen_UnitDegreesAnticlockwise Usage_i16(0x952)
+#define Usage_Sen_UnitDegreesClockwise Usage_i16(0x953)
+#define Usage_Sen_UnitDegrees Usage_i16(0x954)
+#define Usage_Sen_UnitDegreesSecond Usage_i16(0x955)
+#define Usage_Sen_UnitDegreesSecondSecond Usage_i16(0x956)
+#define Usage_Sen_UnitKnot Usage_i16(0x957)
+#define Usage_Sen_UnitPercent Usage_i16(0x958)
+#define Usage_Sen_UnitSecond Usage_i16(0x959)
+#define Usage_Sen_UnitMillisecond Usage_i16(0x95a)
+#define Usage_Sen_UnitG Usage_i16(0x95b)
+#define Usage_Sen_UnitBytes Usage_i16(0x95c)
+#define Usage_Sen_UnitMilligauss Usage_i16(0x95d)
+#define Usage_Sen_UnitBits Usage_i16(0x95e)
+#define Usage_Sen_ActivityStateNoStateChange Usage_i16(0x960)
+#define Usage_Sen_ActivityStateStartActivity Usage_i16(0x961)
+#define Usage_Sen_ActivityStateEndActivity Usage_i16(0x962)
+#define Usage_Sen_Exponent0 Usage_i16(0x970)
+#define Usage_Sen_Exponent1 Usage_i16(0x971)
+#define Usage_Sen_Exponent2 Usage_i16(0x972)
+#define Usage_Sen_Exponent3 Usage_i16(0x973)
+#define Usage_Sen_Exponent4 Usage_i16(0x974)
+#define Usage_Sen_Exponent5 Usage_i16(0x975)
+#define Usage_Sen_Exponent6 Usage_i16(0x976)
+#define Usage_Sen_Exponent7 Usage_i16(0x977)
+#define Usage_Sen_Exponent8 Usage_i16(0x978)
+#define Usage_Sen_Exponent9 Usage_i16(0x979)
+#define Usage_Sen_ExponentA Usage_i16(0x97a)
+#define Usage_Sen_ExponentB Usage_i16(0x97b)
+#define Usage_Sen_ExponentC Usage_i16(0x97c)
+#define Usage_Sen_ExponentD Usage_i16(0x97d)
+#define Usage_Sen_ExponentE Usage_i16(0x97e)
+#define Usage_Sen_ExponentF Usage_i16(0x97f)
+#define Usage_Sen_DevicePositionUnknown Usage_i16(0x980)
+#define Usage_Sen_DevicePositionUnchanged Usage_i16(0x981)
+#define Usage_Sen_DevicePositionOnDesk Usage_i16(0x982)
+#define Usage_Sen_DevicePositionInHand Usage_i16(0x983)
+#define Usage_Sen_DevicePositionMovinginBag Usage_i16(0x984)
+#define Usage_Sen_DevicePositionStationaryinBag Usage_i16(0x985)
+#define Usage_Sen_StepTypeUnknown Usage_i16(0x990)
+#define Usage_Sen_StepTypeWalking Usage_i16(0x991)
+#define Usage_Sen_StepTypeRunning Usage_i16(0x992)
+#define Usage_Sen_GestureStateUnknown Usage_i16(0x9a0)
+#define Usage_Sen_GestureStateStarted Usage_i16(0x9a1)
+#define Usage_Sen_GestureStateCompleted Usage_i16(0x9a2)
+#define Usage_Sen_GestureStateCancelled Usage_i16(0x9a3)
+#define Usage_Sen_HingeFoldContributingPanelUnknown Usage_i16(0x9b0)
+#define Usage_Sen_HingeFoldContributingPanelPanel1 Usage_i16(0x9b1)
+#define Usage_Sen_HingeFoldContributingPanelPanel2 Usage_i16(0x9b2)
+#define Usage_Sen_HingeFoldContributingPanelBoth Usage_i16(0x9b3)
+#define Usage_Sen_HingeFoldTypeUnknown Usage_i16(0x9b4)
+#define Usage_Sen_HingeFoldTypeIncreasing Usage_i16(0x9b5)
+#define Usage_Sen_HingeFoldTypeDecreasing Usage_i16(0x9b6)
+#define Usage_Sen_HumanPresenceDetectionTypeVendorDefinedNonBiometric Usage_i16(0x9c0)
+#define Usage_Sen_HumanPresenceDetectionTypeVendorDefinedBiometric Usage_i16(0x9c1)
+#define Usage_Sen_HumanPresenceDetectionTypeFacialBiometric Usage_i16(0x9c2)
+#define Usage_Sen_HumanPresenceDetectionTypeAudioBiometric Usage_i16(0x9c3)
+#define Usage_Sen_ModifierChangeSensitivityAbsolute Usage_i16(0x1000)
+#define Usage_Sen_ModifierMaximum Usage_i16(0x2000)
+#define Usage_Sen_ModifierMinimum Usage_i16(0x3000)
+#define Usage_Sen_ModifierAccuracy Usage_i16(0x4000)
+#define Usage_Sen_ModifierResolution Usage_i16(0x5000)
+#define Usage_Sen_ModifierThresholdHigh Usage_i16(0x6000)
+#define Usage_Sen_ModifierThresholdLow Usage_i16(0x7000)
+#define Usage_Sen_ModifierCalibrationOffset Usage_i16(0x8000)
+#define Usage_Sen_ModifierCalibrationMultiplier Usage_i16(0x9000)
+#define Usage_Sen_ModifierReportInterval Usage_i16(0xa000)
+#define Usage_Sen_ModifierFrequencyMax Usage_i16(0xb000)
+#define Usage_Sen_ModifierPeriodMax Usage_i16(0xc000)
+#define Usage_Sen_ModifierChangeSensitivityPercentofRange Usage_i16(0xd000)
+#define Usage_Sen_ModifierChangeSensitivityPercentRelative Usage_i16(0xe000)
+#define Usage_Sen_ModifierVendorReserved Usage_i16(0xf000)
+#define Usage_MI_MedicalUltrasound Usage_i8(0x1)
+#define Usage_MI_VCRAcquisition Usage_i8(0x20)
+#define Usage_MI_FreezeThaw Usage_i8(0x21)
+#define Usage_MI_ClipStore Usage_i8(0x22)
+#define Usage_MI_Update Usage_i8(0x23)
+#define Usage_MI_Next Usage_i8(0x24)
+#define Usage_MI_Save Usage_i8(0x25)
+#define Usage_MI_Print Usage_i8(0x26)
+#define Usage_MI_MicrophoneEnable Usage_i8(0x27)
+#define Usage_MI_Cine Usage_i8(0x40)
+#define Usage_MI_TransmitPower Usage_i8(0x41)
+#define Usage_MI_Volume Usage_i8(0x42)
+#define Usage_MI_Focus Usage_i8(0x43)
+#define Usage_MI_Depth Usage_i8(0x44)
+#define Usage_MI_SoftStepPrimary Usage_i8(0x60)
+#define Usage_MI_SoftStepSecondary Usage_i8(0x61)
+#define Usage_MI_DepthGainCompensation Usage_i8(0x70)
+#define Usage_MI_ZoomSelect Usage_i8(0x80)
+#define Usage_MI_ZoomAdjust Usage_i8(0x81)
+#define Usage_MI_SpectralDopplerModeSelect Usage_i8(0x82)
+#define Usage_MI_SpectralDopplerAdjust Usage_i8(0x83)
+#define Usage_MI_ColorDopplerModeSelect Usage_i8(0x84)
+#define Usage_MI_ColorDopplerAdjust Usage_i8(0x85)
+#define Usage_MI_MotionModeSelect Usage_i8(0x86)
+#define Usage_MI_MotionModeAdjust Usage_i8(0x87)
+#define Usage_MI_TwoDModeSelect Usage_i8(0x88)
+#define Usage_MI_TwoDModeAdjust Usage_i8(0x89)
+#define Usage_MI_SoftControlSelect Usage_i8(0xa0)
+#define Usage_MI_SoftControlAdjust Usage_i8(0xa1)
+#define Usage_BD_BrailleDisplay Usage_i8(0x1)
+#define Usage_BD_BrailleRow Usage_i8(0x2)
+#define Usage_BD_EightDotBrailleCell Usage_i8(0x3)
+#define Usage_BD_SixDotBrailleCell Usage_i8(0x4)
+#define Usage_BD_NumberofBrailleCells Usage_i8(0x5)
+#define Usage_BD_ScreenReaderControl Usage_i8(0x6)
+#define Usage_BD_ScreenReaderIdentifier Usage_i8(0x7)
+#define Usage_BD_RouterSet1 Usage_i8(0xfa)
+#define Usage_BD_RouterSet2 Usage_i8(0xfb)
+#define Usage_BD_RouterSet3 Usage_i8(0xfc)
+#define Usage_BD_RouterKey Usage_i16(0x100)
+#define Usage_BD_RowRouterKey Usage_i16(0x101)
+#define Usage_BD_BrailleButtons Usage_i16(0x200)
+#define Usage_BD_BrailleKeyboardDot1 Usage_i16(0x201)
+#define Usage_BD_BrailleKeyboardDot2 Usage_i16(0x202)
+#define Usage_BD_BrailleKeyboardDot3 Usage_i16(0x203)
+#define Usage_BD_BrailleKeyboardDot4 Usage_i16(0x204)
+#define Usage_BD_BrailleKeyboardDot5 Usage_i16(0x205)
+#define Usage_BD_BrailleKeyboardDot6 Usage_i16(0x206)
+#define Usage_BD_BrailleKeyboardDot7 Usage_i16(0x207)
+#define Usage_BD_BrailleKeyboardDot8 Usage_i16(0x208)
+#define Usage_BD_BrailleKeyboardSpace Usage_i16(0x209)
+#define Usage_BD_BrailleKeyboardLeftSpace Usage_i16(0x20a)
+#define Usage_BD_BrailleKeyboardRightSpace Usage_i16(0x20b)
+#define Usage_BD_BrailleFaceControls Usage_i16(0x20c)
+#define Usage_BD_BrailleLeftControls Usage_i16(0x20d)
+#define Usage_BD_BrailleRightControls Usage_i16(0x20e)
+#define Usage_BD_BrailleTopControls Usage_i16(0x20f)
+#define Usage_BD_BrailleJoystickCenter Usage_i16(0x210)
+#define Usage_BD_BrailleJoystickUp Usage_i16(0x211)
+#define Usage_BD_BrailleJoystickDown Usage_i16(0x212)
+#define Usage_BD_BrailleJoystickLeft Usage_i16(0x213)
+#define Usage_BD_BrailleJoystickRight Usage_i16(0x214)
+#define Usage_BD_BrailleDPadCenter Usage_i16(0x215)
+#define Usage_BD_BrailleDPadUp Usage_i16(0x216)
+#define Usage_BD_BrailleDPadDown Usage_i16(0x217)
+#define Usage_BD_BrailleDPadLeft Usage_i16(0x218)
+#define Usage_BD_BrailleDPadRight Usage_i16(0x219)
+#define Usage_BD_BraillePanLeft Usage_i16(0x21a)
+#define Usage_BD_BraillePanRight Usage_i16(0x21b)
+#define Usage_BD_BrailleRockerUp Usage_i16(0x21c)
+#define Usage_BD_BrailleRockerDown Usage_i16(0x21d)
+#define Usage_BD_BrailleRockerPress Usage_i16(0x21e)
+#define Usage_LAI_LampArray Usage_i8(0x1)
+#define Usage_LAI_LampArrayAttributesReport Usage_i8(0x2)
+#define Usage_LAI_LampCount Usage_i8(0x3)
+#define Usage_LAI_BoundingBoxWidthInMicrometers Usage_i8(0x4)
+#define Usage_LAI_BoundingBoxHeightInMicrometers Usage_i8(0x5)
+#define Usage_LAI_BoundingBoxDepthInMicrometers Usage_i8(0x6)
+#define Usage_LAI_LampArrayKind Usage_i8(0x7)
+#define Usage_LAI_MinUpdateIntervalInMicroseconds Usage_i8(0x8)
+#define Usage_LAI_LampAttributesRequestReport Usage_i8(0x20)
+#define Usage_LAI_LampId Usage_i8(0x21)
+#define Usage_LAI_LampAttributesResponseReport Usage_i8(0x22)
+#define Usage_LAI_PositionXInMicrometers Usage_i8(0x23)
+#define Usage_LAI_PositionYInMicrometers Usage_i8(0x24)
+#define Usage_LAI_PositionZInMicrometers Usage_i8(0x25)
+#define Usage_LAI_LampPurposes Usage_i8(0x26)
+#define Usage_LAI_UpdateLatencyInMicroseconds Usage_i8(0x27)
+#define Usage_LAI_RedLevelCount Usage_i8(0x28)
+#define Usage_LAI_GreenLevelCount Usage_i8(0x29)
+#define Usage_LAI_BlueLevelCount Usage_i8(0x2a)
+#define Usage_LAI_IntensityLevelCount Usage_i8(0x2b)
+#define Usage_LAI_IsProgrammable Usage_i8(0x2c)
+#define Usage_LAI_InputBinding Usage_i8(0x2d)
+#define Usage_LAI_LampMultiUpdateReport Usage_i8(0x50)
+#define Usage_LAI_RedUpdateChannel Usage_i8(0x51)
+#define Usage_LAI_GreenUpdateChannel Usage_i8(0x52)
+#define Usage_LAI_BlueUpdateChannel Usage_i8(0x53)
+#define Usage_LAI_IntensityUpdateChannel Usage_i8(0x54)
+#define Usage_LAI_LampUpdateFlags Usage_i8(0x55)
+#define Usage_LAI_LampRangeUpdateReport Usage_i8(0x60)
+#define Usage_LAI_LampIdStart Usage_i8(0x61)
+#define Usage_LAI_LampIdEnd Usage_i8(0x62)
+#define Usage_LAI_LampArrayControlReport Usage_i8(0x70)
+#define Usage_LAI_AutonomousMode Usage_i8(0x71)
+#define Usage_Mon_MonitorControl Usage_i8(0x1)
+#define Usage_Mon_EDIDInformation Usage_i8(0x2)
+#define Usage_Mon_VDIFInformation Usage_i8(0x3)
+#define Usage_Mon_VESAVersion Usage_i8(0x4)
+#define Usage_VESAVC_Degauss Usage_i8(0x1)
+#define Usage_VESAVC_Brightness Usage_i8(0x10)
+#define Usage_VESAVC_Contrast Usage_i8(0x12)
+#define Usage_VESAVC_RedVideoGain Usage_i8(0x16)
+#define Usage_VESAVC_GreenVideoGain Usage_i8(0x18)
+#define Usage_VESAVC_BlueVideoGain Usage_i8(0x1a)
+#define Usage_VESAVC_Focus Usage_i8(0x1c)
+#define Usage_VESAVC_HorizontalPosition Usage_i8(0x20)
+#define Usage_VESAVC_HorizontalSize Usage_i8(0x22)
+#define Usage_VESAVC_HorizontalPincushion Usage_i8(0x24)
+#define Usage_VESAVC_HorizontalPincushionBalance Usage_i8(0x26)
+#define Usage_VESAVC_HorizontalMisconvergence Usage_i8(0x28)
+#define Usage_VESAVC_HorizontalLinearity Usage_i8(0x2a)
+#define Usage_VESAVC_HorizontalLinearityBalance Usage_i8(0x2c)
+#define Usage_VESAVC_VerticalPosition Usage_i8(0x30)
+#define Usage_VESAVC_VerticalSize Usage_i8(0x32)
+#define Usage_VESAVC_VerticalPincushion Usage_i8(0x34)
+#define Usage_VESAVC_VerticalPincushionBalance Usage_i8(0x36)
+#define Usage_VESAVC_VerticalMisconvergence Usage_i8(0x38)
+#define Usage_VESAVC_VerticalLinearity Usage_i8(0x3a)
+#define Usage_VESAVC_VerticalLinearityBalance Usage_i8(0x3c)
+#define Usage_VESAVC_ParallelogramDistortionKeyBalance Usage_i8(0x40)
+#define Usage_VESAVC_TrapezoidalDistortionKey Usage_i8(0x42)
+#define Usage_VESAVC_TiltRotation Usage_i8(0x44)
+#define Usage_VESAVC_TopCornerDistortionControl Usage_i8(0x46)
+#define Usage_VESAVC_TopCornerDistortionBalance Usage_i8(0x48)
+#define Usage_VESAVC_BottomCornerDistortionControl Usage_i8(0x4a)
+#define Usage_VESAVC_BottomCornerDistortionBalance Usage_i8(0x4c)
+#define Usage_VESAVC_HorizontalMoiré Usage_i8(0x56)
+#define Usage_VESAVC_VerticalMoiré Usage_i8(0x58)
+#define Usage_VESAVC_InputLevelSelect Usage_i8(0x5e)
+#define Usage_VESAVC_InputSourceSelect Usage_i8(0x60)
+#define Usage_VESAVC_RedVideoBlackLevel Usage_i8(0x6c)
+#define Usage_VESAVC_GreenVideoBlackLevel Usage_i8(0x6e)
+#define Usage_VESAVC_BlueVideoBlackLevel Usage_i8(0x70)
+#define Usage_VESAVC_AutoSizeCenter Usage_i8(0xa2)
+#define Usage_VESAVC_PolarityHorizontalSynchronization Usage_i8(0xa4)
+#define Usage_VESAVC_PolarityVerticalSynchronization Usage_i8(0xa6)
+#define Usage_VESAVC_SynchronizationType Usage_i8(0xa8)
+#define Usage_VESAVC_ScreenOrientation Usage_i8(0xaa)
+#define Usage_VESAVC_HorizontalFrequency Usage_i8(0xac)
+#define Usage_VESAVC_VerticalFrequency Usage_i8(0xae)
+#define Usage_VESAVC_Settings Usage_i8(0xb0)
+#define Usage_VESAVC_OnScreenDisplay Usage_i8(0xca)
+#define Usage_VESAVC_StereoMode Usage_i8(0xd4)
+#define Usage_Pow_iName Usage_i8(0x1)
+#define Usage_Pow_PresentStatus Usage_i8(0x2)
+#define Usage_Pow_ChangedStatus Usage_i8(0x3)
+#define Usage_Pow_UPS Usage_i8(0x4)
+#define Usage_Pow_PowerSupply Usage_i8(0x5)
+#define Usage_Pow_BatterySystem Usage_i8(0x10)
+#define Usage_Pow_BatterySystemId Usage_i8(0x11)
+#define Usage_Pow_Battery Usage_i8(0x12)
+#define Usage_Pow_BatteryId Usage_i8(0x13)
+#define Usage_Pow_Charger Usage_i8(0x14)
+#define Usage_Pow_ChargerId Usage_i8(0x15)
+#define Usage_Pow_PowerConverter Usage_i8(0x16)
+#define Usage_Pow_PowerConverterId Usage_i8(0x17)
+#define Usage_Pow_OutletSystem Usage_i8(0x18)
+#define Usage_Pow_OutletSystemId Usage_i8(0x19)
+#define Usage_Pow_Input Usage_i8(0x1a)
+#define Usage_Pow_InputId Usage_i8(0x1b)
+#define Usage_Pow_Output Usage_i8(0x1c)
+#define Usage_Pow_OutputId Usage_i8(0x1d)
+#define Usage_Pow_Flow Usage_i8(0x1e)
+#define Usage_Pow_FlowId Usage_i8(0x1f)
+#define Usage_Pow_Outlet Usage_i8(0x20)
+#define Usage_Pow_OutletId Usage_i8(0x21)
+#define Usage_Pow_Gang Usage_i8(0x22)
+#define Usage_Pow_GangId Usage_i8(0x23)
+#define Usage_Pow_PowerSummary Usage_i8(0x24)
+#define Usage_Pow_PowerSummaryId Usage_i8(0x25)
+#define Usage_Pow_Voltage Usage_i8(0x30)
+#define Usage_Pow_Current Usage_i8(0x31)
+#define Usage_Pow_Frequency Usage_i8(0x32)
+#define Usage_Pow_ApparentPower Usage_i8(0x33)
+#define Usage_Pow_ActivePower Usage_i8(0x34)
+#define Usage_Pow_PercentLoad Usage_i8(0x35)
+#define Usage_Pow_Temperature Usage_i8(0x36)
+#define Usage_Pow_Humidity Usage_i8(0x37)
+#define Usage_Pow_BadCount Usage_i8(0x38)
+#define Usage_Pow_ConfigVoltage Usage_i8(0x40)
+#define Usage_Pow_ConfigCurrent Usage_i8(0x41)
+#define Usage_Pow_ConfigFrequency Usage_i8(0x42)
+#define Usage_Pow_ConfigApparentPower Usage_i8(0x43)
+#define Usage_Pow_ConfigActivePower Usage_i8(0x44)
+#define Usage_Pow_ConfigPercentLoad Usage_i8(0x45)
+#define Usage_Pow_ConfigTemperature Usage_i8(0x46)
+#define Usage_Pow_ConfigHumidity Usage_i8(0x47)
+#define Usage_Pow_SwitchOnControl Usage_i8(0x50)
+#define Usage_Pow_SwitchOffControl Usage_i8(0x51)
+#define Usage_Pow_ToggleControl Usage_i8(0x52)
+#define Usage_Pow_LowVoltageTransfer Usage_i8(0x53)
+#define Usage_Pow_HighVoltageTransfer Usage_i8(0x54)
+#define Usage_Pow_DelayBeforeReboot Usage_i8(0x55)
+#define Usage_Pow_DelayBeforeStartup Usage_i8(0x56)
+#define Usage_Pow_DelayBeforeShutdown Usage_i8(0x57)
+#define Usage_Pow_Test Usage_i8(0x58)
+#define Usage_Pow_ModuleReset Usage_i8(0x59)
+#define Usage_Pow_AudibleAlarmControl Usage_i8(0x5a)
+#define Usage_Pow_Present Usage_i8(0x60)
+#define Usage_Pow_Good Usage_i8(0x61)
+#define Usage_Pow_InternalFailure Usage_i8(0x62)
+#define Usage_Pow_VoltagOutOfRange Usage_i8(0x63)
+#define Usage_Pow_FrequencyOutOfRange Usage_i8(0x64)
+#define Usage_Pow_Overload Usage_i8(0x65)
+#define Usage_Pow_OverCharged Usage_i8(0x66)
+#define Usage_Pow_OverTemperature Usage_i8(0x67)
+#define Usage_Pow_ShutdownRequested Usage_i8(0x68)
+#define Usage_Pow_ShutdownImminent Usage_i8(0x69)
+#define Usage_Pow_SwitchOnOff Usage_i8(0x6b)
+#define Usage_Pow_Switchable Usage_i8(0x6c)
+#define Usage_Pow_Used Usage_i8(0x6d)
+#define Usage_Pow_Boost Usage_i8(0x6e)
+#define Usage_Pow_Buck Usage_i8(0x6f)
+#define Usage_Pow_Initialized Usage_i8(0x70)
+#define Usage_Pow_Tested Usage_i8(0x71)
+#define Usage_Pow_AwaitingPower Usage_i8(0x72)
+#define Usage_Pow_CommunicationLost Usage_i8(0x73)
+#define Usage_Pow_iManufacturer Usage_i8(0xfd)
+#define Usage_Pow_iProduct Usage_i8(0xfe)
+#define Usage_Pow_iSerialNumber Usage_i16(0xff)
+#define Usage_BS_SmartBatteryBatteryMode Usage_i8(0x1)
+#define Usage_BS_SmartBatteryBatteryStatus Usage_i8(0x2)
+#define Usage_BS_SmartBatteryAlarmWarning Usage_i8(0x3)
+#define Usage_BS_SmartBatteryChargerMode Usage_i8(0x4)
+#define Usage_BS_SmartBatteryChargerStatus Usage_i8(0x5)
+#define Usage_BS_SmartBatteryChargerSpecInfo Usage_i8(0x6)
+#define Usage_BS_SmartBatterySelectorState Usage_i8(0x7)
+#define Usage_BS_SmartBatterySelectorPresets Usage_i8(0x8)
+#define Usage_BS_SmartBatterySelectorInfo Usage_i8(0x9)
+#define Usage_BS_OptionalMfgFunction1 Usage_i8(0x10)
+#define Usage_BS_OptionalMfgFunction2 Usage_i8(0x11)
+#define Usage_BS_OptionalMfgFunction3 Usage_i8(0x12)
+#define Usage_BS_OptionalMfgFunction4 Usage_i8(0x13)
+#define Usage_BS_OptionalMfgFunction5 Usage_i8(0x14)
+#define Usage_BS_ConnectionToSMBus Usage_i8(0x15)
+#define Usage_BS_OutputConnection Usage_i8(0x16)
+#define Usage_BS_ChargerConnection Usage_i8(0x17)
+#define Usage_BS_BatteryInsertion Usage_i8(0x18)
+#define Usage_BS_UseNext Usage_i8(0x19)
+#define Usage_BS_OKToUse Usage_i8(0x1a)
+#define Usage_BS_BatterySupported Usage_i8(0x1b)
+#define Usage_BS_SelectorRevision Usage_i8(0x1c)
+#define Usage_BS_ChargingIndicator Usage_i8(0x1d)
+#define Usage_BS_ManufacturerAccess Usage_i8(0x28)
+#define Usage_BS_RemainingCapacityLimit Usage_i8(0x29)
+#define Usage_BS_RemainingTimeLimit Usage_i8(0x2a)
+#define Usage_BS_AtRate Usage_i8(0x2b)
+#define Usage_BS_CapacityMode Usage_i8(0x2c)
+#define Usage_BS_BroadcastToCharger Usage_i8(0x2d)
+#define Usage_BS_PrimaryBattery Usage_i8(0x2e)
+#define Usage_BS_ChargeController Usage_i8(0x2f)
+#define Usage_BS_TerminateCharge Usage_i8(0x40)
+#define Usage_BS_TerminateDischarge Usage_i8(0x41)
+#define Usage_BS_BelowRemainingCapacityLimit Usage_i8(0x42)
+#define Usage_BS_RemainingTimeLimitExpired Usage_i8(0x43)
+#define Usage_BS_Charging Usage_i8(0x44)
+#define Usage_BS_Discharging Usage_i8(0x45)
+#define Usage_BS_FullyCharged Usage_i8(0x46)
+#define Usage_BS_FullyDischarged Usage_i8(0x47)
+#define Usage_BS_ConditioningFlag Usage_i8(0x48)
+#define Usage_BS_AtRateOK Usage_i8(0x49)
+#define Usage_BS_SmartBatteryErrorCode Usage_i8(0x4a)
+#define Usage_BS_NeedReplacement Usage_i8(0x4b)
+#define Usage_BS_AtRateTimeToFull Usage_i8(0x60)
+#define Usage_BS_AtRateTimeToEmpty Usage_i8(0x61)
+#define Usage_BS_AverageCurrent Usage_i8(0x62)
+#define Usage_BS_MaxError Usage_i8(0x63)
+#define Usage_BS_RelativeStateOfCharge Usage_i8(0x64)
+#define Usage_BS_AbsoluteStateOfCharge Usage_i8(0x65)
+#define Usage_BS_RemainingCapacity Usage_i8(0x66)
+#define Usage_BS_FullChargeCapacity Usage_i8(0x67)
+#define Usage_BS_RunTimeToEmpty Usage_i8(0x68)
+#define Usage_BS_AverageTimeToEmpty Usage_i8(0x69)
+#define Usage_BS_AverageTimeToFull Usage_i8(0x6a)
+#define Usage_BS_CycleCount Usage_i8(0x6b)
+#define Usage_BS_BatteryPackModelLevel Usage_i8(0x80)
+#define Usage_BS_InternalChargeController Usage_i8(0x81)
+#define Usage_BS_PrimaryBatterySupport Usage_i8(0x82)
+#define Usage_BS_DesignCapacity Usage_i8(0x83)
+#define Usage_BS_SpecificationInfo Usage_i8(0x84)
+#define Usage_BS_ManufactureDate Usage_i8(0x85)
+#define Usage_BS_SerialNumber Usage_i8(0x86)
+#define Usage_BS_iManufacturerName Usage_i8(0x87)
+#define Usage_BS_iDeviceName Usage_i8(0x88)
+#define Usage_BS_iDeviceChemistry Usage_i8(0x89)
+#define Usage_BS_ManufacturerData Usage_i8(0x8a)
+#define Usage_BS_Rechargeable Usage_i8(0x8b)
+#define Usage_BS_WarningCapacityLimit Usage_i8(0x8c)
+#define Usage_BS_CapacityGranularity1 Usage_i8(0x8d)
+#define Usage_BS_CapacityGranularity2 Usage_i8(0x8e)
+#define Usage_BS_iOEMInformation Usage_i8(0x8f)
+#define Usage_BS_InhibitCharge Usage_i8(0xc0)
+#define Usage_BS_EnablePolling Usage_i8(0xc1)
+#define Usage_BS_ResetToZero Usage_i8(0xc2)
+#define Usage_BS_ACPresent Usage_i8(0xd0)
+#define Usage_BS_BatteryPresent Usage_i8(0xd1)
+#define Usage_BS_PowerFail Usage_i8(0xd2)
+#define Usage_BS_AlarmInhibited Usage_i8(0xd3)
+#define Usage_BS_ThermistorUnderRange Usage_i8(0xd4)
+#define Usage_BS_ThermistorHot Usage_i8(0xd5)
+#define Usage_BS_ThermistorCold Usage_i8(0xd6)
+#define Usage_BS_ThermistorOverRange Usage_i8(0xd7)
+#define Usage_BS_VoltageOutOfRange Usage_i8(0xd8)
+#define Usage_BS_CurrentOutOfRange Usage_i8(0xd9)
+#define Usage_BS_CurrentNotRegulated Usage_i8(0xda)
+#define Usage_BS_VoltageNotRegulated Usage_i8(0xdb)
+#define Usage_BS_MasterMode Usage_i8(0xdc)
+#define Usage_BS_ChargerSelectorSupport Usage_i8(0xf0)
+#define Usage_BS_ChargerSpec Usage_i8(0xf1)
+#define Usage_BS_Level2 Usage_i8(0xf2)
+#define Usage_BS_Level3 Usage_i8(0xf3)
+#define Usage_BS_BarcodeBadgeReader Usage_i8(0x1)
+#define Usage_BS_BarcodeScanner Usage_i8(0x2)
+#define Usage_BS_DumbBarCodeScanner Usage_i8(0x3)
+#define Usage_BS_CordlessScannerBase Usage_i8(0x4)
+#define Usage_BS_BarCodeScannerCradle Usage_i8(0x5)
+#define Usage_BS_AttributeReport Usage_i8(0x10)
+#define Usage_BS_SettingsReport Usage_i8(0x11)
+#define Usage_BS_ScannedDataReport Usage_i8(0x12)
+#define Usage_BS_RawScannedDataReport Usage_i8(0x13)
+#define Usage_BS_TriggerReport Usage_i8(0x14)
+#define Usage_BS_StatusReport Usage_i8(0x15)
+#define Usage_BS_UPCEANControlReport Usage_i8(0x16)
+#define Usage_BS_EAN23LabelControlReport Usage_i8(0x17)
+#define Usage_BS_Code39ControlReport Usage_i8(0x18)
+#define Usage_BS_Interleaved2of5ControlReport Usage_i8(0x19)
+#define Usage_BS_Standard2of5ControlReport Usage_i8(0x1a)
+#define Usage_BS_MSIPlesseyControlReport Usage_i8(0x1b)
+#define Usage_BS_CodabarControlReport Usage_i8(0x1c)
+#define Usage_BS_Code128ControlReport Usage_i8(0x1d)
+#define Usage_BS_Misc1DControlReport Usage_i8(0x1e)
+#define Usage_BS_TwoDControlReport Usage_i8(0x1f)
+#define Usage_BS_AimingPointerMode Usage_i8(0x30)
+#define Usage_BS_BarCodePresentSensor Usage_i8(0x31)
+#define Usage_BS_Class1ALaser Usage_i8(0x32)
+#define Usage_BS_Class2Laser Usage_i8(0x33)
+#define Usage_BS_HeaterPresent Usage_i8(0x34)
+#define Usage_BS_ContactScanner Usage_i8(0x35)
+#define Usage_BS_ElectronicArticleSurveillanceNotification Usage_i8(0x36)
+#define Usage_BS_ConstantElectronicArticleSurveillance Usage_i8(0x37)
+#define Usage_BS_ErrorIndication Usage_i8(0x38)
+#define Usage_BS_FixedBeeper Usage_i8(0x39)
+#define Usage_BS_GoodDecodeIndication Usage_i8(0x3a)
+#define Usage_BS_HandsFreeScanning Usage_i8(0x3b)
+#define Usage_BS_IntrinsicallySafe Usage_i8(0x3c)
+#define Usage_BS_KlasseEinsLaser Usage_i8(0x3d)
+#define Usage_BS_LongRangeScanner Usage_i8(0x3e)
+#define Usage_BS_MirrorSpeedControl Usage_i8(0x3f)
+#define Usage_BS_NotOnFileIndication Usage_i8(0x40)
+#define Usage_BS_ProgrammableBeeper Usage_i8(0x41)
+#define Usage_BS_Triggerless Usage_i8(0x42)
+#define Usage_BS_Wand Usage_i8(0x43)
+#define Usage_BS_WaterResistant Usage_i8(0x44)
+#define Usage_BS_MultiRangeScanner Usage_i8(0x45)
+#define Usage_BS_ProximitySensor Usage_i8(0x46)
+#define Usage_BS_FragmentDecoding Usage_i8(0x4d)
+#define Usage_BS_ScannerReadConfidence Usage_i8(0x4e)
+#define Usage_BS_DataPrefix Usage_i8(0x4f)
+#define Usage_BS_PrefixAIMI Usage_i8(0x50)
+#define Usage_BS_PrefixNone Usage_i8(0x51)
+#define Usage_BS_PrefixProprietary Usage_i8(0x52)
+#define Usage_BS_ActiveTime Usage_i8(0x55)
+#define Usage_BS_AimingLaserPattern Usage_i8(0x56)
+#define Usage_BS_BarCodePresent Usage_i8(0x57)
+#define Usage_BS_BeeperState Usage_i8(0x58)
+#define Usage_BS_LaserOnTime Usage_i8(0x59)
+#define Usage_BS_LaserState Usage_i8(0x5a)
+#define Usage_BS_LockoutTime Usage_i8(0x5b)
+#define Usage_BS_MotorState Usage_i8(0x5c)
+#define Usage_BS_MotorTimeout Usage_i8(0x5d)
+#define Usage_BS_PowerOnResetScanner Usage_i8(0x5e)
+#define Usage_BS_PreventReadofBarcodes Usage_i8(0x5f)
+#define Usage_BS_InitiateBarcodeRead Usage_i8(0x60)
+#define Usage_BS_TriggerState Usage_i8(0x61)
+#define Usage_BS_TriggerMode Usage_i8(0x62)
+#define Usage_BS_TriggerModeBlinkingLaserOn Usage_i8(0x63)
+#define Usage_BS_TriggerModeContinuousLaserOn Usage_i8(0x64)
+#define Usage_BS_TriggerModeLaseronwhilePulled Usage_i8(0x65)
+#define Usage_BS_TriggerModeLaserstaysonafterrelease Usage_i8(0x66)
+#define Usage_BS_CommitParameterstoNVM Usage_i8(0x6d)
+#define Usage_BS_ParameterScanning Usage_i8(0x6e)
+#define Usage_BS_ParametersChanged Usage_i8(0x6f)
+#define Usage_BS_Setparameterdefaultvalues Usage_i8(0x70)
+#define Usage_BS_ScannerInCradle Usage_i8(0x75)
+#define Usage_BS_ScannerInRange Usage_i8(0x76)
+#define Usage_BS_AimDuration Usage_i8(0x7a)
+#define Usage_BS_GoodReadLampDuration Usage_i8(0x7b)
+#define Usage_BS_GoodReadLampIntensity Usage_i8(0x7c)
+#define Usage_BS_GoodReadLED Usage_i8(0x7d)
+#define Usage_BS_GoodReadToneFrequency Usage_i8(0x7e)
+#define Usage_BS_GoodReadToneLength Usage_i8(0x7f)
+#define Usage_BS_GoodReadToneVolume Usage_i8(0x80)
+#define Usage_BS_NoReadMessage Usage_i8(0x82)
+#define Usage_BS_NotonFileVolume Usage_i8(0x83)
+#define Usage_BS_PowerupBeep Usage_i8(0x84)
+#define Usage_BS_SoundErrorBeep Usage_i8(0x85)
+#define Usage_BS_SoundGoodReadBeep Usage_i8(0x86)
+#define Usage_BS_SoundNotOnFileBeep Usage_i8(0x87)
+#define Usage_BS_GoodReadWhentoWrite Usage_i8(0x88)
+#define Usage_BS_GRWTIAfterDecode Usage_i8(0x89)
+#define Usage_BS_GRWTIBeepLampaftertransmit Usage_i8(0x8a)
+#define Usage_BS_GRWTINoBeepLampuseatall Usage_i8(0x8b)
+#define Usage_BS_BooklandEAN Usage_i8(0x91)
+#define Usage_BS_ConvertEAN8to13Type Usage_i8(0x92)
+#define Usage_BS_ConvertUPCAtoEAN13 Usage_i8(0x93)
+#define Usage_BS_ConvertUPCEtoA Usage_i8(0x94)
+#define Usage_BS_EAN13 Usage_i8(0x95)
+#define Usage_BS_EAN8 Usage_i8(0x96)
+#define Usage_BS_EAN99128Mandatory Usage_i8(0x97)
+#define Usage_BS_EAN99P5128Optional Usage_i8(0x98)
+#define Usage_BS_EnableEANTwoLabel Usage_i8(0x99)
+#define Usage_BS_UPCEAN Usage_i8(0x9a)
+#define Usage_BS_UPCEANCouponCode Usage_i8(0x9b)
+#define Usage_BS_UPCEANPeriodicals Usage_i8(0x9c)
+#define Usage_BS_UPCA Usage_i8(0x9d)
+#define Usage_BS_UPCAwith128Mandatory Usage_i8(0x9e)
+#define Usage_BS_UPCAwith128Optional Usage_i8(0x9f)
+#define Usage_BS_UPCAwithP5Optional Usage_i8(0xa0)
+#define Usage_BS_UPCE Usage_i8(0xa1)
+#define Usage_BS_UPCE1 Usage_i8(0xa2)
+#define Usage_BS_Periodical Usage_i8(0xa9)
+#define Usage_BS_PeriodicalAutoDiscriminatePlus2 Usage_i8(0xaa)
+#define Usage_BS_PeriodicalOnlyDecodewithPlus2 Usage_i8(0xab)
+#define Usage_BS_PeriodicalIgnorePlus2 Usage_i8(0xac)
+#define Usage_BS_PeriodicalAutoDiscriminatePlus5 Usage_i8(0xad)
+#define Usage_BS_PeriodicalOnlyDecodewithPlus5 Usage_i8(0xae)
+#define Usage_BS_PeriodicalIgnorePlus5 Usage_i8(0xaf)
+#define Usage_BS_Check Usage_i8(0xb0)
+#define Usage_BS_CheckDisablePrice Usage_i8(0xb1)
+#define Usage_BS_CheckEnable4digitPrice Usage_i8(0xb2)
+#define Usage_BS_CheckEnable5digitPrice Usage_i8(0xb3)
+#define Usage_BS_CheckEnableEuropean4digitPrice Usage_i8(0xb4)
+#define Usage_BS_CheckEnableEuropean5digitPrice Usage_i8(0xb5)
+#define Usage_BS_EANTwoLabel Usage_i8(0xb7)
+#define Usage_BS_EANThreeLabel Usage_i8(0xb8)
+#define Usage_BS_EAN8FlagDigit1 Usage_i8(0xb9)
+#define Usage_BS_EAN8FlagDigit2 Usage_i8(0xba)
+#define Usage_BS_EAN8FlagDigit3 Usage_i8(0xbb)
+#define Usage_BS_EAN13FlagDigit1 Usage_i8(0xbc)
+#define Usage_BS_EAN13FlagDigit2 Usage_i8(0xbd)
+#define Usage_BS_EAN13FlagDigit3 Usage_i8(0xbe)
+#define Usage_BS_AddEAN23LabelDefinition Usage_i8(0xbf)
+#define Usage_BS_ClearallEAN23LabelDefinitions Usage_i8(0xc0)
+#define Usage_BS_Codabar Usage_i8(0xc3)
+#define Usage_BS_Code128 Usage_i8(0xc4)
+#define Usage_BS_Code39 Usage_i8(0xc7)
+#define Usage_BS_Code93 Usage_i8(0xc8)
+#define Usage_BS_FullASCIIConversion Usage_i8(0xc9)
+#define Usage_BS_Interleaved2of5 Usage_i8(0xca)
+#define Usage_BS_ItalianPharmacyCode Usage_i8(0xcb)
+#define Usage_BS_MSIPlessey Usage_i8(0xcc)
+#define Usage_BS_Standard2of5IATA Usage_i8(0xcd)
+#define Usage_BS_Standard2of5 Usage_i8(0xce)
+#define Usage_BS_TransmitStartStop Usage_i8(0xd3)
+#define Usage_BS_TriOptic Usage_i8(0xd4)
+#define Usage_BS_UCCEAN128 Usage_i8(0xd5)
+#define Usage_BS_CheckDigit Usage_i8(0xd6)
+#define Usage_BS_CheckDigitDisable Usage_i8(0xd7)
+#define Usage_BS_CheckDigitEnableInterleaved2of5OPCC Usage_i8(0xd8)
+#define Usage_BS_CheckDigitEnableInterleaved2of5USS Usage_i8(0xd9)
+#define Usage_BS_CheckDigitEnableStandard2of5OPCC Usage_i8(0xda)
+#define Usage_BS_CheckDigitEnableStandard2of5USS Usage_i8(0xdb)
+#define Usage_BS_CheckDigitEnableOneMSIPlessey Usage_i8(0xdc)
+#define Usage_BS_CheckDigitEnableTwoMSIPlessey Usage_i8(0xdd)
+#define Usage_BS_CheckDigitCodabarEnable Usage_i8(0xde)
+#define Usage_BS_CheckDigitCode39Enable Usage_i8(0xdf)
+#define Usage_BS_TransmitCheckDigit Usage_i8(0xf0)
+#define Usage_BS_DisableCheckDigitTransmit Usage_i8(0xf1)
+#define Usage_BS_EnableCheckDigitTransmit Usage_i8(0xf2)
+#define Usage_BS_SymbologyIdentifier1 Usage_i8(0xfb)
+#define Usage_BS_SymbologyIdentifier2 Usage_i8(0xfc)
+#define Usage_BS_SymbologyIdentifier3 Usage_i8(0xfd)
+#define Usage_BS_DecodedData Usage_i8(0xfe)
+#define Usage_BS_DecodeDataContinued Usage_i16(0xff)
+#define Usage_BS_BarSpaceData Usage_i16(0x100)
+#define Usage_BS_ScannerDataAccuracy Usage_i16(0x101)
+#define Usage_BS_RawDataPolarity Usage_i16(0x102)
+#define Usage_BS_PolarityInvertedBarCode Usage_i16(0x103)
+#define Usage_BS_PolarityNormalBarCode Usage_i16(0x104)
+#define Usage_BS_MinimumLengthtoDecode Usage_i16(0x106)
+#define Usage_BS_MaximumLengthtoDecode Usage_i16(0x107)
+#define Usage_BS_DiscreteLengthtoDecode1 Usage_i16(0x108)
+#define Usage_BS_DiscreteLengthtoDecode2 Usage_i16(0x109)
+#define Usage_BS_DataLengthMethod Usage_i16(0x10a)
+#define Usage_BS_DLMethodReadany Usage_i16(0x10b)
+#define Usage_BS_DLMethodCheckinRange Usage_i16(0x10c)
+#define Usage_BS_DLMethodCheckforDiscrete Usage_i16(0x10d)
+#define Usage_BS_AztecCode Usage_i16(0x110)
+#define Usage_BS_BC412 Usage_i16(0x111)
+#define Usage_BS_ChannelCode Usage_i16(0x112)
+#define Usage_BS_Code16 Usage_i16(0x113)
+#define Usage_BS_Code32 Usage_i16(0x114)
+#define Usage_BS_Code49 Usage_i16(0x115)
+#define Usage_BS_CodeOne Usage_i16(0x116)
+#define Usage_BS_Colorcode Usage_i16(0x117)
+#define Usage_BS_DataMatrix Usage_i16(0x118)
+#define Usage_BS_MaxiCode Usage_i16(0x119)
+#define Usage_BS_MicroPDF Usage_i16(0x11a)
+#define Usage_BS_PDF417 Usage_i16(0x11b)
+#define Usage_BS_PosiCode Usage_i16(0x11c)
+#define Usage_BS_QRCode Usage_i16(0x11d)
+#define Usage_BS_SuperCode Usage_i16(0x11e)
+#define Usage_BS_UltraCode Usage_i16(0x11f)
+#define Usage_BS_USD5SlugCode Usage_i16(0x120)
+#define Usage_BS_VeriCode Usage_i16(0x121)
+#define Usage_Sca_Scales Usage_i8(0x1)
+#define Usage_Sca_ScaleDevice Usage_i8(0x20)
+#define Usage_Sca_ScaleClass Usage_i8(0x21)
+#define Usage_Sca_ScaleClassIMetric Usage_i8(0x22)
+#define Usage_Sca_ScaleClassIIMetric Usage_i8(0x23)
+#define Usage_Sca_ScaleClassIIIMetric Usage_i8(0x24)
+#define Usage_Sca_ScaleClassIIILMetric Usage_i8(0x25)
+#define Usage_Sca_ScaleClassIVMetric Usage_i8(0x26)
+#define Usage_Sca_ScaleClassIIIEnglish Usage_i8(0x27)
+#define Usage_Sca_ScaleClassIIILEnglish Usage_i8(0x28)
+#define Usage_Sca_ScaleClassIVEnglish Usage_i8(0x29)
+#define Usage_Sca_ScaleClassGeneric Usage_i8(0x2a)
+#define Usage_Sca_ScaleAttributeReport Usage_i8(0x30)
+#define Usage_Sca_ScaleControlReport Usage_i8(0x31)
+#define Usage_Sca_ScaleDataReport Usage_i8(0x32)
+#define Usage_Sca_ScaleStatusReport Usage_i8(0x33)
+#define Usage_Sca_ScaleWeightLimitReport Usage_i8(0x34)
+#define Usage_Sca_ScaleStatisticsReport Usage_i8(0x35)
+#define Usage_Sca_DataWeight Usage_i8(0x40)
+#define Usage_Sca_DataScaling Usage_i8(0x41)
+#define Usage_Sca_WeightUnit Usage_i8(0x50)
+#define Usage_Sca_WeightUnitMilligram Usage_i8(0x51)
+#define Usage_Sca_WeightUnitGram Usage_i8(0x52)
+#define Usage_Sca_WeightUnitKilogram Usage_i8(0x53)
+#define Usage_Sca_WeightUnitCarats Usage_i8(0x54)
+#define Usage_Sca_WeightUnitTaels Usage_i8(0x55)
+#define Usage_Sca_WeightUnitGrains Usage_i8(0x56)
+#define Usage_Sca_WeightUnitPennyweights Usage_i8(0x57)
+#define Usage_Sca_WeightUnitMetricTon Usage_i8(0x58)
+#define Usage_Sca_WeightUnitAvoirTon Usage_i8(0x59)
+#define Usage_Sca_WeightUnitTroyOunce Usage_i8(0x5a)
+#define Usage_Sca_WeightUnitOunce Usage_i8(0x5b)
+#define Usage_Sca_WeightUnitPound Usage_i8(0x5c)
+#define Usage_Sca_CalibrationCount Usage_i8(0x60)
+#define Usage_Sca_ReZeroCount Usage_i8(0x61)
+#define Usage_Sca_ScaleStatus Usage_i8(0x70)
+#define Usage_Sca_ScaleStatusFault Usage_i8(0x71)
+#define Usage_Sca_ScaleStatusStableatCenterofZero Usage_i8(0x72)
+#define Usage_Sca_ScaleStatusInMotion Usage_i8(0x73)
+#define Usage_Sca_ScaleStatusWeightStable Usage_i8(0x74)
+#define Usage_Sca_ScaleStatusUnderZero Usage_i8(0x75)
+#define Usage_Sca_ScaleStatusOverWeightLimit Usage_i8(0x76)
+#define Usage_Sca_ScaleStatusRequiresCalibration Usage_i8(0x77)
+#define Usage_Sca_ScaleStatusRequiresRezeroing Usage_i8(0x78)
+#define Usage_Sca_ZeroScale Usage_i8(0x80)
+#define Usage_Sca_EnforcedZeroReturn Usage_i8(0x81)
+#define Usage_MSR_MSRDeviceReadOnly Usage_i8(0x1)
+#define Usage_MSR_Track1Length Usage_i8(0x11)
+#define Usage_MSR_Track2Length Usage_i8(0x12)
+#define Usage_MSR_Track3Length Usage_i8(0x13)
+#define Usage_MSR_TrackJISLength Usage_i8(0x14)
+#define Usage_MSR_TrackData Usage_i8(0x20)
+#define Usage_MSR_Track1Data Usage_i8(0x21)
+#define Usage_MSR_Track2Data Usage_i8(0x22)
+#define Usage_MSR_Track3Data Usage_i8(0x23)
+#define Usage_MSR_TrackJISData Usage_i8(0x24)
+#define Usage_CC_CameraAutofocus Usage_i8(0x20)
+#define Usage_CC_CameraShutter Usage_i8(0x21)
+#define Usage_Arc_GeneralPurposeIOCard Usage_i8(0x1)
+#define Usage_Arc_CoinDoor Usage_i8(0x2)
+#define Usage_Arc_WatchdogTimer Usage_i8(0x3)
+#define Usage_Arc_GeneralPurposeAnalogInputState Usage_i8(0x30)
+#define Usage_Arc_GeneralPurposeDigitalInputState Usage_i8(0x31)
+#define Usage_Arc_GeneralPurposeOpticalInputState Usage_i8(0x32)
+#define Usage_Arc_GeneralPurposeDigitalOutputState Usage_i8(0x33)
+#define Usage_Arc_NumberofCoinDoors Usage_i8(0x34)
+#define Usage_Arc_CoinDrawerDropCount Usage_i8(0x35)
+#define Usage_Arc_CoinDrawerStart Usage_i8(0x36)
+#define Usage_Arc_CoinDrawerService Usage_i8(0x37)
+#define Usage_Arc_CoinDrawerTilt Usage_i8(0x38)
+#define Usage_Arc_CoinDoorTest Usage_i8(0x39)
+#define Usage_Arc_CoinDoorLockout Usage_i8(0x40)
+#define Usage_Arc_WatchdogTimeout Usage_i8(0x41)
+#define Usage_Arc_WatchdogAction Usage_i8(0x42)
+#define Usage_Arc_WatchdogReboot Usage_i8(0x43)
+#define Usage_Arc_WatchdogRestart Usage_i8(0x44)
+#define Usage_Arc_AlarmInput Usage_i8(0x45)
+#define Usage_Arc_CoinDoorCounter Usage_i8(0x46)
+#define Usage_Arc_IODirectionMapping Usage_i8(0x47)
+#define Usage_Arc_SetIODirectionMapping Usage_i8(0x48)
+#define Usage_Arc_ExtendedOpticalInputState Usage_i8(0x49)
+#define Usage_Arc_PinPadInputState Usage_i8(0x4a)
+#define Usage_Arc_PinPadStatus Usage_i8(0x4b)
+#define Usage_Arc_PinPadOutput Usage_i8(0x4c)
+#define Usage_Arc_PinPadCommand Usage_i8(0x4d)
+#define Usage_FIDOA_U2FAuthenticatorDevice Usage_i8(0x1)
+#define Usage_FIDOA_InputReportData Usage_i8(0x20)
+#define Usage_FIDOA_OutputReportData Usage_i8(0x21)
diff --git a/drivers/hid/bpf/progs/hid_usages.h b/drivers/hid/bpf/progs/hid_usages.h
new file mode 100644
index 000000000..5469b25c9
--- /dev/null
+++ b/drivers/hid/bpf/progs/hid_usages.h
@@ -0,0 +1,2810 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2025 Red Hat, Inc
+ */
+
+// THIS FILE IS GENERATED, DO NOT EDIT
+
+#pragma once
+
+/* ----- Generated Usage Pages and Usages ------ */
+#define HidUsagePage_GenericDesktop 0x01
+#define HidUsagePage_SimulationControls 0x02
+#define HidUsagePage_VRControls 0x03
+#define HidUsagePage_SportControls 0x04
+#define HidUsagePage_GameControls 0x05
+#define HidUsagePage_GenericDeviceControls 0x06
+#define HidUsagePage_KeyboardKeypad 0x07
+#define HidUsagePage_LED 0x08
+#define HidUsagePage_Button 0x09
+#define HidUsagePage_Ordinal 0x0a
+#define HidUsagePage_TelephonyDevice 0x0b
+#define HidUsagePage_Consumer 0x0c
+#define HidUsagePage_Digitizers 0x0d
+#define HidUsagePage_Haptics 0x0e
+#define HidUsagePage_PhysicalInputDevice 0x0f
+#define HidUsagePage_Unicode 0x10
+#define HidUsagePage_SoC 0x11
+#define HidUsagePage_EyeandHeadTrackers 0x12
+#define HidUsagePage_AuxiliaryDisplay 0x14
+#define HidUsagePage_Sensors 0x20
+#define HidUsagePage_MedicalInstrument 0x40
+#define HidUsagePage_BrailleDisplay 0x41
+#define HidUsagePage_LightingAndIllumination 0x59
+#define HidUsagePage_Monitor 0x80
+#define HidUsagePage_MonitorEnumerated 0x81
+#define HidUsagePage_VESAVirtualControls 0x82
+#define HidUsagePage_Power 0x84
+#define HidUsagePage_BatterySystem 0x85
+#define HidUsagePage_BarcodeScanner 0x8c
+#define HidUsagePage_Scales 0x8d
+#define HidUsagePage_MagneticStripeReader 0x8e
+#define HidUsagePage_CameraControl 0x90
+#define HidUsagePage_Arcade 0x91
+#define HidUsagePage_FIDOAlliance 0xf1d0
+
+#define HidUsage_GD_Pointer 0x01
+#define HidUsage_GD_Mouse 0x02
+#define HidUsage_GD_Joystick 0x04
+#define HidUsage_GD_Gamepad 0x05
+#define HidUsage_GD_Keyboard 0x06
+#define HidUsage_GD_Keypad 0x07
+#define HidUsage_GD_MultiaxisController 0x08
+#define HidUsage_GD_TabletPCSystemControls 0x09
+#define HidUsage_GD_WaterCoolingDevice 0x0a
+#define HidUsage_GD_ComputerChassisDevice 0x0b
+#define HidUsage_GD_WirelessRadioControls 0x0c
+#define HidUsage_GD_PortableDeviceControl 0x0d
+#define HidUsage_GD_SystemMultiAxisController 0x0e
+#define HidUsage_GD_SpatialController 0x0f
+#define HidUsage_GD_AssistiveControl 0x10
+#define HidUsage_GD_DeviceDock 0x11
+#define HidUsage_GD_DockableDevice 0x12
+#define HidUsage_GD_CallStateManagementControl 0x13
+#define HidUsage_GD_X 0x30
+#define HidUsage_GD_Y 0x31
+#define HidUsage_GD_Z 0x32
+#define HidUsage_GD_Rx 0x33
+#define HidUsage_GD_Ry 0x34
+#define HidUsage_GD_Rz 0x35
+#define HidUsage_GD_Slider 0x36
+#define HidUsage_GD_Dial 0x37
+#define HidUsage_GD_Wheel 0x38
+#define HidUsage_GD_HatSwitch 0x39
+#define HidUsage_GD_CountedBuffer 0x3a
+#define HidUsage_GD_ByteCount 0x3b
+#define HidUsage_GD_MotionWakeup 0x3c
+#define HidUsage_GD_Start 0x3d
+#define HidUsage_GD_Select 0x3e
+#define HidUsage_GD_Vx 0x40
+#define HidUsage_GD_Vy 0x41
+#define HidUsage_GD_Vz 0x42
+#define HidUsage_GD_Vbrx 0x43
+#define HidUsage_GD_Vbry 0x44
+#define HidUsage_GD_Vbrz 0x45
+#define HidUsage_GD_Vno 0x46
+#define HidUsage_GD_FeatureNotification 0x47
+#define HidUsage_GD_ResolutionMultiplier 0x48
+#define HidUsage_GD_Qx 0x49
+#define HidUsage_GD_Qy 0x4a
+#define HidUsage_GD_Qz 0x4b
+#define HidUsage_GD_Qw 0x4c
+#define HidUsage_GD_SystemControl 0x80
+#define HidUsage_GD_SystemPowerDown 0x81
+#define HidUsage_GD_SystemSleep 0x82
+#define HidUsage_GD_SystemWakeUp 0x83
+#define HidUsage_GD_SystemContextMenu 0x84
+#define HidUsage_GD_SystemMainMenu 0x85
+#define HidUsage_GD_SystemAppMenu 0x86
+#define HidUsage_GD_SystemMenuHelp 0x87
+#define HidUsage_GD_SystemMenuExit 0x88
+#define HidUsage_GD_SystemMenuSelect 0x89
+#define HidUsage_GD_SystemMenuRight 0x8a
+#define HidUsage_GD_SystemMenuLeft 0x8b
+#define HidUsage_GD_SystemMenuUp 0x8c
+#define HidUsage_GD_SystemMenuDown 0x8d
+#define HidUsage_GD_SystemColdRestart 0x8e
+#define HidUsage_GD_SystemWarmRestart 0x8f
+#define HidUsage_GD_DpadUp 0x90
+#define HidUsage_GD_DpadDown 0x91
+#define HidUsage_GD_DpadRight 0x92
+#define HidUsage_GD_DpadLeft 0x93
+#define HidUsage_GD_IndexTrigger 0x94
+#define HidUsage_GD_PalmTrigger 0x95
+#define HidUsage_GD_Thumbstick 0x96
+#define HidUsage_GD_SystemFunctionShift 0x97
+#define HidUsage_GD_SystemFunctionShiftLock 0x98
+#define HidUsage_GD_SystemFunctionShiftLockIndicator 0x99
+#define HidUsage_GD_SystemDismissNotification 0x9a
+#define HidUsage_GD_SystemDoNotDisturb 0x9b
+#define HidUsage_GD_SystemDock 0xa0
+#define HidUsage_GD_SystemUndock 0xa1
+#define HidUsage_GD_SystemSetup 0xa2
+#define HidUsage_GD_SystemBreak 0xa3
+#define HidUsage_GD_SystemDebuggerBreak 0xa4
+#define HidUsage_GD_ApplicationBreak 0xa5
+#define HidUsage_GD_ApplicationDebuggerBreak 0xa6
+#define HidUsage_GD_SystemSpeakerMute 0xa7
+#define HidUsage_GD_SystemHibernate 0xa8
+#define HidUsage_GD_SystemMicrophoneMute 0xa9
+#define HidUsage_GD_SystemAccessibilityBinding 0xaa
+#define HidUsage_GD_SystemDisplayInvert 0xb0
+#define HidUsage_GD_SystemDisplayInternal 0xb1
+#define HidUsage_GD_SystemDisplayExternal 0xb2
+#define HidUsage_GD_SystemDisplayBoth 0xb3
+#define HidUsage_GD_SystemDisplayDual 0xb4
+#define HidUsage_GD_SystemDisplayToggleIntExtMode 0xb5
+#define HidUsage_GD_SystemDisplaySwapPrimarySecondary 0xb6
+#define HidUsage_GD_SystemDisplayToggleLCDAutoscale 0xb7
+#define HidUsage_GD_SensorZone 0xc0
+#define HidUsage_GD_RPM 0xc1
+#define HidUsage_GD_CoolantLevel 0xc2
+#define HidUsage_GD_CoolantCriticalLevel 0xc3
+#define HidUsage_GD_CoolantPump 0xc4
+#define HidUsage_GD_ChassisEnclosure 0xc5
+#define HidUsage_GD_WirelessRadioButton 0xc6
+#define HidUsage_GD_WirelessRadioLED 0xc7
+#define HidUsage_GD_WirelessRadioSliderSwitch 0xc8
+#define HidUsage_GD_SystemDisplayRotationLockButton 0xc9
+#define HidUsage_GD_SystemDisplayRotationLockSliderSwitch 0xca
+#define HidUsage_GD_ControlEnable 0xcb
+#define HidUsage_GD_DockableDeviceUniqueID 0xd0
+#define HidUsage_GD_DockableDeviceVendorID 0xd1
+#define HidUsage_GD_DockableDevicePrimaryUsagePage 0xd2
+#define HidUsage_GD_DockableDevicePrimaryUsageID 0xd3
+#define HidUsage_GD_DockableDeviceDockingState 0xd4
+#define HidUsage_GD_DockableDeviceDisplayOcclusion 0xd5
+#define HidUsage_GD_DockableDeviceObjectType 0xd6
+#define HidUsage_GD_CallActiveLED 0xe0
+#define HidUsage_GD_CallMuteToggle 0xe1
+#define HidUsage_GD_CallMuteLED 0xe2
+#define HidUsage_SC_FlightSimulationDevice 0x01
+#define HidUsage_SC_AutomobileSimulationDevice 0x02
+#define HidUsage_SC_TankSimulationDevice 0x03
+#define HidUsage_SC_SpaceshipSimulationDevice 0x04
+#define HidUsage_SC_SubmarineSimulationDevice 0x05
+#define HidUsage_SC_SailingSimulationDevice 0x06
+#define HidUsage_SC_MotorcycleSimulationDevice 0x07
+#define HidUsage_SC_SportsSimulationDevice 0x08
+#define HidUsage_SC_AirplaneSimulationDevice 0x09
+#define HidUsage_SC_HelicopterSimulationDevice 0x0a
+#define HidUsage_SC_MagicCarpetSimulationDevice 0x0b
+#define HidUsage_SC_BicycleSimulationDevice 0x0c
+#define HidUsage_SC_FlightControlStick 0x20
+#define HidUsage_SC_FlightStick 0x21
+#define HidUsage_SC_CyclicControl 0x22
+#define HidUsage_SC_CyclicTrim 0x23
+#define HidUsage_SC_FlightYoke 0x24
+#define HidUsage_SC_TrackControl 0x25
+#define HidUsage_SC_Aileron 0xb0
+#define HidUsage_SC_AileronTrim 0xb1
+#define HidUsage_SC_AntiTorqueControl 0xb2
+#define HidUsage_SC_AutopilotEnable 0xb3
+#define HidUsage_SC_ChaffRelease 0xb4
+#define HidUsage_SC_CollectiveControl 0xb5
+#define HidUsage_SC_DiveBrake 0xb6
+#define HidUsage_SC_ElectronicCountermeasures 0xb7
+#define HidUsage_SC_Elevator 0xb8
+#define HidUsage_SC_ElevatorTrim 0xb9
+#define HidUsage_SC_Rudder 0xba
+#define HidUsage_SC_Throttle 0xbb
+#define HidUsage_SC_FlightCommunications 0xbc
+#define HidUsage_SC_FlareRelease 0xbd
+#define HidUsage_SC_LandingGear 0xbe
+#define HidUsage_SC_ToeBrake 0xbf
+#define HidUsage_SC_Trigger 0xc0
+#define HidUsage_SC_WeaponsArm 0xc1
+#define HidUsage_SC_WeaponsSelect 0xc2
+#define HidUsage_SC_WingFlaps 0xc3
+#define HidUsage_SC_Accelerator 0xc4
+#define HidUsage_SC_Brake 0xc5
+#define HidUsage_SC_Clutch 0xc6
+#define HidUsage_SC_Shifter 0xc7
+#define HidUsage_SC_Steering 0xc8
+#define HidUsage_SC_TurretDirection 0xc9
+#define HidUsage_SC_BarrelElevation 0xca
+#define HidUsage_SC_DivePlane 0xcb
+#define HidUsage_SC_Ballast 0xcc
+#define HidUsage_SC_BicycleCrank 0xcd
+#define HidUsage_SC_HandleBars 0xce
+#define HidUsage_SC_FrontBrake 0xcf
+#define HidUsage_SC_RearBrake 0xd0
+#define HidUsage_VRC_Belt 0x01
+#define HidUsage_VRC_BodySuit 0x02
+#define HidUsage_VRC_Flexor 0x03
+#define HidUsage_VRC_Glove 0x04
+#define HidUsage_VRC_HeadTracker 0x05
+#define HidUsage_VRC_HeadMountedDisplay 0x06
+#define HidUsage_VRC_HandTracker 0x07
+#define HidUsage_VRC_Oculometer 0x08
+#define HidUsage_VRC_Vest 0x09
+#define HidUsage_VRC_AnimatronicDevice 0x0a
+#define HidUsage_VRC_StereoEnable 0x20
+#define HidUsage_VRC_DisplayEnable 0x21
+#define HidUsage_SC_BaseballBat 0x01
+#define HidUsage_SC_GolfClub 0x02
+#define HidUsage_SC_RowingMachine 0x03
+#define HidUsage_SC_Treadmill 0x04
+#define HidUsage_SC_Oar 0x30
+#define HidUsage_SC_Slope 0x31
+#define HidUsage_SC_Rate 0x32
+#define HidUsage_SC_StickSpeed 0x33
+#define HidUsage_SC_StickFaceAngle 0x34
+#define HidUsage_SC_StickHeelToe 0x35
+#define HidUsage_SC_StickFollowThrough 0x36
+#define HidUsage_SC_StickTempo 0x37
+#define HidUsage_SC_StickType 0x38
+#define HidUsage_SC_StickHeight 0x39
+#define HidUsage_SC_Putter 0x50
+#define HidUsage_SC_OneIron 0x51
+#define HidUsage_SC_TwoIron 0x52
+#define HidUsage_SC_ThreeIron 0x53
+#define HidUsage_SC_FourIron 0x54
+#define HidUsage_SC_FiveIron 0x55
+#define HidUsage_SC_SixIron 0x56
+#define HidUsage_SC_SevenIron 0x57
+#define HidUsage_SC_EightIron 0x58
+#define HidUsage_SC_NineIron 0x59
+#define HidUsage_SC_One0Iron 0x5a
+#define HidUsage_SC_One1Iron 0x5b
+#define HidUsage_SC_SandWedge 0x5c
+#define HidUsage_SC_LoftWedge 0x5d
+#define HidUsage_SC_PowerWedge 0x5e
+#define HidUsage_SC_OneWood 0x5f
+#define HidUsage_SC_ThreeWood 0x60
+#define HidUsage_SC_FiveWood 0x61
+#define HidUsage_SC_SevenWood 0x62
+#define HidUsage_SC_NineWood 0x63
+#define HidUsage_GC_ThreeDGameController 0x01
+#define HidUsage_GC_PinballDevice 0x02
+#define HidUsage_GC_GunDevice 0x03
+#define HidUsage_GC_PointofView 0x20
+#define HidUsage_GC_TurnRightLeft 0x21
+#define HidUsage_GC_PitchForwardBackward 0x22
+#define HidUsage_GC_RollRightLeft 0x23
+#define HidUsage_GC_MoveRightLeft 0x24
+#define HidUsage_GC_MoveForwardBackward 0x25
+#define HidUsage_GC_MoveUpDown 0x26
+#define HidUsage_GC_LeanRightLeft 0x27
+#define HidUsage_GC_LeanForwardBackward 0x28
+#define HidUsage_GC_HeightofPOV 0x29
+#define HidUsage_GC_Flipper 0x2a
+#define HidUsage_GC_SecondaryFlipper 0x2b
+#define HidUsage_GC_Bump 0x2c
+#define HidUsage_GC_NewGame 0x2d
+#define HidUsage_GC_ShootBall 0x2e
+#define HidUsage_GC_Player 0x2f
+#define HidUsage_GC_GunBolt 0x30
+#define HidUsage_GC_GunClip 0x31
+#define HidUsage_GC_GunSelector 0x32
+#define HidUsage_GC_GunSingleShot 0x33
+#define HidUsage_GC_GunBurst 0x34
+#define HidUsage_GC_GunAutomatic 0x35
+#define HidUsage_GC_GunSafety 0x36
+#define HidUsage_GC_GamepadFireJump 0x37
+#define HidUsage_GC_GamepadTrigger 0x39
+#define HidUsage_GC_FormfittingGamepad 0x3a
+#define HidUsage_GDC_BackgroundNonuserControls 0x01
+#define HidUsage_GDC_BatteryStrength 0x20
+#define HidUsage_GDC_WirelessChannel 0x21
+#define HidUsage_GDC_WirelessID 0x22
+#define HidUsage_GDC_DiscoverWirelessControl 0x23
+#define HidUsage_GDC_SecurityCodeCharacterEntered 0x24
+#define HidUsage_GDC_SecurityCodeCharacterErased 0x25
+#define HidUsage_GDC_SecurityCodeCleared 0x26
+#define HidUsage_GDC_SequenceID 0x27
+#define HidUsage_GDC_SequenceIDReset 0x28
+#define HidUsage_GDC_RFSignalStrength 0x29
+#define HidUsage_GDC_SoftwareVersion 0x2a
+#define HidUsage_GDC_ProtocolVersion 0x2b
+#define HidUsage_GDC_HardwareVersion 0x2c
+#define HidUsage_GDC_Major 0x2d
+#define HidUsage_GDC_Minor 0x2e
+#define HidUsage_GDC_Revision 0x2f
+#define HidUsage_GDC_Handedness 0x30
+#define HidUsage_GDC_EitherHand 0x31
+#define HidUsage_GDC_LeftHand 0x32
+#define HidUsage_GDC_RightHand 0x33
+#define HidUsage_GDC_BothHands 0x34
+#define HidUsage_GDC_GripPoseOffset 0x40
+#define HidUsage_GDC_PointerPoseOffset 0x41
+#define HidUsage_KK_ErrorRollOver 0x01
+#define HidUsage_KK_POSTFail 0x02
+#define HidUsage_KK_ErrorUndefined 0x03
+#define HidUsage_KK_KeyboardA 0x04
+#define HidUsage_KK_KeyboardB 0x05
+#define HidUsage_KK_KeyboardC 0x06
+#define HidUsage_KK_KeyboardD 0x07
+#define HidUsage_KK_KeyboardE 0x08
+#define HidUsage_KK_KeyboardF 0x09
+#define HidUsage_KK_KeyboardG 0x0a
+#define HidUsage_KK_KeyboardH 0x0b
+#define HidUsage_KK_KeyboardI 0x0c
+#define HidUsage_KK_KeyboardJ 0x0d
+#define HidUsage_KK_KeyboardK 0x0e
+#define HidUsage_KK_KeyboardL 0x0f
+#define HidUsage_KK_KeyboardM 0x10
+#define HidUsage_KK_KeyboardN 0x11
+#define HidUsage_KK_KeyboardO 0x12
+#define HidUsage_KK_KeyboardP 0x13
+#define HidUsage_KK_KeyboardQ 0x14
+#define HidUsage_KK_KeyboardR 0x15
+#define HidUsage_KK_KeyboardS 0x16
+#define HidUsage_KK_KeyboardT 0x17
+#define HidUsage_KK_KeyboardU 0x18
+#define HidUsage_KK_KeyboardV 0x19
+#define HidUsage_KK_KeyboardW 0x1a
+#define HidUsage_KK_KeyboardX 0x1b
+#define HidUsage_KK_KeyboardY 0x1c
+#define HidUsage_KK_KeyboardZ 0x1d
+#define HidUsage_KK_Keyboard1andBang 0x1e
+#define HidUsage_KK_Keyboard2andAt 0x1f
+#define HidUsage_KK_Keyboard3andHash 0x20
+#define HidUsage_KK_Keyboard4andDollar 0x21
+#define HidUsage_KK_Keyboard5andPercent 0x22
+#define HidUsage_KK_Keyboard6andCaret 0x23
+#define HidUsage_KK_Keyboard7andAmpersand 0x24
+#define HidUsage_KK_Keyboard8andStar 0x25
+#define HidUsage_KK_Keyboard9andLeftBracket 0x26
+#define HidUsage_KK_Keyboard0andRightBracket 0x27
+#define HidUsage_KK_KeyboardReturnEnter 0x28
+#define HidUsage_KK_KeyboardEscape 0x29
+#define HidUsage_KK_KeyboardDelete 0x2a
+#define HidUsage_KK_KeyboardTab 0x2b
+#define HidUsage_KK_KeyboardSpacebar 0x2c
+#define HidUsage_KK_KeyboardDashandUnderscore 0x2d
+#define HidUsage_KK_KeyboardEqualsandPlus 0x2e
+#define HidUsage_KK_KeyboardLeftBrace 0x2f
+#define HidUsage_KK_KeyboardRightBrace 0x30
+#define HidUsage_KK_KeyboardBackslashandPipe 0x31
+#define HidUsage_KK_KeyboardNonUSHashandTilde 0x32
+#define HidUsage_KK_KeyboardSemiColonandColon 0x33
+#define HidUsage_KK_KeyboardLeftAposandDouble 0x34
+#define HidUsage_KK_KeyboardGraveAccentandTilde 0x35
+#define HidUsage_KK_KeyboardCommaandLessThan 0x36
+#define HidUsage_KK_KeyboardPeriodandGreaterThan 0x37
+#define HidUsage_KK_KeyboardForwardSlashandQuestionMark 0x38
+#define HidUsage_KK_KeyboardCapsLock 0x39
+#define HidUsage_KK_KeyboardF1 0x3a
+#define HidUsage_KK_KeyboardF2 0x3b
+#define HidUsage_KK_KeyboardF3 0x3c
+#define HidUsage_KK_KeyboardF4 0x3d
+#define HidUsage_KK_KeyboardF5 0x3e
+#define HidUsage_KK_KeyboardF6 0x3f
+#define HidUsage_KK_KeyboardF7 0x40
+#define HidUsage_KK_KeyboardF8 0x41
+#define HidUsage_KK_KeyboardF9 0x42
+#define HidUsage_KK_KeyboardF10 0x43
+#define HidUsage_KK_KeyboardF11 0x44
+#define HidUsage_KK_KeyboardF12 0x45
+#define HidUsage_KK_KeyboardPrintScreen 0x46
+#define HidUsage_KK_KeyboardScrollLock 0x47
+#define HidUsage_KK_KeyboardPause 0x48
+#define HidUsage_KK_KeyboardInsert 0x49
+#define HidUsage_KK_KeyboardHome 0x4a
+#define HidUsage_KK_KeyboardPageUp 0x4b
+#define HidUsage_KK_KeyboardDeleteForward 0x4c
+#define HidUsage_KK_KeyboardEnd 0x4d
+#define HidUsage_KK_KeyboardPageDown 0x4e
+#define HidUsage_KK_KeyboardRightArrow 0x4f
+#define HidUsage_KK_KeyboardLeftArrow 0x50
+#define HidUsage_KK_KeyboardDownArrow 0x51
+#define HidUsage_KK_KeyboardUpArrow 0x52
+#define HidUsage_KK_KeypadNumLockandClear 0x53
+#define HidUsage_KK_KeypadForwardSlash 0x54
+#define HidUsage_KK_KeypadStar 0x55
+#define HidUsage_KK_KeypadDash 0x56
+#define HidUsage_KK_KeypadPlus 0x57
+#define HidUsage_KK_KeypadENTER 0x58
+#define HidUsage_KK_Keypad1andEnd 0x59
+#define HidUsage_KK_Keypad2andDownArrow 0x5a
+#define HidUsage_KK_Keypad3andPageDn 0x5b
+#define HidUsage_KK_Keypad4andLeftArrow 0x5c
+#define HidUsage_KK_Keypad5 0x5d
+#define HidUsage_KK_Keypad6andRightArrow 0x5e
+#define HidUsage_KK_Keypad7andHome 0x5f
+#define HidUsage_KK_Keypad8andUpArrow 0x60
+#define HidUsage_KK_Keypad9andPageUp 0x61
+#define HidUsage_KK_Keypad0andInsert 0x62
+#define HidUsage_KK_KeypadPeriodandDelete 0x63
+#define HidUsage_KK_KeyboardNonUSBackslashandPipe 0x64
+#define HidUsage_KK_KeyboardApplication 0x65
+#define HidUsage_KK_KeyboardPower 0x66
+#define HidUsage_KK_KeypadEquals 0x67
+#define HidUsage_KK_KeyboardF13 0x68
+#define HidUsage_KK_KeyboardF14 0x69
+#define HidUsage_KK_KeyboardF15 0x6a
+#define HidUsage_KK_KeyboardF16 0x6b
+#define HidUsage_KK_KeyboardF17 0x6c
+#define HidUsage_KK_KeyboardF18 0x6d
+#define HidUsage_KK_KeyboardF19 0x6e
+#define HidUsage_KK_KeyboardF20 0x6f
+#define HidUsage_KK_KeyboardF21 0x70
+#define HidUsage_KK_KeyboardF22 0x71
+#define HidUsage_KK_KeyboardF23 0x72
+#define HidUsage_KK_KeyboardF24 0x73
+#define HidUsage_KK_KeyboardExecute 0x74
+#define HidUsage_KK_KeyboardHelp 0x75
+#define HidUsage_KK_KeyboardMenu 0x76
+#define HidUsage_KK_KeyboardSelect 0x77
+#define HidUsage_KK_KeyboardStop 0x78
+#define HidUsage_KK_KeyboardAgain 0x79
+#define HidUsage_KK_KeyboardUndo 0x7a
+#define HidUsage_KK_KeyboardCut 0x7b
+#define HidUsage_KK_KeyboardCopy 0x7c
+#define HidUsage_KK_KeyboardPaste 0x7d
+#define HidUsage_KK_KeyboardFind 0x7e
+#define HidUsage_KK_KeyboardMute 0x7f
+#define HidUsage_KK_KeyboardVolumeUp 0x80
+#define HidUsage_KK_KeyboardVolumeDown 0x81
+#define HidUsage_KK_KeyboardLockingCapsLock 0x82
+#define HidUsage_KK_KeyboardLockingNumLock 0x83
+#define HidUsage_KK_KeyboardLockingScrollLock 0x84
+#define HidUsage_KK_KeypadComma 0x85
+#define HidUsage_KK_KeypadEqualSign 0x86
+#define HidUsage_KK_KeyboardInternational1 0x87
+#define HidUsage_KK_KeyboardInternational2 0x88
+#define HidUsage_KK_KeyboardInternational3 0x89
+#define HidUsage_KK_KeyboardInternational4 0x8a
+#define HidUsage_KK_KeyboardInternational5 0x8b
+#define HidUsage_KK_KeyboardInternational6 0x8c
+#define HidUsage_KK_KeyboardInternational7 0x8d
+#define HidUsage_KK_KeyboardInternational8 0x8e
+#define HidUsage_KK_KeyboardInternational9 0x8f
+#define HidUsage_KK_KeyboardLANG1 0x90
+#define HidUsage_KK_KeyboardLANG2 0x91
+#define HidUsage_KK_KeyboardLANG3 0x92
+#define HidUsage_KK_KeyboardLANG4 0x93
+#define HidUsage_KK_KeyboardLANG5 0x94
+#define HidUsage_KK_KeyboardLANG6 0x95
+#define HidUsage_KK_KeyboardLANG7 0x96
+#define HidUsage_KK_KeyboardLANG8 0x97
+#define HidUsage_KK_KeyboardLANG9 0x98
+#define HidUsage_KK_KeyboardAlternateErase 0x99
+#define HidUsage_KK_KeyboardSysReqAttention 0x9a
+#define HidUsage_KK_KeyboardCancel 0x9b
+#define HidUsage_KK_KeyboardClear 0x9c
+#define HidUsage_KK_KeyboardPrior 0x9d
+#define HidUsage_KK_KeyboardReturn 0x9e
+#define HidUsage_KK_KeyboardSeparator 0x9f
+#define HidUsage_KK_KeyboardOut 0xa0
+#define HidUsage_KK_KeyboardOper 0xa1
+#define HidUsage_KK_KeyboardClearAgain 0xa2
+#define HidUsage_KK_KeyboardCrSelProps 0xa3
+#define HidUsage_KK_KeyboardExSel 0xa4
+#define HidUsage_KK_KeypadDouble0 0xb0
+#define HidUsage_KK_KeypadTriple0 0xb1
+#define HidUsage_KK_ThousandsSeparator 0xb2
+#define HidUsage_KK_DecimalSeparator 0xb3
+#define HidUsage_KK_CurrencyUnit 0xb4
+#define HidUsage_KK_CurrencySubunit 0xb5
+#define HidUsage_KK_KeypadLeftBracket 0xb6
+#define HidUsage_KK_KeypadRightBracket 0xb7
+#define HidUsage_KK_KeypadLeftBrace 0xb8
+#define HidUsage_KK_KeypadRightBrace 0xb9
+#define HidUsage_KK_KeypadTab 0xba
+#define HidUsage_KK_KeypadBackspace 0xbb
+#define HidUsage_KK_KeypadA 0xbc
+#define HidUsage_KK_KeypadB 0xbd
+#define HidUsage_KK_KeypadC 0xbe
+#define HidUsage_KK_KeypadD 0xbf
+#define HidUsage_KK_KeypadE 0xc0
+#define HidUsage_KK_KeypadF 0xc1
+#define HidUsage_KK_KeypadXOR 0xc2
+#define HidUsage_KK_KeypadCaret 0xc3
+#define HidUsage_KK_KeypadPercentage 0xc4
+#define HidUsage_KK_KeypadLess 0xc5
+#define HidUsage_KK_KeypadGreater 0xc6
+#define HidUsage_KK_KeypadAmpersand 0xc7
+#define HidUsage_KK_KeypadDoubleAmpersand 0xc8
+#define HidUsage_KK_KeypadBar 0xc9
+#define HidUsage_KK_KeypadDoubleBar 0xca
+#define HidUsage_KK_KeypadColon 0xcb
+#define HidUsage_KK_KeypadHash 0xcc
+#define HidUsage_KK_KeypadSpace 0xcd
+#define HidUsage_KK_KeypadAt 0xce
+#define HidUsage_KK_KeypadBang 0xcf
+#define HidUsage_KK_KeypadMemoryStore 0xd0
+#define HidUsage_KK_KeypadMemoryRecall 0xd1
+#define HidUsage_KK_KeypadMemoryClear 0xd2
+#define HidUsage_KK_KeypadMemoryAdd 0xd3
+#define HidUsage_KK_KeypadMemorySubtract 0xd4
+#define HidUsage_KK_KeypadMemoryMultiply 0xd5
+#define HidUsage_KK_KeypadMemoryDivide 0xd6
+#define HidUsage_KK_KeypadPlusMinus 0xd7
+#define HidUsage_KK_KeypadClear 0xd8
+#define HidUsage_KK_KeypadClearEntry 0xd9
+#define HidUsage_KK_KeypadBinary 0xda
+#define HidUsage_KK_KeypadOctal 0xdb
+#define HidUsage_KK_KeypadDecimal 0xdc
+#define HidUsage_KK_KeypadHexadecimal 0xdd
+#define HidUsage_KK_KeyboardLeftControl 0xe0
+#define HidUsage_KK_KeyboardLeftShift 0xe1
+#define HidUsage_KK_KeyboardLeftAlt 0xe2
+#define HidUsage_KK_KeyboardLeftGUI 0xe3
+#define HidUsage_KK_KeyboardRightControl 0xe4
+#define HidUsage_KK_KeyboardRightShift 0xe5
+#define HidUsage_KK_KeyboardRightAlt 0xe6
+#define HidUsage_KK_KeyboardRightGUI 0xe7
+#define HidUsage_LED_NumLock 0x01
+#define HidUsage_LED_CapsLock 0x02
+#define HidUsage_LED_ScrollLock 0x03
+#define HidUsage_LED_Compose 0x04
+#define HidUsage_LED_Kana 0x05
+#define HidUsage_LED_Power 0x06
+#define HidUsage_LED_Shift 0x07
+#define HidUsage_LED_DoNotDisturb 0x08
+#define HidUsage_LED_Mute 0x09
+#define HidUsage_LED_ToneEnable 0x0a
+#define HidUsage_LED_HighCutFilter 0x0b
+#define HidUsage_LED_LowCutFilter 0x0c
+#define HidUsage_LED_EqualizerEnable 0x0d
+#define HidUsage_LED_SoundFieldOn 0x0e
+#define HidUsage_LED_SurroundOn 0x0f
+#define HidUsage_LED_Repeat 0x10
+#define HidUsage_LED_Stereo 0x11
+#define HidUsage_LED_SamplingRateDetect 0x12
+#define HidUsage_LED_Spinning 0x13
+#define HidUsage_LED_CAV 0x14
+#define HidUsage_LED_CLV 0x15
+#define HidUsage_LED_RecordingFormatDetect 0x16
+#define HidUsage_LED_OffHook 0x17
+#define HidUsage_LED_Ring 0x18
+#define HidUsage_LED_MessageWaiting 0x19
+#define HidUsage_LED_DataMode 0x1a
+#define HidUsage_LED_BatteryOperation 0x1b
+#define HidUsage_LED_BatteryOK 0x1c
+#define HidUsage_LED_BatteryLow 0x1d
+#define HidUsage_LED_Speaker 0x1e
+#define HidUsage_LED_Headset 0x1f
+#define HidUsage_LED_Hold 0x20
+#define HidUsage_LED_Microphone 0x21
+#define HidUsage_LED_Coverage 0x22
+#define HidUsage_LED_NightMode 0x23
+#define HidUsage_LED_SendCalls 0x24
+#define HidUsage_LED_CallPickup 0x25
+#define HidUsage_LED_Conference 0x26
+#define HidUsage_LED_Standby 0x27
+#define HidUsage_LED_CameraOn 0x28
+#define HidUsage_LED_CameraOff 0x29
+#define HidUsage_LED_OnLine 0x2a
+#define HidUsage_LED_OffLine 0x2b
+#define HidUsage_LED_Busy 0x2c
+#define HidUsage_LED_Ready 0x2d
+#define HidUsage_LED_PaperOut 0x2e
+#define HidUsage_LED_PaperJam 0x2f
+#define HidUsage_LED_Remote 0x30
+#define HidUsage_LED_Forward 0x31
+#define HidUsage_LED_Reverse 0x32
+#define HidUsage_LED_Stop 0x33
+#define HidUsage_LED_Rewind 0x34
+#define HidUsage_LED_FastForward 0x35
+#define HidUsage_LED_Play 0x36
+#define HidUsage_LED_Pause 0x37
+#define HidUsage_LED_Record 0x38
+#define HidUsage_LED_Error 0x39
+#define HidUsage_LED_UsageSelectedIndicator 0x3a
+#define HidUsage_LED_UsageInUseIndicator 0x3b
+#define HidUsage_LED_UsageMultiModeIndicator 0x3c
+#define HidUsage_LED_IndicatorOn 0x3d
+#define HidUsage_LED_IndicatorFlash 0x3e
+#define HidUsage_LED_IndicatorSlowBlink 0x3f
+#define HidUsage_LED_IndicatorFastBlink 0x40
+#define HidUsage_LED_IndicatorOff 0x41
+#define HidUsage_LED_FlashOnTime 0x42
+#define HidUsage_LED_SlowBlinkOnTime 0x43
+#define HidUsage_LED_SlowBlinkOffTime 0x44
+#define HidUsage_LED_FastBlinkOnTime 0x45
+#define HidUsage_LED_FastBlinkOffTime 0x46
+#define HidUsage_LED_UsageIndicatorColor 0x47
+#define HidUsage_LED_IndicatorRed 0x48
+#define HidUsage_LED_IndicatorGreen 0x49
+#define HidUsage_LED_IndicatorAmber 0x4a
+#define HidUsage_LED_GenericIndicator 0x4b
+#define HidUsage_LED_SystemSuspend 0x4c
+#define HidUsage_LED_ExternalPowerConnected 0x4d
+#define HidUsage_LED_IndicatorBlue 0x4e
+#define HidUsage_LED_IndicatorOrange 0x4f
+#define HidUsage_LED_GoodStatus 0x50
+#define HidUsage_LED_WarningStatus 0x51
+#define HidUsage_LED_RGBLED 0x52
+#define HidUsage_LED_RedLEDChannel 0x53
+#define HidUsage_LED_BlueLEDChannel 0x54
+#define HidUsage_LED_GreenLEDChannel 0x55
+#define HidUsage_LED_LEDIntensity 0x56
+#define HidUsage_LED_SystemMicrophoneMute 0x57
+#define HidUsage_LED_PlayerIndicator 0x60
+#define HidUsage_LED_Player1 0x61
+#define HidUsage_LED_Player2 0x62
+#define HidUsage_LED_Player3 0x63
+#define HidUsage_LED_Player4 0x64
+#define HidUsage_LED_Player5 0x65
+#define HidUsage_LED_Player6 0x66
+#define HidUsage_LED_Player7 0x67
+#define HidUsage_LED_Player8 0x68
+#define HidUsage_TD_Phone 0x01
+#define HidUsage_TD_AnsweringMachine 0x02
+#define HidUsage_TD_MessageControls 0x03
+#define HidUsage_TD_Handset 0x04
+#define HidUsage_TD_Headset 0x05
+#define HidUsage_TD_TelephonyKeyPad 0x06
+#define HidUsage_TD_ProgrammableButton 0x07
+#define HidUsage_TD_HookSwitch 0x20
+#define HidUsage_TD_Flash 0x21
+#define HidUsage_TD_Feature 0x22
+#define HidUsage_TD_Hold 0x23
+#define HidUsage_TD_Redial 0x24
+#define HidUsage_TD_Transfer 0x25
+#define HidUsage_TD_Drop 0x26
+#define HidUsage_TD_Park 0x27
+#define HidUsage_TD_ForwardCalls 0x28
+#define HidUsage_TD_AlternateFunction 0x29
+#define HidUsage_TD_Line 0x2a
+#define HidUsage_TD_SpeakerPhone 0x2b
+#define HidUsage_TD_Conference 0x2c
+#define HidUsage_TD_RingEnable 0x2d
+#define HidUsage_TD_RingSelect 0x2e
+#define HidUsage_TD_PhoneMute 0x2f
+#define HidUsage_TD_CallerID 0x30
+#define HidUsage_TD_Send 0x31
+#define HidUsage_TD_SpeedDial 0x50
+#define HidUsage_TD_StoreNumber 0x51
+#define HidUsage_TD_RecallNumber 0x52
+#define HidUsage_TD_PhoneDirectory 0x53
+#define HidUsage_TD_VoiceMail 0x70
+#define HidUsage_TD_ScreenCalls 0x71
+#define HidUsage_TD_DoNotDisturb 0x72
+#define HidUsage_TD_Message 0x73
+#define HidUsage_TD_AnswerOnOff 0x74
+#define HidUsage_TD_InsideDialTone 0x90
+#define HidUsage_TD_OutsideDialTone 0x91
+#define HidUsage_TD_InsideRingTone 0x92
+#define HidUsage_TD_OutsideRingTone 0x93
+#define HidUsage_TD_PriorityRingTone 0x94
+#define HidUsage_TD_InsideRingback 0x95
+#define HidUsage_TD_PriorityRingback 0x96
+#define HidUsage_TD_LineBusyTone 0x97
+#define HidUsage_TD_ReorderTone 0x98
+#define HidUsage_TD_CallWaitingTone 0x99
+#define HidUsage_TD_ConfirmationTone1 0x9a
+#define HidUsage_TD_ConfirmationTone2 0x9b
+#define HidUsage_TD_TonesOff 0x9c
+#define HidUsage_TD_OutsideRingback 0x9d
+#define HidUsage_TD_Ringer 0x9e
+#define HidUsage_TD_PhoneKey0 0xb0
+#define HidUsage_TD_PhoneKey1 0xb1
+#define HidUsage_TD_PhoneKey2 0xb2
+#define HidUsage_TD_PhoneKey3 0xb3
+#define HidUsage_TD_PhoneKey4 0xb4
+#define HidUsage_TD_PhoneKey5 0xb5
+#define HidUsage_TD_PhoneKey6 0xb6
+#define HidUsage_TD_PhoneKey7 0xb7
+#define HidUsage_TD_PhoneKey8 0xb8
+#define HidUsage_TD_PhoneKey9 0xb9
+#define HidUsage_TD_PhoneKeyStar 0xba
+#define HidUsage_TD_PhoneKeyPound 0xbb
+#define HidUsage_TD_PhoneKeyA 0xbc
+#define HidUsage_TD_PhoneKeyB 0xbd
+#define HidUsage_TD_PhoneKeyC 0xbe
+#define HidUsage_TD_PhoneKeyD 0xbf
+#define HidUsage_TD_PhoneCallHistoryKey 0xc0
+#define HidUsage_TD_PhoneCallerIDKey 0xc1
+#define HidUsage_TD_PhoneSettingsKey 0xc2
+#define HidUsage_TD_HostControl 0xf0
+#define HidUsage_TD_HostAvailable 0xf1
+#define HidUsage_TD_HostCallActive 0xf2
+#define HidUsage_TD_ActivateHandsetAudio 0xf3
+#define HidUsage_TD_RingType 0xf4
+#define HidUsage_TD_RedialablePhoneNumber 0xf5
+#define HidUsage_TD_StopRingTone 0xf8
+#define HidUsage_TD_PSTNRingTone 0xf9
+#define HidUsage_TD_HostRingTone 0xfa
+#define HidUsage_TD_AlertSoundError 0xfb
+#define HidUsage_TD_AlertSoundConfirm 0xfc
+#define HidUsage_TD_AlertSoundNotification 0xfd
+#define HidUsage_TD_SilentRing 0xfe
+#define HidUsage_TD_EmailMessageWaiting 0x108
+#define HidUsage_TD_VoicemailMessageWaiting 0x109
+#define HidUsage_TD_HostHold 0x10a
+#define HidUsage_TD_IncomingCallHistoryCount 0x110
+#define HidUsage_TD_OutgoingCallHistoryCount 0x111
+#define HidUsage_TD_IncomingCallHistory 0x112
+#define HidUsage_TD_OutgoingCallHistory 0x113
+#define HidUsage_TD_PhoneLocale 0x114
+#define HidUsage_TD_PhoneTimeSecond 0x140
+#define HidUsage_TD_PhoneTimeMinute 0x141
+#define HidUsage_TD_PhoneTimeHour 0x142
+#define HidUsage_TD_PhoneDateDay 0x143
+#define HidUsage_TD_PhoneDateMonth 0x144
+#define HidUsage_TD_PhoneDateYear 0x145
+#define HidUsage_TD_HandsetNickname 0x146
+#define HidUsage_TD_AddressBookID 0x147
+#define HidUsage_TD_CallDuration 0x14a
+#define HidUsage_TD_DualModePhone 0x14b
+#define HidUsage_Con_ConsumerControl 0x01
+#define HidUsage_Con_NumericKeyPad 0x02
+#define HidUsage_Con_ProgrammableButtons 0x03
+#define HidUsage_Con_Microphone 0x04
+#define HidUsage_Con_Headphone 0x05
+#define HidUsage_Con_GraphicEqualizer 0x06
+#define HidUsage_Con_Plus10 0x20
+#define HidUsage_Con_Plus100 0x21
+#define HidUsage_Con_AMPM 0x22
+#define HidUsage_Con_Power 0x30
+#define HidUsage_Con_Reset 0x31
+#define HidUsage_Con_Sleep 0x32
+#define HidUsage_Con_SleepAfter 0x33
+#define HidUsage_Con_SleepMode 0x34
+#define HidUsage_Con_Illumination 0x35
+#define HidUsage_Con_FunctionButtons 0x36
+#define HidUsage_Con_Menu 0x40
+#define HidUsage_Con_MenuPick 0x41
+#define HidUsage_Con_MenuUp 0x42
+#define HidUsage_Con_MenuDown 0x43
+#define HidUsage_Con_MenuLeft 0x44
+#define HidUsage_Con_MenuRight 0x45
+#define HidUsage_Con_MenuEscape 0x46
+#define HidUsage_Con_MenuValueIncrease 0x47
+#define HidUsage_Con_MenuValueDecrease 0x48
+#define HidUsage_Con_DataOnScreen 0x60
+#define HidUsage_Con_ClosedCaption 0x61
+#define HidUsage_Con_ClosedCaptionSelect 0x62
+#define HidUsage_Con_VCRTV 0x63
+#define HidUsage_Con_BroadcastMode 0x64
+#define HidUsage_Con_Snapshot 0x65
+#define HidUsage_Con_Still 0x66
+#define HidUsage_Con_PictureinPictureToggle 0x67
+#define HidUsage_Con_PictureinPictureSwap 0x68
+#define HidUsage_Con_RedMenuButton 0x69
+#define HidUsage_Con_GreenMenuButton 0x6a
+#define HidUsage_Con_BlueMenuButton 0x6b
+#define HidUsage_Con_YellowMenuButton 0x6c
+#define HidUsage_Con_Aspect 0x6d
+#define HidUsage_Con_ThreeDModeSelect 0x6e
+#define HidUsage_Con_DisplayBrightnessIncrement 0x6f
+#define HidUsage_Con_DisplayBrightnessDecrement 0x70
+#define HidUsage_Con_DisplayBrightness 0x71
+#define HidUsage_Con_DisplayBacklightToggle 0x72
+#define HidUsage_Con_DisplaySetBrightnesstoMinimum 0x73
+#define HidUsage_Con_DisplaySetBrightnesstoMaximum 0x74
+#define HidUsage_Con_DisplaySetAutoBrightness 0x75
+#define HidUsage_Con_CameraAccessEnabled 0x76
+#define HidUsage_Con_CameraAccessDisabled 0x77
+#define HidUsage_Con_CameraAccessToggle 0x78
+#define HidUsage_Con_KeyboardBrightnessIncrement 0x79
+#define HidUsage_Con_KeyboardBrightnessDecrement 0x7a
+#define HidUsage_Con_KeyboardBacklightSetLevel 0x7b
+#define HidUsage_Con_KeyboardBacklightOOC 0x7c
+#define HidUsage_Con_KeyboardBacklightSetMinimum 0x7d
+#define HidUsage_Con_KeyboardBacklightSetMaximum 0x7e
+#define HidUsage_Con_KeyboardBacklightAuto 0x7f
+#define HidUsage_Con_Selection 0x80
+#define HidUsage_Con_AssignSelection 0x81
+#define HidUsage_Con_ModeStep 0x82
+#define HidUsage_Con_RecallLast 0x83
+#define HidUsage_Con_EnterChannel 0x84
+#define HidUsage_Con_OrderMovie 0x85
+#define HidUsage_Con_Channel 0x86
+#define HidUsage_Con_MediaSelection 0x87
+#define HidUsage_Con_MediaSelectComputer 0x88
+#define HidUsage_Con_MediaSelectTV 0x89
+#define HidUsage_Con_MediaSelectWWW 0x8a
+#define HidUsage_Con_MediaSelectDVD 0x8b
+#define HidUsage_Con_MediaSelectTelephone 0x8c
+#define HidUsage_Con_MediaSelectProgramGuide 0x8d
+#define HidUsage_Con_MediaSelectVideoPhone 0x8e
+#define HidUsage_Con_MediaSelectGames 0x8f
+#define HidUsage_Con_MediaSelectMessages 0x90
+#define HidUsage_Con_MediaSelectCD 0x91
+#define HidUsage_Con_MediaSelectVCR 0x92
+#define HidUsage_Con_MediaSelectTuner 0x93
+#define HidUsage_Con_Quit 0x94
+#define HidUsage_Con_Help 0x95
+#define HidUsage_Con_MediaSelectTape 0x96
+#define HidUsage_Con_MediaSelectCable 0x97
+#define HidUsage_Con_MediaSelectSatellite 0x98
+#define HidUsage_Con_MediaSelectSecurity 0x99
+#define HidUsage_Con_MediaSelectHome 0x9a
+#define HidUsage_Con_MediaSelectCall 0x9b
+#define HidUsage_Con_ChannelIncrement 0x9c
+#define HidUsage_Con_ChannelDecrement 0x9d
+#define HidUsage_Con_MediaSelectSAP 0x9e
+#define HidUsage_Con_VCRPlus 0xa0
+#define HidUsage_Con_Once 0xa1
+#define HidUsage_Con_Daily 0xa2
+#define HidUsage_Con_Weekly 0xa3
+#define HidUsage_Con_Monthly 0xa4
+#define HidUsage_Con_Play 0xb0
+#define HidUsage_Con_Pause 0xb1
+#define HidUsage_Con_Record 0xb2
+#define HidUsage_Con_FastForward 0xb3
+#define HidUsage_Con_Rewind 0xb4
+#define HidUsage_Con_ScanNextTrack 0xb5
+#define HidUsage_Con_ScanPreviousTrack 0xb6
+#define HidUsage_Con_Stop 0xb7
+#define HidUsage_Con_Eject 0xb8
+#define HidUsage_Con_RandomPlay 0xb9
+#define HidUsage_Con_SelectDisc 0xba
+#define HidUsage_Con_EnterDisc 0xbb
+#define HidUsage_Con_Repeat 0xbc
+#define HidUsage_Con_Tracking 0xbd
+#define HidUsage_Con_TrackNormal 0xbe
+#define HidUsage_Con_SlowTracking 0xbf
+#define HidUsage_Con_FrameForward 0xc0
+#define HidUsage_Con_FrameBack 0xc1
+#define HidUsage_Con_Mark 0xc2
+#define HidUsage_Con_ClearMark 0xc3
+#define HidUsage_Con_RepeatFromMark 0xc4
+#define HidUsage_Con_ReturnToMark 0xc5
+#define HidUsage_Con_SearchMarkForward 0xc6
+#define HidUsage_Con_SearchMarkBackwards 0xc7
+#define HidUsage_Con_CounterReset 0xc8
+#define HidUsage_Con_ShowCounter 0xc9
+#define HidUsage_Con_TrackingIncrement 0xca
+#define HidUsage_Con_TrackingDecrement 0xcb
+#define HidUsage_Con_StopEject 0xcc
+#define HidUsage_Con_PlayPause 0xcd
+#define HidUsage_Con_PlaySkip 0xce
+#define HidUsage_Con_VoiceCommand 0xcf
+#define HidUsage_Con_InvokeCaptureInterface 0xd0
+#define HidUsage_Con_StartorStopGameRecording 0xd1
+#define HidUsage_Con_HistoricalGameCapture 0xd2
+#define HidUsage_Con_CaptureGameScreenshot 0xd3
+#define HidUsage_Con_ShoworHideRecordingIndicator 0xd4
+#define HidUsage_Con_StartorStopMicrophoneCapture 0xd5
+#define HidUsage_Con_StartorStopCameraCapture 0xd6
+#define HidUsage_Con_StartorStopGameBroadcast 0xd7
+#define HidUsage_Con_StartorStopVoiceDictationSession 0xd8
+#define HidUsage_Con_InvokeDismissEmojiPicker 0xd9
+#define HidUsage_Con_Volume 0xe0
+#define HidUsage_Con_Balance 0xe1
+#define HidUsage_Con_Mute 0xe2
+#define HidUsage_Con_Bass 0xe3
+#define HidUsage_Con_Treble 0xe4
+#define HidUsage_Con_BassBoost 0xe5
+#define HidUsage_Con_SurroundMode 0xe6
+#define HidUsage_Con_Loudness 0xe7
+#define HidUsage_Con_MPX 0xe8
+#define HidUsage_Con_VolumeIncrement 0xe9
+#define HidUsage_Con_VolumeDecrement 0xea
+#define HidUsage_Con_SpeedSelect 0xf0
+#define HidUsage_Con_PlaybackSpeed 0xf1
+#define HidUsage_Con_StandardPlay 0xf2
+#define HidUsage_Con_LongPlay 0xf3
+#define HidUsage_Con_ExtendedPlay 0xf4
+#define HidUsage_Con_Slow 0xf5
+#define HidUsage_Con_FanEnable 0x100
+#define HidUsage_Con_FanSpeed 0x101
+#define HidUsage_Con_LightEnable 0x102
+#define HidUsage_Con_LightIlluminationLevel 0x103
+#define HidUsage_Con_ClimateControlEnable 0x104
+#define HidUsage_Con_RoomTemperature 0x105
+#define HidUsage_Con_SecurityEnable 0x106
+#define HidUsage_Con_FireAlarm 0x107
+#define HidUsage_Con_PoliceAlarm 0x108
+#define HidUsage_Con_Proximity 0x109
+#define HidUsage_Con_Motion 0x10a
+#define HidUsage_Con_DuressAlarm 0x10b
+#define HidUsage_Con_HoldupAlarm 0x10c
+#define HidUsage_Con_MedicalAlarm 0x10d
+#define HidUsage_Con_BalanceRight 0x150
+#define HidUsage_Con_BalanceLeft 0x151
+#define HidUsage_Con_BassIncrement 0x152
+#define HidUsage_Con_BassDecrement 0x153
+#define HidUsage_Con_TrebleIncrement 0x154
+#define HidUsage_Con_TrebleDecrement 0x155
+#define HidUsage_Con_SpeakerSystem 0x160
+#define HidUsage_Con_ChannelLeft 0x161
+#define HidUsage_Con_ChannelRight 0x162
+#define HidUsage_Con_ChannelCenter 0x163
+#define HidUsage_Con_ChannelFront 0x164
+#define HidUsage_Con_ChannelCenterFront 0x165
+#define HidUsage_Con_ChannelSide 0x166
+#define HidUsage_Con_ChannelSurround 0x167
+#define HidUsage_Con_ChannelLowFrequencyEnhancement 0x168
+#define HidUsage_Con_ChannelTop 0x169
+#define HidUsage_Con_ChannelUnknown 0x16a
+#define HidUsage_Con_Subchannel 0x170
+#define HidUsage_Con_SubchannelIncrement 0x171
+#define HidUsage_Con_SubchannelDecrement 0x172
+#define HidUsage_Con_AlternateAudioIncrement 0x173
+#define HidUsage_Con_AlternateAudioDecrement 0x174
+#define HidUsage_Con_ApplicationLaunchButtons 0x180
+#define HidUsage_Con_ALLaunchButtonConfigurationTool 0x181
+#define HidUsage_Con_ALProgrammableButtonConfiguration 0x182
+#define HidUsage_Con_ALConsumerControlConfiguration 0x183
+#define HidUsage_Con_ALWordProcessor 0x184
+#define HidUsage_Con_ALTextEditor 0x185
+#define HidUsage_Con_ALSpreadsheet 0x186
+#define HidUsage_Con_ALGraphicsEditor 0x187
+#define HidUsage_Con_ALPresentationApp 0x188
+#define HidUsage_Con_ALDatabaseApp 0x189
+#define HidUsage_Con_ALEmailReader 0x18a
+#define HidUsage_Con_ALNewsreader 0x18b
+#define HidUsage_Con_ALVoicemail 0x18c
+#define HidUsage_Con_ALContactsAddressBook 0x18d
+#define HidUsage_Con_ALCalendarSchedule 0x18e
+#define HidUsage_Con_ALTaskProjectManager 0x18f
+#define HidUsage_Con_ALLogJournalTimecard 0x190
+#define HidUsage_Con_ALCheckbookFinance 0x191
+#define HidUsage_Con_ALCalculator 0x192
+#define HidUsage_Con_ALAVCapturePlayback 0x193
+#define HidUsage_Con_ALLocalMachineBrowser 0x194
+#define HidUsage_Con_ALLANWANBrowser 0x195
+#define HidUsage_Con_ALInternetBrowser 0x196
+#define HidUsage_Con_ALRemoteNetworkingISPConnect 0x197
+#define HidUsage_Con_ALNetworkConference 0x198
+#define HidUsage_Con_ALNetworkChat 0x199
+#define HidUsage_Con_ALTelephonyDialer 0x19a
+#define HidUsage_Con_ALLogon 0x19b
+#define HidUsage_Con_ALLogoff 0x19c
+#define HidUsage_Con_ALLogonLogoff 0x19d
+#define HidUsage_Con_ALTerminalLockScreensaver 0x19e
+#define HidUsage_Con_ALControlPanel 0x19f
+#define HidUsage_Con_ALCommandLineProcessorRun 0x1a0
+#define HidUsage_Con_ALProcessTaskManager 0x1a1
+#define HidUsage_Con_ALSelectTaskApplication 0x1a2
+#define HidUsage_Con_ALNextTaskApplication 0x1a3
+#define HidUsage_Con_ALPreviousTaskApplication 0x1a4
+#define HidUsage_Con_ALPreemptiveHaltTaskApplication 0x1a5
+#define HidUsage_Con_ALIntegratedHelpCenter 0x1a6
+#define HidUsage_Con_ALDocuments 0x1a7
+#define HidUsage_Con_ALThesaurus 0x1a8
+#define HidUsage_Con_ALDictionary 0x1a9
+#define HidUsage_Con_ALDesktop 0x1aa
+#define HidUsage_Con_ALSpellCheck 0x1ab
+#define HidUsage_Con_ALGrammarCheck 0x1ac
+#define HidUsage_Con_ALWirelessStatus 0x1ad
+#define HidUsage_Con_ALKeyboardLayout 0x1ae
+#define HidUsage_Con_ALVirusProtection 0x1af
+#define HidUsage_Con_ALEncryption 0x1b0
+#define HidUsage_Con_ALScreenSaver 0x1b1
+#define HidUsage_Con_ALAlarms 0x1b2
+#define HidUsage_Con_ALClock 0x1b3
+#define HidUsage_Con_ALFileBrowser 0x1b4
+#define HidUsage_Con_ALPowerStatus 0x1b5
+#define HidUsage_Con_ALImageBrowser 0x1b6
+#define HidUsage_Con_ALAudioBrowser 0x1b7
+#define HidUsage_Con_ALMovieBrowser 0x1b8
+#define HidUsage_Con_ALDigitalRightsManager 0x1b9
+#define HidUsage_Con_ALDigitalWallet 0x1ba
+#define HidUsage_Con_ALInstantMessaging 0x1bc
+#define HidUsage_Con_ALOEMFeaturesTipsTutorialBrowser 0x1bd
+#define HidUsage_Con_ALOEMHelp 0x1be
+#define HidUsage_Con_ALOnlineCommunity 0x1bf
+#define HidUsage_Con_ALEntertainmentContentBrowser 0x1c0
+#define HidUsage_Con_ALOnlineShoppingBrowser 0x1c1
+#define HidUsage_Con_ALSmartCardInformationHelp 0x1c2
+#define HidUsage_Con_ALMarketMonitorFinanceBrowser 0x1c3
+#define HidUsage_Con_ALCustomizedCorporateNewsBrowser 0x1c4
+#define HidUsage_Con_ALOnlineActivityBrowser 0x1c5
+#define HidUsage_Con_ALResearchSearchBrowser 0x1c6
+#define HidUsage_Con_ALAudioPlayer 0x1c7
+#define HidUsage_Con_ALMessageStatus 0x1c8
+#define HidUsage_Con_ALContactSync 0x1c9
+#define HidUsage_Con_ALNavigation 0x1ca
+#define HidUsage_Con_ALContextawareDesktopAssistant 0x1cb
+#define HidUsage_Con_GenericGUIApplicationControls 0x200
+#define HidUsage_Con_ACNew 0x201
+#define HidUsage_Con_ACOpen 0x202
+#define HidUsage_Con_ACClose 0x203
+#define HidUsage_Con_ACExit 0x204
+#define HidUsage_Con_ACMaximize 0x205
+#define HidUsage_Con_ACMinimize 0x206
+#define HidUsage_Con_ACSave 0x207
+#define HidUsage_Con_ACPrint 0x208
+#define HidUsage_Con_ACProperties 0x209
+#define HidUsage_Con_ACUndo 0x21a
+#define HidUsage_Con_ACCopy 0x21b
+#define HidUsage_Con_ACCut 0x21c
+#define HidUsage_Con_ACPaste 0x21d
+#define HidUsage_Con_ACSelectAll 0x21e
+#define HidUsage_Con_ACFind 0x21f
+#define HidUsage_Con_ACFindandReplace 0x220
+#define HidUsage_Con_ACSearch 0x221
+#define HidUsage_Con_ACGoTo 0x222
+#define HidUsage_Con_ACHome 0x223
+#define HidUsage_Con_ACBack 0x224
+#define HidUsage_Con_ACForward 0x225
+#define HidUsage_Con_ACStop 0x226
+#define HidUsage_Con_ACRefresh 0x227
+#define HidUsage_Con_ACPreviousLink 0x228
+#define HidUsage_Con_ACNextLink 0x229
+#define HidUsage_Con_ACBookmarks 0x22a
+#define HidUsage_Con_ACHistory 0x22b
+#define HidUsage_Con_ACSubscriptions 0x22c
+#define HidUsage_Con_ACZoomIn 0x22d
+#define HidUsage_Con_ACZoomOut 0x22e
+#define HidUsage_Con_ACZoom 0x22f
+#define HidUsage_Con_ACFullScreenView 0x230
+#define HidUsage_Con_ACNormalView 0x231
+#define HidUsage_Con_ACViewToggle 0x232
+#define HidUsage_Con_ACScrollUp 0x233
+#define HidUsage_Con_ACScrollDown 0x234
+#define HidUsage_Con_ACScroll 0x235
+#define HidUsage_Con_ACPanLeft 0x236
+#define HidUsage_Con_ACPanRight 0x237
+#define HidUsage_Con_ACPan 0x238
+#define HidUsage_Con_ACNewWindow 0x239
+#define HidUsage_Con_ACTileHorizontally 0x23a
+#define HidUsage_Con_ACTileVertically 0x23b
+#define HidUsage_Con_ACFormat 0x23c
+#define HidUsage_Con_ACEdit 0x23d
+#define HidUsage_Con_ACBold 0x23e
+#define HidUsage_Con_ACItalics 0x23f
+#define HidUsage_Con_ACUnderline 0x240
+#define HidUsage_Con_ACStrikethrough 0x241
+#define HidUsage_Con_ACSubscript 0x242
+#define HidUsage_Con_ACSuperscript 0x243
+#define HidUsage_Con_ACAllCaps 0x244
+#define HidUsage_Con_ACRotate 0x245
+#define HidUsage_Con_ACResize 0x246
+#define HidUsage_Con_ACFlipHorizontal 0x247
+#define HidUsage_Con_ACFlipVertical 0x248
+#define HidUsage_Con_ACMirrorHorizontal 0x249
+#define HidUsage_Con_ACMirrorVertical 0x24a
+#define HidUsage_Con_ACFontSelect 0x24b
+#define HidUsage_Con_ACFontColor 0x24c
+#define HidUsage_Con_ACFontSize 0x24d
+#define HidUsage_Con_ACJustifyLeft 0x24e
+#define HidUsage_Con_ACJustifyCenterH 0x24f
+#define HidUsage_Con_ACJustifyRight 0x250
+#define HidUsage_Con_ACJustifyBlockH 0x251
+#define HidUsage_Con_ACJustifyTop 0x252
+#define HidUsage_Con_ACJustifyCenterV 0x253
+#define HidUsage_Con_ACJustifyBottom 0x254
+#define HidUsage_Con_ACJustifyBlockV 0x255
+#define HidUsage_Con_ACIndentDecrease 0x256
+#define HidUsage_Con_ACIndentIncrease 0x257
+#define HidUsage_Con_ACNumberedList 0x258
+#define HidUsage_Con_ACRestartNumbering 0x259
+#define HidUsage_Con_ACBulletedList 0x25a
+#define HidUsage_Con_ACPromote 0x25b
+#define HidUsage_Con_ACDemote 0x25c
+#define HidUsage_Con_ACYes 0x25d
+#define HidUsage_Con_ACNo 0x25e
+#define HidUsage_Con_ACCancel 0x25f
+#define HidUsage_Con_ACCatalog 0x260
+#define HidUsage_Con_ACBuyCheckout 0x261
+#define HidUsage_Con_ACAddtoCart 0x262
+#define HidUsage_Con_ACExpand 0x263
+#define HidUsage_Con_ACExpandAll 0x264
+#define HidUsage_Con_ACCollapse 0x265
+#define HidUsage_Con_ACCollapseAll 0x266
+#define HidUsage_Con_ACPrintPreview 0x267
+#define HidUsage_Con_ACPasteSpecial 0x268
+#define HidUsage_Con_ACInsertMode 0x269
+#define HidUsage_Con_ACDelete 0x26a
+#define HidUsage_Con_ACLock 0x26b
+#define HidUsage_Con_ACUnlock 0x26c
+#define HidUsage_Con_ACProtect 0x26d
+#define HidUsage_Con_ACUnprotect 0x26e
+#define HidUsage_Con_ACAttachComment 0x26f
+#define HidUsage_Con_ACDeleteComment 0x270
+#define HidUsage_Con_ACViewComment 0x271
+#define HidUsage_Con_ACSelectWord 0x272
+#define HidUsage_Con_ACSelectSentence 0x273
+#define HidUsage_Con_ACSelectParagraph 0x274
+#define HidUsage_Con_ACSelectColumn 0x275
+#define HidUsage_Con_ACSelectRow 0x276
+#define HidUsage_Con_ACSelectTable 0x277
+#define HidUsage_Con_ACSelectObject 0x278
+#define HidUsage_Con_ACRedoRepeat 0x279
+#define HidUsage_Con_ACSort 0x27a
+#define HidUsage_Con_ACSortAscending 0x27b
+#define HidUsage_Con_ACSortDescending 0x27c
+#define HidUsage_Con_ACFilter 0x27d
+#define HidUsage_Con_ACSetClock 0x27e
+#define HidUsage_Con_ACViewClock 0x27f
+#define HidUsage_Con_ACSelectTimeZone 0x280
+#define HidUsage_Con_ACEditTimeZones 0x281
+#define HidUsage_Con_ACSetAlarm 0x282
+#define HidUsage_Con_ACClearAlarm 0x283
+#define HidUsage_Con_ACSnoozeAlarm 0x284
+#define HidUsage_Con_ACResetAlarm 0x285
+#define HidUsage_Con_ACSynchronize 0x286
+#define HidUsage_Con_ACSendReceive 0x287
+#define HidUsage_Con_ACSendTo 0x288
+#define HidUsage_Con_ACReply 0x289
+#define HidUsage_Con_ACReplyAll 0x28a
+#define HidUsage_Con_ACForwardMsg 0x28b
+#define HidUsage_Con_ACSend 0x28c
+#define HidUsage_Con_ACAttachFile 0x28d
+#define HidUsage_Con_ACUpload 0x28e
+#define HidUsage_Con_ACDownloadSaveTargetAs 0x28f
+#define HidUsage_Con_ACSetBorders 0x290
+#define HidUsage_Con_ACInsertRow 0x291
+#define HidUsage_Con_ACInsertColumn 0x292
+#define HidUsage_Con_ACInsertFile 0x293
+#define HidUsage_Con_ACInsertPicture 0x294
+#define HidUsage_Con_ACInsertObject 0x295
+#define HidUsage_Con_ACInsertSymbol 0x296
+#define HidUsage_Con_ACSaveandClose 0x297
+#define HidUsage_Con_ACRename 0x298
+#define HidUsage_Con_ACMerge 0x299
+#define HidUsage_Con_ACSplit 0x29a
+#define HidUsage_Con_ACDisributeHorizontally 0x29b
+#define HidUsage_Con_ACDistributeVertically 0x29c
+#define HidUsage_Con_ACNextKeyboardLayoutSelect 0x29d
+#define HidUsage_Con_ACNavigationGuidance 0x29e
+#define HidUsage_Con_ACDesktopShowAllWindows 0x29f
+#define HidUsage_Con_ACSoftKeyLeft 0x2a0
+#define HidUsage_Con_ACSoftKeyRight 0x2a1
+#define HidUsage_Con_ACDesktopShowAllApplications 0x2a2
+#define HidUsage_Con_ACIdleKeepAlive 0x2b0
+#define HidUsage_Con_ExtendedKeyboardAttributesCollection 0x2c0
+#define HidUsage_Con_KeyboardFormFactor 0x2c1
+#define HidUsage_Con_KeyboardKeyType 0x2c2
+#define HidUsage_Con_KeyboardPhysicalLayout 0x2c3
+#define HidUsage_Con_VendorSpecificKeyboardPhysicalLayout 0x2c4
+#define HidUsage_Con_KeyboardIETFLanguageTagIndex 0x2c5
+#define HidUsage_Con_ImplementedKeyboardInputAssistControls 0x2c6
+#define HidUsage_Con_KeyboardInputAssistPrevious 0x2c7
+#define HidUsage_Con_KeyboardInputAssistNext 0x2c8
+#define HidUsage_Con_KeyboardInputAssistPreviousGroup 0x2c9
+#define HidUsage_Con_KeyboardInputAssistNextGroup 0x2ca
+#define HidUsage_Con_KeyboardInputAssistAccept 0x2cb
+#define HidUsage_Con_KeyboardInputAssistCancel 0x2cc
+#define HidUsage_Con_PrivacyScreenToggle 0x2d0
+#define HidUsage_Con_PrivacyScreenLevelDecrement 0x2d1
+#define HidUsage_Con_PrivacyScreenLevelIncrement 0x2d2
+#define HidUsage_Con_PrivacyScreenLevelMinimum 0x2d3
+#define HidUsage_Con_PrivacyScreenLevelMaximum 0x2d4
+#define HidUsage_Con_ContactEdited 0x500
+#define HidUsage_Con_ContactAdded 0x501
+#define HidUsage_Con_ContactRecordActive 0x502
+#define HidUsage_Con_ContactIndex 0x503
+#define HidUsage_Con_ContactNickname 0x504
+#define HidUsage_Con_ContactFirstName 0x505
+#define HidUsage_Con_ContactLastName 0x506
+#define HidUsage_Con_ContactFullName 0x507
+#define HidUsage_Con_ContactPhoneNumberPersonal 0x508
+#define HidUsage_Con_ContactPhoneNumberBusiness 0x509
+#define HidUsage_Con_ContactPhoneNumberMobile 0x50a
+#define HidUsage_Con_ContactPhoneNumberPager 0x50b
+#define HidUsage_Con_ContactPhoneNumberFax 0x50c
+#define HidUsage_Con_ContactPhoneNumberOther 0x50d
+#define HidUsage_Con_ContactEmailPersonal 0x50e
+#define HidUsage_Con_ContactEmailBusiness 0x50f
+#define HidUsage_Con_ContactEmailOther 0x510
+#define HidUsage_Con_ContactEmailMain 0x511
+#define HidUsage_Con_ContactSpeedDialNumber 0x512
+#define HidUsage_Con_ContactStatusFlag 0x513
+#define HidUsage_Con_ContactMisc 0x514
+#define HidUsage_Dig_Digitizer 0x01
+#define HidUsage_Dig_Pen 0x02
+#define HidUsage_Dig_LightPen 0x03
+#define HidUsage_Dig_TouchScreen 0x04
+#define HidUsage_Dig_TouchPad 0x05
+#define HidUsage_Dig_Whiteboard 0x06
+#define HidUsage_Dig_CoordinateMeasuringMachine 0x07
+#define HidUsage_Dig_ThreeDDigitizer 0x08
+#define HidUsage_Dig_StereoPlotter 0x09
+#define HidUsage_Dig_ArticulatedArm 0x0a
+#define HidUsage_Dig_Armature 0x0b
+#define HidUsage_Dig_MultiplePointDigitizer 0x0c
+#define HidUsage_Dig_FreeSpaceWand 0x0d
+#define HidUsage_Dig_DeviceConfiguration 0x0e
+#define HidUsage_Dig_CapacitiveHeatMapDigitizer 0x0f
+#define HidUsage_Dig_Stylus 0x20
+#define HidUsage_Dig_Puck 0x21
+#define HidUsage_Dig_Finger 0x22
+#define HidUsage_Dig_Devicesettings 0x23
+#define HidUsage_Dig_CharacterGesture 0x24
+#define HidUsage_Dig_TipPressure 0x30
+#define HidUsage_Dig_BarrelPressure 0x31
+#define HidUsage_Dig_InRange 0x32
+#define HidUsage_Dig_Touch 0x33
+#define HidUsage_Dig_Untouch 0x34
+#define HidUsage_Dig_Tap 0x35
+#define HidUsage_Dig_Quality 0x36
+#define HidUsage_Dig_DataValid 0x37
+#define HidUsage_Dig_TransducerIndex 0x38
+#define HidUsage_Dig_TabletFunctionKeys 0x39
+#define HidUsage_Dig_ProgramChangeKeys 0x3a
+#define HidUsage_Dig_BatteryStrength 0x3b
+#define HidUsage_Dig_Invert 0x3c
+#define HidUsage_Dig_XTilt 0x3d
+#define HidUsage_Dig_YTilt 0x3e
+#define HidUsage_Dig_Azimuth 0x3f
+#define HidUsage_Dig_Altitude 0x40
+#define HidUsage_Dig_Twist 0x41
+#define HidUsage_Dig_TipSwitch 0x42
+#define HidUsage_Dig_SecondaryTipSwitch 0x43
+#define HidUsage_Dig_BarrelSwitch 0x44
+#define HidUsage_Dig_Eraser 0x45
+#define HidUsage_Dig_TabletPick 0x46
+#define HidUsage_Dig_TouchValid 0x47
+#define HidUsage_Dig_Width 0x48
+#define HidUsage_Dig_Height 0x49
+#define HidUsage_Dig_ContactIdentifier 0x51
+#define HidUsage_Dig_DeviceMode 0x52
+#define HidUsage_Dig_DeviceIdentifier 0x53
+#define HidUsage_Dig_ContactCount 0x54
+#define HidUsage_Dig_ContactCountMaximum 0x55
+#define HidUsage_Dig_ScanTime 0x56
+#define HidUsage_Dig_SurfaceSwitch 0x57
+#define HidUsage_Dig_ButtonSwitch 0x58
+#define HidUsage_Dig_PadType 0x59
+#define HidUsage_Dig_SecondaryBarrelSwitch 0x5a
+#define HidUsage_Dig_TransducerSerialNumber 0x5b
+#define HidUsage_Dig_PreferredColor 0x5c
+#define HidUsage_Dig_PreferredColorisLocked 0x5d
+#define HidUsage_Dig_PreferredLineWidth 0x5e
+#define HidUsage_Dig_PreferredLineWidthisLocked 0x5f
+#define HidUsage_Dig_LatencyMode 0x60
+#define HidUsage_Dig_GestureCharacterQuality 0x61
+#define HidUsage_Dig_CharacterGestureDataLength 0x62
+#define HidUsage_Dig_CharacterGestureData 0x63
+#define HidUsage_Dig_GestureCharacterEncoding 0x64
+#define HidUsage_Dig_UTF8CharacterGestureEncoding 0x65
+#define HidUsage_Dig_UTF16LittleEndianCharacterGestureEncoding 0x66
+#define HidUsage_Dig_UTF16BigEndianCharacterGestureEncoding 0x67
+#define HidUsage_Dig_UTF32LittleEndianCharacterGestureEncoding 0x68
+#define HidUsage_Dig_UTF32BigEndianCharacterGestureEncoding 0x69
+#define HidUsage_Dig_CapacitiveHeatMapProtocolVendorID 0x6a
+#define HidUsage_Dig_CapacitiveHeatMapProtocolVersion 0x6b
+#define HidUsage_Dig_CapacitiveHeatMapFrameData 0x6c
+#define HidUsage_Dig_GestureCharacterEnable 0x6d
+#define HidUsage_Dig_TransducerSerialNumberPart2 0x6e
+#define HidUsage_Dig_NoPreferredColor 0x6f
+#define HidUsage_Dig_PreferredLineStyle 0x70
+#define HidUsage_Dig_PreferredLineStyleisLocked 0x71
+#define HidUsage_Dig_Ink 0x72
+#define HidUsage_Dig_Pencil 0x73
+#define HidUsage_Dig_Highlighter 0x74
+#define HidUsage_Dig_ChiselMarker 0x75
+#define HidUsage_Dig_Brush 0x76
+#define HidUsage_Dig_NoPreference 0x77
+#define HidUsage_Dig_DigitizerDiagnostic 0x80
+#define HidUsage_Dig_DigitizerError 0x81
+#define HidUsage_Dig_ErrNormalStatus 0x82
+#define HidUsage_Dig_ErrTransducersExceeded 0x83
+#define HidUsage_Dig_ErrFullTransFeaturesUnavailable 0x84
+#define HidUsage_Dig_ErrChargeLow 0x85
+#define HidUsage_Dig_TransducerSoftwareInfo 0x90
+#define HidUsage_Dig_TransducerVendorId 0x91
+#define HidUsage_Dig_TransducerProductId 0x92
+#define HidUsage_Dig_DeviceSupportedProtocols 0x93
+#define HidUsage_Dig_TransducerSupportedProtocols 0x94
+#define HidUsage_Dig_NoProtocol 0x95
+#define HidUsage_Dig_WacomAESProtocol 0x96
+#define HidUsage_Dig_USIProtocol 0x97
+#define HidUsage_Dig_MicrosoftPenProtocol 0x98
+#define HidUsage_Dig_SupportedReportRates 0xa0
+#define HidUsage_Dig_ReportRate 0xa1
+#define HidUsage_Dig_TransducerConnected 0xa2
+#define HidUsage_Dig_SwitchDisabled 0xa3
+#define HidUsage_Dig_SwitchUnimplemented 0xa4
+#define HidUsage_Dig_TransducerSwitches 0xa5
+#define HidUsage_Dig_TransducerIndexSelector 0xa6
+#define HidUsage_Dig_ButtonPressThreshold 0xb0
+#define HidUsage_Hap_SimpleHapticController 0x01
+#define HidUsage_Hap_WaveformList 0x10
+#define HidUsage_Hap_DurationList 0x11
+#define HidUsage_Hap_AutoTrigger 0x20
+#define HidUsage_Hap_ManualTrigger 0x21
+#define HidUsage_Hap_AutoTriggerAssociatedControl 0x22
+#define HidUsage_Hap_Intensity 0x23
+#define HidUsage_Hap_RepeatCount 0x24
+#define HidUsage_Hap_RetriggerPeriod 0x25
+#define HidUsage_Hap_WaveformVendorPage 0x26
+#define HidUsage_Hap_WaveformVendorID 0x27
+#define HidUsage_Hap_WaveformCutoffTime 0x28
+#define HidUsage_Hap_WaveformNone 0x1001
+#define HidUsage_Hap_WaveformStop 0x1002
+#define HidUsage_Hap_WaveformClick 0x1003
+#define HidUsage_Hap_WaveformBuzzContinuous 0x1004
+#define HidUsage_Hap_WaveformRumbleContinuous 0x1005
+#define HidUsage_Hap_WaveformPress 0x1006
+#define HidUsage_Hap_WaveformRelease 0x1007
+#define HidUsage_Hap_WaveformHover 0x1008
+#define HidUsage_Hap_WaveformSuccess 0x1009
+#define HidUsage_Hap_WaveformError 0x100a
+#define HidUsage_Hap_WaveformInkContinuous 0x100b
+#define HidUsage_Hap_WaveformPencilContinuous 0x100c
+#define HidUsage_Hap_WaveformMarkerContinuous 0x100d
+#define HidUsage_Hap_WaveformChiselMarkerContinuous 0x100e
+#define HidUsage_Hap_WaveformBrushContinuous 0x100f
+#define HidUsage_Hap_WaveformEraserContinuous 0x1010
+#define HidUsage_Hap_WaveformSparkleContinuous 0x1011
+#define HidUsage_PID_PhysicalInputDevice 0x01
+#define HidUsage_PID_Normal 0x20
+#define HidUsage_PID_SetEffectReport 0x21
+#define HidUsage_PID_EffectParameterBlockIndex 0x22
+#define HidUsage_PID_ParameterBlockOffset 0x23
+#define HidUsage_PID_ROMFlag 0x24
+#define HidUsage_PID_EffectType 0x25
+#define HidUsage_PID_ETConstantForce 0x26
+#define HidUsage_PID_ETRamp 0x27
+#define HidUsage_PID_ETCustomForce 0x28
+#define HidUsage_PID_ETSquare 0x30
+#define HidUsage_PID_ETSine 0x31
+#define HidUsage_PID_ETTriangle 0x32
+#define HidUsage_PID_ETSawtoothUp 0x33
+#define HidUsage_PID_ETSawtoothDown 0x34
+#define HidUsage_PID_ETSpring 0x40
+#define HidUsage_PID_ETDamper 0x41
+#define HidUsage_PID_ETInertia 0x42
+#define HidUsage_PID_ETFriction 0x43
+#define HidUsage_PID_Duration 0x50
+#define HidUsage_PID_SamplePeriod 0x51
+#define HidUsage_PID_Gain 0x52
+#define HidUsage_PID_TriggerButton 0x53
+#define HidUsage_PID_TriggerRepeatInterval 0x54
+#define HidUsage_PID_AxesEnable 0x55
+#define HidUsage_PID_DirectionEnable 0x56
+#define HidUsage_PID_Direction 0x57
+#define HidUsage_PID_TypeSpecificBlockOffset 0x58
+#define HidUsage_PID_BlockType 0x59
+#define HidUsage_PID_SetEnvelopeReport 0x5a
+#define HidUsage_PID_AttackLevel 0x5b
+#define HidUsage_PID_AttackTime 0x5c
+#define HidUsage_PID_FadeLevel 0x5d
+#define HidUsage_PID_FadeTime 0x5e
+#define HidUsage_PID_SetConditionReport 0x5f
+#define HidUsage_PID_CenterPointOffset 0x60
+#define HidUsage_PID_PositiveCoefficient 0x61
+#define HidUsage_PID_NegativeCoefficient 0x62
+#define HidUsage_PID_PositiveSaturation 0x63
+#define HidUsage_PID_NegativeSaturation 0x64
+#define HidUsage_PID_DeadBand 0x65
+#define HidUsage_PID_DownloadForceSample 0x66
+#define HidUsage_PID_IsochCustomForceEnable 0x67
+#define HidUsage_PID_CustomForceDataReport 0x68
+#define HidUsage_PID_CustomForceData 0x69
+#define HidUsage_PID_CustomForceVendorDefinedData 0x6a
+#define HidUsage_PID_SetCustomForceReport 0x6b
+#define HidUsage_PID_CustomForceDataOffset 0x6c
+#define HidUsage_PID_SampleCount 0x6d
+#define HidUsage_PID_SetPeriodicReport 0x6e
+#define HidUsage_PID_Offset 0x6f
+#define HidUsage_PID_Magnitude 0x70
+#define HidUsage_PID_Phase 0x71
+#define HidUsage_PID_Period 0x72
+#define HidUsage_PID_SetConstantForceReport 0x73
+#define HidUsage_PID_SetRampForceReport 0x74
+#define HidUsage_PID_RampStart 0x75
+#define HidUsage_PID_RampEnd 0x76
+#define HidUsage_PID_EffectOperationReport 0x77
+#define HidUsage_PID_EffectOperation 0x78
+#define HidUsage_PID_OpEffectStart 0x79
+#define HidUsage_PID_OpEffectStartSolo 0x7a
+#define HidUsage_PID_OpEffectStop 0x7b
+#define HidUsage_PID_LoopCount 0x7c
+#define HidUsage_PID_DeviceGainReport 0x7d
+#define HidUsage_PID_DeviceGain 0x7e
+#define HidUsage_PID_ParameterBlockPoolsReport 0x7f
+#define HidUsage_PID_RAMPoolSize 0x80
+#define HidUsage_PID_ROMPoolSize 0x81
+#define HidUsage_PID_ROMEffectBlockCount 0x82
+#define HidUsage_PID_SimultaneousEffectsMax 0x83
+#define HidUsage_PID_PoolAlignment 0x84
+#define HidUsage_PID_ParameterBlockMoveReport 0x85
+#define HidUsage_PID_MoveSource 0x86
+#define HidUsage_PID_MoveDestination 0x87
+#define HidUsage_PID_MoveLength 0x88
+#define HidUsage_PID_EffectParameterBlockLoadReport 0x89
+#define HidUsage_PID_EffectParameterBlockLoadStatus 0x8b
+#define HidUsage_PID_BlockLoadSuccess 0x8c
+#define HidUsage_PID_BlockLoadFull 0x8d
+#define HidUsage_PID_BlockLoadError 0x8e
+#define HidUsage_PID_BlockHandle 0x8f
+#define HidUsage_PID_EffectParameterBlockFreeReport 0x90
+#define HidUsage_PID_TypeSpecificBlockHandle 0x91
+#define HidUsage_PID_PIDStateReport 0x92
+#define HidUsage_PID_EffectPlaying 0x94
+#define HidUsage_PID_PIDDeviceControlReport 0x95
+#define HidUsage_PID_PIDDeviceControl 0x96
+#define HidUsage_PID_DCEnableActuators 0x97
+#define HidUsage_PID_DCDisableActuators 0x98
+#define HidUsage_PID_DCStopAllEffects 0x99
+#define HidUsage_PID_DCReset 0x9a
+#define HidUsage_PID_DCPause 0x9b
+#define HidUsage_PID_DCContinue 0x9c
+#define HidUsage_PID_DevicePaused 0x9f
+#define HidUsage_PID_ActuatorsEnabled 0xa0
+#define HidUsage_PID_SafetySwitch 0xa4
+#define HidUsage_PID_ActuatorOverrideSwitch 0xa5
+#define HidUsage_PID_ActuatorPower 0xa6
+#define HidUsage_PID_StartDelay 0xa7
+#define HidUsage_PID_ParameterBlockSize 0xa8
+#define HidUsage_PID_DeviceManagedPool 0xa9
+#define HidUsage_PID_SharedParameterBlocks 0xaa
+#define HidUsage_PID_CreateNewEffectParameterBlockReport 0xab
+#define HidUsage_PID_RAMPoolAvailable 0xac
+#define HidUsage_SC_SocControl 0x01
+#define HidUsage_SC_FirmwareTransfer 0x02
+#define HidUsage_SC_FirmwareFileId 0x03
+#define HidUsage_SC_FileOffsetInBytes 0x04
+#define HidUsage_SC_FileTransferSizeMaxInBytes 0x05
+#define HidUsage_SC_FilePayload 0x06
+#define HidUsage_SC_FilePayloadSizeInBytes 0x07
+#define HidUsage_SC_FilePayloadContainsLastBytes 0x08
+#define HidUsage_SC_FileTransferStop 0x09
+#define HidUsage_SC_FileTransferTillEnd 0x0a
+#define HidUsage_EHT_EyeTracker 0x01
+#define HidUsage_EHT_HeadTracker 0x02
+#define HidUsage_EHT_TrackingData 0x10
+#define HidUsage_EHT_Capabilities 0x11
+#define HidUsage_EHT_Configuration 0x12
+#define HidUsage_EHT_Status 0x13
+#define HidUsage_EHT_Control 0x14
+#define HidUsage_EHT_SensorTimestamp 0x20
+#define HidUsage_EHT_PositionX 0x21
+#define HidUsage_EHT_PositionY 0x22
+#define HidUsage_EHT_PositionZ 0x23
+#define HidUsage_EHT_GazePoint 0x24
+#define HidUsage_EHT_LeftEyePosition 0x25
+#define HidUsage_EHT_RightEyePosition 0x26
+#define HidUsage_EHT_HeadPosition 0x27
+#define HidUsage_EHT_HeadDirectionPoint 0x28
+#define HidUsage_EHT_RotationaboutXaxis 0x29
+#define HidUsage_EHT_RotationaboutYaxis 0x2a
+#define HidUsage_EHT_RotationaboutZaxis 0x2b
+#define HidUsage_EHT_TrackerQuality 0x100
+#define HidUsage_EHT_MinimumTrackingDistance 0x101
+#define HidUsage_EHT_OptimumTrackingDistance 0x102
+#define HidUsage_EHT_MaximumTrackingDistance 0x103
+#define HidUsage_EHT_MaximumScreenPlaneWidth 0x104
+#define HidUsage_EHT_MaximumScreenPlaneHeight 0x105
+#define HidUsage_EHT_DisplayManufacturerID 0x200
+#define HidUsage_EHT_DisplayProductID 0x201
+#define HidUsage_EHT_DisplaySerialNumber 0x202
+#define HidUsage_EHT_DisplayManufacturerDate 0x203
+#define HidUsage_EHT_CalibratedScreenWidth 0x204
+#define HidUsage_EHT_CalibratedScreenHeight 0x205
+#define HidUsage_EHT_SamplingFrequency 0x300
+#define HidUsage_EHT_ConfigurationStatus 0x301
+#define HidUsage_EHT_DeviceModeRequest 0x400
+#define HidUsage_AD_AlphanumericDisplay 0x01
+#define HidUsage_AD_AuxiliaryDisplay 0x02
+#define HidUsage_AD_DisplayAttributesReport 0x20
+#define HidUsage_AD_ASCIICharacterSet 0x21
+#define HidUsage_AD_DataReadBack 0x22
+#define HidUsage_AD_FontReadBack 0x23
+#define HidUsage_AD_DisplayControlReport 0x24
+#define HidUsage_AD_ClearDisplay 0x25
+#define HidUsage_AD_DisplayEnable 0x26
+#define HidUsage_AD_ScreenSaverDelay 0x27
+#define HidUsage_AD_ScreenSaverEnable 0x28
+#define HidUsage_AD_VerticalScroll 0x29
+#define HidUsage_AD_HorizontalScroll 0x2a
+#define HidUsage_AD_CharacterReport 0x2b
+#define HidUsage_AD_DisplayData 0x2c
+#define HidUsage_AD_DisplayStatus 0x2d
+#define HidUsage_AD_StatNotReady 0x2e
+#define HidUsage_AD_StatReady 0x2f
+#define HidUsage_AD_ErrNotaloadablecharacter 0x30
+#define HidUsage_AD_ErrFontdatacannotberead 0x31
+#define HidUsage_AD_CursorPositionReport 0x32
+#define HidUsage_AD_Row 0x33
+#define HidUsage_AD_Column 0x34
+#define HidUsage_AD_Rows 0x35
+#define HidUsage_AD_Columns 0x36
+#define HidUsage_AD_CursorPixelPositioning 0x37
+#define HidUsage_AD_CursorMode 0x38
+#define HidUsage_AD_CursorEnable 0x39
+#define HidUsage_AD_CursorBlink 0x3a
+#define HidUsage_AD_FontReport 0x3b
+#define HidUsage_AD_FontData 0x3c
+#define HidUsage_AD_CharacterWidth 0x3d
+#define HidUsage_AD_CharacterHeight 0x3e
+#define HidUsage_AD_CharacterSpacingHorizontal 0x3f
+#define HidUsage_AD_CharacterSpacingVertical 0x40
+#define HidUsage_AD_UnicodeCharacterSet 0x41
+#define HidUsage_AD_Font7Segment 0x42
+#define HidUsage_AD_SevenSegmentDirectMap 0x43
+#define HidUsage_AD_Font14Segment 0x44
+#define HidUsage_AD_One4SegmentDirectMap 0x45
+#define HidUsage_AD_DisplayBrightness 0x46
+#define HidUsage_AD_DisplayContrast 0x47
+#define HidUsage_AD_CharacterAttribute 0x48
+#define HidUsage_AD_AttributeReadback 0x49
+#define HidUsage_AD_AttributeData 0x4a
+#define HidUsage_AD_CharAttrEnhance 0x4b
+#define HidUsage_AD_CharAttrUnderline 0x4c
+#define HidUsage_AD_CharAttrBlink 0x4d
+#define HidUsage_AD_BitmapSizeX 0x80
+#define HidUsage_AD_BitmapSizeY 0x81
+#define HidUsage_AD_MaxBlitSize 0x82
+#define HidUsage_AD_BitDepthFormat 0x83
+#define HidUsage_AD_DisplayOrientation 0x84
+#define HidUsage_AD_PaletteReport 0x85
+#define HidUsage_AD_PaletteDataSize 0x86
+#define HidUsage_AD_PaletteDataOffset 0x87
+#define HidUsage_AD_PaletteData 0x88
+#define HidUsage_AD_BlitReport 0x8a
+#define HidUsage_AD_BlitRectangleX1 0x8b
+#define HidUsage_AD_BlitRectangleY1 0x8c
+#define HidUsage_AD_BlitRectangleX2 0x8d
+#define HidUsage_AD_BlitRectangleY2 0x8e
+#define HidUsage_AD_BlitData 0x8f
+#define HidUsage_AD_SoftButton 0x90
+#define HidUsage_AD_SoftButtonID 0x91
+#define HidUsage_AD_SoftButtonSide 0x92
+#define HidUsage_AD_SoftButtonOffset1 0x93
+#define HidUsage_AD_SoftButtonOffset2 0x94
+#define HidUsage_AD_SoftButtonReport 0x95
+#define HidUsage_AD_SoftKeys 0xc2
+#define HidUsage_AD_DisplayDataExtensions 0xcc
+#define HidUsage_AD_CharacterMapping 0xcf
+#define HidUsage_AD_UnicodeEquivalent 0xdd
+#define HidUsage_AD_CharacterPageMapping 0xdf
+#define HidUsage_AD_RequestReport 0xff
+#define HidUsage_Sen_Sensor 0x01
+#define HidUsage_Sen_Biometric 0x10
+#define HidUsage_Sen_BiometricHumanPresence 0x11
+#define HidUsage_Sen_BiometricHumanProximity 0x12
+#define HidUsage_Sen_BiometricHumanTouch 0x13
+#define HidUsage_Sen_BiometricBloodPressure 0x14
+#define HidUsage_Sen_BiometricBodyTemperature 0x15
+#define HidUsage_Sen_BiometricHeartRate 0x16
+#define HidUsage_Sen_BiometricHeartRateVariability 0x17
+#define HidUsage_Sen_BiometricPeripheralOxygenSaturation 0x18
+#define HidUsage_Sen_BiometricRespiratoryRate 0x19
+#define HidUsage_Sen_Electrical 0x20
+#define HidUsage_Sen_ElectricalCapacitance 0x21
+#define HidUsage_Sen_ElectricalCurrent 0x22
+#define HidUsage_Sen_ElectricalPower 0x23
+#define HidUsage_Sen_ElectricalInductance 0x24
+#define HidUsage_Sen_ElectricalResistance 0x25
+#define HidUsage_Sen_ElectricalVoltage 0x26
+#define HidUsage_Sen_ElectricalPotentiometer 0x27
+#define HidUsage_Sen_ElectricalFrequency 0x28
+#define HidUsage_Sen_ElectricalPeriod 0x29
+#define HidUsage_Sen_Environmental 0x30
+#define HidUsage_Sen_EnvironmentalAtmosphericPressure 0x31
+#define HidUsage_Sen_EnvironmentalHumidity 0x32
+#define HidUsage_Sen_EnvironmentalTemperature 0x33
+#define HidUsage_Sen_EnvironmentalWindDirection 0x34
+#define HidUsage_Sen_EnvironmentalWindSpeed 0x35
+#define HidUsage_Sen_EnvironmentalAirQuality 0x36
+#define HidUsage_Sen_EnvironmentalHeatIndex 0x37
+#define HidUsage_Sen_EnvironmentalSurfaceTemperature 0x38
+#define HidUsage_Sen_EnvironmentalVolatileOrganicCompounds 0x39
+#define HidUsage_Sen_EnvironmentalObjectPresence 0x3a
+#define HidUsage_Sen_EnvironmentalObjectProximity 0x3b
+#define HidUsage_Sen_Light 0x40
+#define HidUsage_Sen_LightAmbientLight 0x41
+#define HidUsage_Sen_LightConsumerInfrared 0x42
+#define HidUsage_Sen_LightInfraredLight 0x43
+#define HidUsage_Sen_LightVisibleLight 0x44
+#define HidUsage_Sen_LightUltravioletLight 0x45
+#define HidUsage_Sen_Location 0x50
+#define HidUsage_Sen_LocationBroadcast 0x51
+#define HidUsage_Sen_LocationDeadReckoning 0x52
+#define HidUsage_Sen_LocationGPSGlobalPositioningSystem 0x53
+#define HidUsage_Sen_LocationLookup 0x54
+#define HidUsage_Sen_LocationOther 0x55
+#define HidUsage_Sen_LocationStatic 0x56
+#define HidUsage_Sen_LocationTriangulation 0x57
+#define HidUsage_Sen_Mechanical 0x60
+#define HidUsage_Sen_MechanicalBooleanSwitch 0x61
+#define HidUsage_Sen_MechanicalBooleanSwitchArray 0x62
+#define HidUsage_Sen_MechanicalMultivalueSwitch 0x63
+#define HidUsage_Sen_MechanicalForce 0x64
+#define HidUsage_Sen_MechanicalPressure 0x65
+#define HidUsage_Sen_MechanicalStrain 0x66
+#define HidUsage_Sen_MechanicalWeight 0x67
+#define HidUsage_Sen_MechanicalHapticVibrator 0x68
+#define HidUsage_Sen_MechanicalHallEffectSwitch 0x69
+#define HidUsage_Sen_Motion 0x70
+#define HidUsage_Sen_MotionAccelerometer1D 0x71
+#define HidUsage_Sen_MotionAccelerometer2D 0x72
+#define HidUsage_Sen_MotionAccelerometer3D 0x73
+#define HidUsage_Sen_MotionGyrometer1D 0x74
+#define HidUsage_Sen_MotionGyrometer2D 0x75
+#define HidUsage_Sen_MotionGyrometer3D 0x76
+#define HidUsage_Sen_MotionMotionDetector 0x77
+#define HidUsage_Sen_MotionSpeedometer 0x78
+#define HidUsage_Sen_MotionAccelerometer 0x79
+#define HidUsage_Sen_MotionGyrometer 0x7a
+#define HidUsage_Sen_MotionGravityVector 0x7b
+#define HidUsage_Sen_MotionLinearAccelerometer 0x7c
+#define HidUsage_Sen_Orientation 0x80
+#define HidUsage_Sen_OrientationCompass1D 0x81
+#define HidUsage_Sen_OrientationCompass2D 0x82
+#define HidUsage_Sen_OrientationCompass3D 0x83
+#define HidUsage_Sen_OrientationInclinometer1D 0x84
+#define HidUsage_Sen_OrientationInclinometer2D 0x85
+#define HidUsage_Sen_OrientationInclinometer3D 0x86
+#define HidUsage_Sen_OrientationDistance1D 0x87
+#define HidUsage_Sen_OrientationDistance2D 0x88
+#define HidUsage_Sen_OrientationDistance3D 0x89
+#define HidUsage_Sen_OrientationDeviceOrientation 0x8a
+#define HidUsage_Sen_OrientationCompass 0x8b
+#define HidUsage_Sen_OrientationInclinometer 0x8c
+#define HidUsage_Sen_OrientationDistance 0x8d
+#define HidUsage_Sen_OrientationRelativeOrientation 0x8e
+#define HidUsage_Sen_OrientationSimpleOrientation 0x8f
+#define HidUsage_Sen_Scanner 0x90
+#define HidUsage_Sen_ScannerBarcode 0x91
+#define HidUsage_Sen_ScannerRFID 0x92
+#define HidUsage_Sen_ScannerNFC 0x93
+#define HidUsage_Sen_Time 0xa0
+#define HidUsage_Sen_TimeAlarmTimer 0xa1
+#define HidUsage_Sen_TimeRealTimeClock 0xa2
+#define HidUsage_Sen_PersonalActivity 0xb0
+#define HidUsage_Sen_PersonalActivityActivityDetection 0xb1
+#define HidUsage_Sen_PersonalActivityDevicePosition 0xb2
+#define HidUsage_Sen_PersonalActivityFloorTracker 0xb3
+#define HidUsage_Sen_PersonalActivityPedometer 0xb4
+#define HidUsage_Sen_PersonalActivityStepDetection 0xb5
+#define HidUsage_Sen_OrientationExtended 0xc0
+#define HidUsage_Sen_OrientationExtendedGeomagneticOrientation 0xc1
+#define HidUsage_Sen_OrientationExtendedMagnetometer 0xc2
+#define HidUsage_Sen_Gesture 0xd0
+#define HidUsage_Sen_GestureChassisFlipGesture 0xd1
+#define HidUsage_Sen_GestureHingeFoldGesture 0xd2
+#define HidUsage_Sen_Other 0xe0
+#define HidUsage_Sen_OtherCustom 0xe1
+#define HidUsage_Sen_OtherGeneric 0xe2
+#define HidUsage_Sen_OtherGenericEnumerator 0xe3
+#define HidUsage_Sen_OtherHingeAngle 0xe4
+#define HidUsage_Sen_VendorReserved1 0xf0
+#define HidUsage_Sen_VendorReserved2 0xf1
+#define HidUsage_Sen_VendorReserved3 0xf2
+#define HidUsage_Sen_VendorReserved4 0xf3
+#define HidUsage_Sen_VendorReserved5 0xf4
+#define HidUsage_Sen_VendorReserved6 0xf5
+#define HidUsage_Sen_VendorReserved7 0xf6
+#define HidUsage_Sen_VendorReserved8 0xf7
+#define HidUsage_Sen_VendorReserved9 0xf8
+#define HidUsage_Sen_VendorReserved10 0xf9
+#define HidUsage_Sen_VendorReserved11 0xfa
+#define HidUsage_Sen_VendorReserved12 0xfb
+#define HidUsage_Sen_VendorReserved13 0xfc
+#define HidUsage_Sen_VendorReserved14 0xfd
+#define HidUsage_Sen_VendorReserved15 0xfe
+#define HidUsage_Sen_VendorReserved16 0xff
+#define HidUsage_Sen_Event 0x200
+#define HidUsage_Sen_EventSensorState 0x201
+#define HidUsage_Sen_EventSensorEvent 0x202
+#define HidUsage_Sen_Property 0x300
+#define HidUsage_Sen_PropertyFriendlyName 0x301
+#define HidUsage_Sen_PropertyPersistentUniqueID 0x302
+#define HidUsage_Sen_PropertySensorStatus 0x303
+#define HidUsage_Sen_PropertyMinimumReportInterval 0x304
+#define HidUsage_Sen_PropertySensorManufacturer 0x305
+#define HidUsage_Sen_PropertySensorModel 0x306
+#define HidUsage_Sen_PropertySensorSerialNumber 0x307
+#define HidUsage_Sen_PropertySensorDescription 0x308
+#define HidUsage_Sen_PropertySensorConnectionType 0x309
+#define HidUsage_Sen_PropertySensorDevicePath 0x30a
+#define HidUsage_Sen_PropertyHardwareRevision 0x30b
+#define HidUsage_Sen_PropertyFirmwareVersion 0x30c
+#define HidUsage_Sen_PropertyReleaseDate 0x30d
+#define HidUsage_Sen_PropertyReportInterval 0x30e
+#define HidUsage_Sen_PropertyChangeSensitivityAbsolute 0x30f
+#define HidUsage_Sen_PropertyChangeSensitivityPercentofRange 0x310
+#define HidUsage_Sen_PropertyChangeSensitivityPercentRelative 0x311
+#define HidUsage_Sen_PropertyAccuracy 0x312
+#define HidUsage_Sen_PropertyResolution 0x313
+#define HidUsage_Sen_PropertyMaximum 0x314
+#define HidUsage_Sen_PropertyMinimum 0x315
+#define HidUsage_Sen_PropertyReportingState 0x316
+#define HidUsage_Sen_PropertySamplingRate 0x317
+#define HidUsage_Sen_PropertyResponseCurve 0x318
+#define HidUsage_Sen_PropertyPowerState 0x319
+#define HidUsage_Sen_PropertyMaximumFIFOEvents 0x31a
+#define HidUsage_Sen_PropertyReportLatency 0x31b
+#define HidUsage_Sen_PropertyFlushFIFOEvents 0x31c
+#define HidUsage_Sen_PropertyMaximumPowerConsumption 0x31d
+#define HidUsage_Sen_PropertyIsPrimary 0x31e
+#define HidUsage_Sen_PropertyHumanPresenceDetectionType 0x31f
+#define HidUsage_Sen_DataFieldLocation 0x400
+#define HidUsage_Sen_DataFieldAltitudeAntennaSeaLevel 0x402
+#define HidUsage_Sen_DataFieldDifferentialReferenceStationID 0x403
+#define HidUsage_Sen_DataFieldAltitudeEllipsoidError 0x404
+#define HidUsage_Sen_DataFieldAltitudeEllipsoid 0x405
+#define HidUsage_Sen_DataFieldAltitudeSeaLevelError 0x406
+#define HidUsage_Sen_DataFieldAltitudeSeaLevel 0x407
+#define HidUsage_Sen_DataFieldDifferentialGPSDataAge 0x408
+#define HidUsage_Sen_DataFieldErrorRadius 0x409
+#define HidUsage_Sen_DataFieldFixQuality 0x40a
+#define HidUsage_Sen_DataFieldFixType 0x40b
+#define HidUsage_Sen_DataFieldGeoidalSeparation 0x40c
+#define HidUsage_Sen_DataFieldGPSOperationMode 0x40d
+#define HidUsage_Sen_DataFieldGPSSelectionMode 0x40e
+#define HidUsage_Sen_DataFieldGPSStatus 0x40f
+#define HidUsage_Sen_DataFieldPositionDilutionofPrecision 0x410
+#define HidUsage_Sen_DataFieldHorizontalDilutionofPrecision 0x411
+#define HidUsage_Sen_DataFieldVerticalDilutionofPrecision 0x412
+#define HidUsage_Sen_DataFieldLatitude 0x413
+#define HidUsage_Sen_DataFieldLongitude 0x414
+#define HidUsage_Sen_DataFieldTrueHeading 0x415
+#define HidUsage_Sen_DataFieldMagneticHeading 0x416
+#define HidUsage_Sen_DataFieldMagneticVariation 0x417
+#define HidUsage_Sen_DataFieldSpeed 0x418
+#define HidUsage_Sen_DataFieldSatellitesinView 0x419
+#define HidUsage_Sen_DataFieldSatellitesinViewAzimuth 0x41a
+#define HidUsage_Sen_DataFieldSatellitesinViewElevation 0x41b
+#define HidUsage_Sen_DataFieldSatellitesinViewIDs 0x41c
+#define HidUsage_Sen_DataFieldSatellitesinViewPRNs 0x41d
+#define HidUsage_Sen_DataFieldSatellitesinViewSNRatios 0x41e
+#define HidUsage_Sen_DataFieldSatellitesUsedCount 0x41f
+#define HidUsage_Sen_DataFieldSatellitesUsedPRNs 0x420
+#define HidUsage_Sen_DataFieldNMEASentence 0x421
+#define HidUsage_Sen_DataFieldAddressLine1 0x422
+#define HidUsage_Sen_DataFieldAddressLine2 0x423
+#define HidUsage_Sen_DataFieldCity 0x424
+#define HidUsage_Sen_DataFieldStateorProvince 0x425
+#define HidUsage_Sen_DataFieldCountryorRegion 0x426
+#define HidUsage_Sen_DataFieldPostalCode 0x427
+#define HidUsage_Sen_PropertyLocation 0x42a
+#define HidUsage_Sen_PropertyLocationDesiredAccuracy 0x42b
+#define HidUsage_Sen_DataFieldEnvironmental 0x430
+#define HidUsage_Sen_DataFieldAtmosphericPressure 0x431
+#define HidUsage_Sen_DataFieldRelativeHumidity 0x433
+#define HidUsage_Sen_DataFieldTemperature 0x434
+#define HidUsage_Sen_DataFieldWindDirection 0x435
+#define HidUsage_Sen_DataFieldWindSpeed 0x436
+#define HidUsage_Sen_DataFieldAirQualityIndex 0x437
+#define HidUsage_Sen_DataFieldEquivalentCO2 0x438
+#define HidUsage_Sen_DataFieldVolatileOrganicCompoundConcentration 0x439
+#define HidUsage_Sen_DataFieldObjectPresence 0x43a
+#define HidUsage_Sen_DataFieldObjectProximityRange 0x43b
+#define HidUsage_Sen_DataFieldObjectProximityOutofRange 0x43c
+#define HidUsage_Sen_PropertyEnvironmental 0x440
+#define HidUsage_Sen_PropertyReferencePressure 0x441
+#define HidUsage_Sen_DataFieldMotion 0x450
+#define HidUsage_Sen_DataFieldMotionState 0x451
+#define HidUsage_Sen_DataFieldAcceleration 0x452
+#define HidUsage_Sen_DataFieldAccelerationAxisX 0x453
+#define HidUsage_Sen_DataFieldAccelerationAxisY 0x454
+#define HidUsage_Sen_DataFieldAccelerationAxisZ 0x455
+#define HidUsage_Sen_DataFieldAngularVelocity 0x456
+#define HidUsage_Sen_DataFieldAngularVelocityaboutXAxis 0x457
+#define HidUsage_Sen_DataFieldAngularVelocityaboutYAxis 0x458
+#define HidUsage_Sen_DataFieldAngularVelocityaboutZAxis 0x459
+#define HidUsage_Sen_DataFieldAngularPosition 0x45a
+#define HidUsage_Sen_DataFieldAngularPositionaboutXAxis 0x45b
+#define HidUsage_Sen_DataFieldAngularPositionaboutYAxis 0x45c
+#define HidUsage_Sen_DataFieldAngularPositionaboutZAxis 0x45d
+#define HidUsage_Sen_DataFieldMotionSpeed 0x45e
+#define HidUsage_Sen_DataFieldMotionIntensity 0x45f
+#define HidUsage_Sen_DataFieldOrientation 0x470
+#define HidUsage_Sen_DataFieldHeading 0x471
+#define HidUsage_Sen_DataFieldHeadingXAxis 0x472
+#define HidUsage_Sen_DataFieldHeadingYAxis 0x473
+#define HidUsage_Sen_DataFieldHeadingZAxis 0x474
+#define HidUsage_Sen_DataFieldHeadingCompensatedMagneticNorth 0x475
+#define HidUsage_Sen_DataFieldHeadingCompensatedTrueNorth 0x476
+#define HidUsage_Sen_DataFieldHeadingMagneticNorth 0x477
+#define HidUsage_Sen_DataFieldHeadingTrueNorth 0x478
+#define HidUsage_Sen_DataFieldDistance 0x479
+#define HidUsage_Sen_DataFieldDistanceXAxis 0x47a
+#define HidUsage_Sen_DataFieldDistanceYAxis 0x47b
+#define HidUsage_Sen_DataFieldDistanceZAxis 0x47c
+#define HidUsage_Sen_DataFieldDistanceOutofRange 0x47d
+#define HidUsage_Sen_DataFieldTilt 0x47e
+#define HidUsage_Sen_DataFieldTiltXAxis 0x47f
+#define HidUsage_Sen_DataFieldTiltYAxis 0x480
+#define HidUsage_Sen_DataFieldTiltZAxis 0x481
+#define HidUsage_Sen_DataFieldRotationMatrix 0x482
+#define HidUsage_Sen_DataFieldQuaternion 0x483
+#define HidUsage_Sen_DataFieldMagneticFlux 0x484
+#define HidUsage_Sen_DataFieldMagneticFluxXAxis 0x485
+#define HidUsage_Sen_DataFieldMagneticFluxYAxis 0x486
+#define HidUsage_Sen_DataFieldMagneticFluxZAxis 0x487
+#define HidUsage_Sen_DataFieldMagnetometerAccuracy 0x488
+#define HidUsage_Sen_DataFieldSimpleOrientationDirection 0x489
+#define HidUsage_Sen_DataFieldMechanical 0x490
+#define HidUsage_Sen_DataFieldBooleanSwitchState 0x491
+#define HidUsage_Sen_DataFieldBooleanSwitchArrayStates 0x492
+#define HidUsage_Sen_DataFieldMultivalueSwitchValue 0x493
+#define HidUsage_Sen_DataFieldForce 0x494
+#define HidUsage_Sen_DataFieldAbsolutePressure 0x495
+#define HidUsage_Sen_DataFieldGaugePressure 0x496
+#define HidUsage_Sen_DataFieldStrain 0x497
+#define HidUsage_Sen_DataFieldWeight 0x498
+#define HidUsage_Sen_PropertyMechanical 0x4a0
+#define HidUsage_Sen_PropertyVibrationState 0x4a1
+#define HidUsage_Sen_PropertyForwardVibrationSpeed 0x4a2
+#define HidUsage_Sen_PropertyBackwardVibrationSpeed 0x4a3
+#define HidUsage_Sen_DataFieldBiometric 0x4b0
+#define HidUsage_Sen_DataFieldHumanPresence 0x4b1
+#define HidUsage_Sen_DataFieldHumanProximityRange 0x4b2
+#define HidUsage_Sen_DataFieldHumanProximityOutofRange 0x4b3
+#define HidUsage_Sen_DataFieldHumanTouchState 0x4b4
+#define HidUsage_Sen_DataFieldBloodPressure 0x4b5
+#define HidUsage_Sen_DataFieldBloodPressureDiastolic 0x4b6
+#define HidUsage_Sen_DataFieldBloodPressureSystolic 0x4b7
+#define HidUsage_Sen_DataFieldHeartRate 0x4b8
+#define HidUsage_Sen_DataFieldRestingHeartRate 0x4b9
+#define HidUsage_Sen_DataFieldHeartbeatInterval 0x4ba
+#define HidUsage_Sen_DataFieldRespiratoryRate 0x4bb
+#define HidUsage_Sen_DataFieldSpO2 0x4bc
+#define HidUsage_Sen_DataFieldHumanAttentionDetected 0x4bd
+#define HidUsage_Sen_DataFieldHumanHeadAzimuth 0x4be
+#define HidUsage_Sen_DataFieldHumanHeadAltitude 0x4bf
+#define HidUsage_Sen_DataFieldHumanHeadRoll 0x4c0
+#define HidUsage_Sen_DataFieldHumanHeadPitch 0x4c1
+#define HidUsage_Sen_DataFieldHumanHeadYaw 0x4c2
+#define HidUsage_Sen_DataFieldHumanCorrelationId 0x4c3
+#define HidUsage_Sen_DataFieldLight 0x4d0
+#define HidUsage_Sen_DataFieldIlluminance 0x4d1
+#define HidUsage_Sen_DataFieldColorTemperature 0x4d2
+#define HidUsage_Sen_DataFieldChromaticity 0x4d3
+#define HidUsage_Sen_DataFieldChromaticityX 0x4d4
+#define HidUsage_Sen_DataFieldChromaticityY 0x4d5
+#define HidUsage_Sen_DataFieldConsumerIRSentenceReceive 0x4d6
+#define HidUsage_Sen_DataFieldInfraredLight 0x4d7
+#define HidUsage_Sen_DataFieldRedLight 0x4d8
+#define HidUsage_Sen_DataFieldGreenLight 0x4d9
+#define HidUsage_Sen_DataFieldBlueLight 0x4da
+#define HidUsage_Sen_DataFieldUltravioletALight 0x4db
+#define HidUsage_Sen_DataFieldUltravioletBLight 0x4dc
+#define HidUsage_Sen_DataFieldUltravioletIndex 0x4dd
+#define HidUsage_Sen_DataFieldNearInfraredLight 0x4de
+#define HidUsage_Sen_PropertyLight 0x4df
+#define HidUsage_Sen_PropertyConsumerIRSentenceSend 0x4e0
+#define HidUsage_Sen_PropertyAutoBrightnessPreferred 0x4e2
+#define HidUsage_Sen_PropertyAutoColorPreferred 0x4e3
+#define HidUsage_Sen_DataFieldScanner 0x4f0
+#define HidUsage_Sen_DataFieldRFIDTag40Bit 0x4f1
+#define HidUsage_Sen_DataFieldNFCSentenceReceive 0x4f2
+#define HidUsage_Sen_PropertyScanner 0x4f8
+#define HidUsage_Sen_PropertyNFCSentenceSend 0x4f9
+#define HidUsage_Sen_DataFieldElectrical 0x500
+#define HidUsage_Sen_DataFieldCapacitance 0x501
+#define HidUsage_Sen_DataFieldCurrent 0x502
+#define HidUsage_Sen_DataFieldElectricalPower 0x503
+#define HidUsage_Sen_DataFieldInductance 0x504
+#define HidUsage_Sen_DataFieldResistance 0x505
+#define HidUsage_Sen_DataFieldVoltage 0x506
+#define HidUsage_Sen_DataFieldFrequency 0x507
+#define HidUsage_Sen_DataFieldPeriod 0x508
+#define HidUsage_Sen_DataFieldPercentofRange 0x509
+#define HidUsage_Sen_DataFieldTime 0x520
+#define HidUsage_Sen_DataFieldYear 0x521
+#define HidUsage_Sen_DataFieldMonth 0x522
+#define HidUsage_Sen_DataFieldDay 0x523
+#define HidUsage_Sen_DataFieldDayofWeek 0x524
+#define HidUsage_Sen_DataFieldHour 0x525
+#define HidUsage_Sen_DataFieldMinute 0x526
+#define HidUsage_Sen_DataFieldSecond 0x527
+#define HidUsage_Sen_DataFieldMillisecond 0x528
+#define HidUsage_Sen_DataFieldTimestamp 0x529
+#define HidUsage_Sen_DataFieldJulianDayofYear 0x52a
+#define HidUsage_Sen_DataFieldTimeSinceSystemBoot 0x52b
+#define HidUsage_Sen_PropertyTime 0x530
+#define HidUsage_Sen_PropertyTimeZoneOffsetfromUTC 0x531
+#define HidUsage_Sen_PropertyTimeZoneName 0x532
+#define HidUsage_Sen_PropertyDaylightSavingsTimeObserved 0x533
+#define HidUsage_Sen_PropertyTimeTrimAdjustment 0x534
+#define HidUsage_Sen_PropertyArmAlarm 0x535
+#define HidUsage_Sen_DataFieldCustom 0x540
+#define HidUsage_Sen_DataFieldCustomUsage 0x541
+#define HidUsage_Sen_DataFieldCustomBooleanArray 0x542
+#define HidUsage_Sen_DataFieldCustomValue 0x543
+#define HidUsage_Sen_DataFieldCustomValue1 0x544
+#define HidUsage_Sen_DataFieldCustomValue2 0x545
+#define HidUsage_Sen_DataFieldCustomValue3 0x546
+#define HidUsage_Sen_DataFieldCustomValue4 0x547
+#define HidUsage_Sen_DataFieldCustomValue5 0x548
+#define HidUsage_Sen_DataFieldCustomValue6 0x549
+#define HidUsage_Sen_DataFieldCustomValue7 0x54a
+#define HidUsage_Sen_DataFieldCustomValue8 0x54b
+#define HidUsage_Sen_DataFieldCustomValue9 0x54c
+#define HidUsage_Sen_DataFieldCustomValue10 0x54d
+#define HidUsage_Sen_DataFieldCustomValue11 0x54e
+#define HidUsage_Sen_DataFieldCustomValue12 0x54f
+#define HidUsage_Sen_DataFieldCustomValue13 0x550
+#define HidUsage_Sen_DataFieldCustomValue14 0x551
+#define HidUsage_Sen_DataFieldCustomValue15 0x552
+#define HidUsage_Sen_DataFieldCustomValue16 0x553
+#define HidUsage_Sen_DataFieldCustomValue17 0x554
+#define HidUsage_Sen_DataFieldCustomValue18 0x555
+#define HidUsage_Sen_DataFieldCustomValue19 0x556
+#define HidUsage_Sen_DataFieldCustomValue20 0x557
+#define HidUsage_Sen_DataFieldCustomValue21 0x558
+#define HidUsage_Sen_DataFieldCustomValue22 0x559
+#define HidUsage_Sen_DataFieldCustomValue23 0x55a
+#define HidUsage_Sen_DataFieldCustomValue24 0x55b
+#define HidUsage_Sen_DataFieldCustomValue25 0x55c
+#define HidUsage_Sen_DataFieldCustomValue26 0x55d
+#define HidUsage_Sen_DataFieldCustomValue27 0x55e
+#define HidUsage_Sen_DataFieldCustomValue28 0x55f
+#define HidUsage_Sen_DataFieldGeneric 0x560
+#define HidUsage_Sen_DataFieldGenericGUIDorPROPERTYKEY 0x561
+#define HidUsage_Sen_DataFieldGenericCategoryGUID 0x562
+#define HidUsage_Sen_DataFieldGenericTypeGUID 0x563
+#define HidUsage_Sen_DataFieldGenericEventPROPERTYKEY 0x564
+#define HidUsage_Sen_DataFieldGenericPropertyPROPERTYKEY 0x565
+#define HidUsage_Sen_DataFieldGenericDataFieldPROPERTYKEY 0x566
+#define HidUsage_Sen_DataFieldGenericEvent 0x567
+#define HidUsage_Sen_DataFieldGenericProperty 0x568
+#define HidUsage_Sen_DataFieldGenericDataField 0x569
+#define HidUsage_Sen_DataFieldEnumeratorTableRowIndex 0x56a
+#define HidUsage_Sen_DataFieldEnumeratorTableRowCount 0x56b
+#define HidUsage_Sen_DataFieldGenericGUIDorPROPERTYKEYkind 0x56c
+#define HidUsage_Sen_DataFieldGenericGUID 0x56d
+#define HidUsage_Sen_DataFieldGenericPROPERTYKEY 0x56e
+#define HidUsage_Sen_DataFieldGenericTopLevelCollectionID 0x56f
+#define HidUsage_Sen_DataFieldGenericReportID 0x570
+#define HidUsage_Sen_DataFieldGenericReportItemPositionIndex 0x571
+#define HidUsage_Sen_DataFieldGenericFirmwareVARTYPE 0x572
+#define HidUsage_Sen_DataFieldGenericUnitofMeasure 0x573
+#define HidUsage_Sen_DataFieldGenericUnitExponent 0x574
+#define HidUsage_Sen_DataFieldGenericReportSize 0x575
+#define HidUsage_Sen_DataFieldGenericReportCount 0x576
+#define HidUsage_Sen_PropertyGeneric 0x580
+#define HidUsage_Sen_PropertyEnumeratorTableRowIndex 0x581
+#define HidUsage_Sen_PropertyEnumeratorTableRowCount 0x582
+#define HidUsage_Sen_DataFieldPersonalActivity 0x590
+#define HidUsage_Sen_DataFieldActivityType 0x591
+#define HidUsage_Sen_DataFieldActivityState 0x592
+#define HidUsage_Sen_DataFieldDevicePosition 0x593
+#define HidUsage_Sen_DataFieldStepCount 0x594
+#define HidUsage_Sen_DataFieldStepCountReset 0x595
+#define HidUsage_Sen_DataFieldStepDuration 0x596
+#define HidUsage_Sen_DataFieldStepType 0x597
+#define HidUsage_Sen_PropertyMinimumActivityDetectionInterval 0x5a0
+#define HidUsage_Sen_PropertySupportedActivityTypes 0x5a1
+#define HidUsage_Sen_PropertySubscribedActivityTypes 0x5a2
+#define HidUsage_Sen_PropertySupportedStepTypes 0x5a3
+#define HidUsage_Sen_PropertySubscribedStepTypes 0x5a4
+#define HidUsage_Sen_PropertyFloorHeight 0x5a5
+#define HidUsage_Sen_DataFieldCustomTypeID 0x5b0
+#define HidUsage_Sen_PropertyCustom 0x5c0
+#define HidUsage_Sen_PropertyCustomValue1 0x5c1
+#define HidUsage_Sen_PropertyCustomValue2 0x5c2
+#define HidUsage_Sen_PropertyCustomValue3 0x5c3
+#define HidUsage_Sen_PropertyCustomValue4 0x5c4
+#define HidUsage_Sen_PropertyCustomValue5 0x5c5
+#define HidUsage_Sen_PropertyCustomValue6 0x5c6
+#define HidUsage_Sen_PropertyCustomValue7 0x5c7
+#define HidUsage_Sen_PropertyCustomValue8 0x5c8
+#define HidUsage_Sen_PropertyCustomValue9 0x5c9
+#define HidUsage_Sen_PropertyCustomValue10 0x5ca
+#define HidUsage_Sen_PropertyCustomValue11 0x5cb
+#define HidUsage_Sen_PropertyCustomValue12 0x5cc
+#define HidUsage_Sen_PropertyCustomValue13 0x5cd
+#define HidUsage_Sen_PropertyCustomValue14 0x5ce
+#define HidUsage_Sen_PropertyCustomValue15 0x5cf
+#define HidUsage_Sen_PropertyCustomValue16 0x5d0
+#define HidUsage_Sen_DataFieldHinge 0x5e0
+#define HidUsage_Sen_DataFieldHingeAngle 0x5e1
+#define HidUsage_Sen_DataFieldGestureSensor 0x5f0
+#define HidUsage_Sen_DataFieldGestureState 0x5f1
+#define HidUsage_Sen_DataFieldHingeFoldInitialAngle 0x5f2
+#define HidUsage_Sen_DataFieldHingeFoldFinalAngle 0x5f3
+#define HidUsage_Sen_DataFieldHingeFoldContributingPanel 0x5f4
+#define HidUsage_Sen_DataFieldHingeFoldType 0x5f5
+#define HidUsage_Sen_SensorStateUndefined 0x800
+#define HidUsage_Sen_SensorStateReady 0x801
+#define HidUsage_Sen_SensorStateNotAvailable 0x802
+#define HidUsage_Sen_SensorStateNoData 0x803
+#define HidUsage_Sen_SensorStateInitializing 0x804
+#define HidUsage_Sen_SensorStateAccessDenied 0x805
+#define HidUsage_Sen_SensorStateError 0x806
+#define HidUsage_Sen_SensorEventUnknown 0x810
+#define HidUsage_Sen_SensorEventStateChanged 0x811
+#define HidUsage_Sen_SensorEventPropertyChanged 0x812
+#define HidUsage_Sen_SensorEventDataUpdated 0x813
+#define HidUsage_Sen_SensorEventPollResponse 0x814
+#define HidUsage_Sen_SensorEventChangeSensitivity 0x815
+#define HidUsage_Sen_SensorEventRangeMaximumReached 0x816
+#define HidUsage_Sen_SensorEventRangeMinimumReached 0x817
+#define HidUsage_Sen_SensorEventHighThresholdCrossUpward 0x818
+#define HidUsage_Sen_SensorEventHighThresholdCrossDownward 0x819
+#define HidUsage_Sen_SensorEventLowThresholdCrossUpward 0x81a
+#define HidUsage_Sen_SensorEventLowThresholdCrossDownward 0x81b
+#define HidUsage_Sen_SensorEventZeroThresholdCrossUpward 0x81c
+#define HidUsage_Sen_SensorEventZeroThresholdCrossDownward 0x81d
+#define HidUsage_Sen_SensorEventPeriodExceeded 0x81e
+#define HidUsage_Sen_SensorEventFrequencyExceeded 0x81f
+#define HidUsage_Sen_SensorEventComplexTrigger 0x820
+#define HidUsage_Sen_ConnectionTypePCIntegrated 0x830
+#define HidUsage_Sen_ConnectionTypePCAttached 0x831
+#define HidUsage_Sen_ConnectionTypePCExternal 0x832
+#define HidUsage_Sen_ReportingStateReportNoEvents 0x840
+#define HidUsage_Sen_ReportingStateReportAllEvents 0x841
+#define HidUsage_Sen_ReportingStateReportThresholdEvents 0x842
+#define HidUsage_Sen_ReportingStateWakeOnNoEvents 0x843
+#define HidUsage_Sen_ReportingStateWakeOnAllEvents 0x844
+#define HidUsage_Sen_ReportingStateWakeOnThresholdEvents 0x845
+#define HidUsage_Sen_ReportingStateAnytime 0x846
+#define HidUsage_Sen_PowerStateUndefined 0x850
+#define HidUsage_Sen_PowerStateD0FullPower 0x851
+#define HidUsage_Sen_PowerStateD1LowPower 0x852
+#define HidUsage_Sen_PowerStateD2StandbyPowerwithWakeup 0x853
+#define HidUsage_Sen_PowerStateD3SleepwithWakeup 0x854
+#define HidUsage_Sen_PowerStateD4PowerOff 0x855
+#define HidUsage_Sen_AccuracyDefault 0x860
+#define HidUsage_Sen_AccuracyHigh 0x861
+#define HidUsage_Sen_AccuracyMedium 0x862
+#define HidUsage_Sen_AccuracyLow 0x863
+#define HidUsage_Sen_FixQualityNoFix 0x870
+#define HidUsage_Sen_FixQualityGPS 0x871
+#define HidUsage_Sen_FixQualityDGPS 0x872
+#define HidUsage_Sen_FixTypeNoFix 0x880
+#define HidUsage_Sen_FixTypeGPSSPSModeFixValid 0x881
+#define HidUsage_Sen_FixTypeDGPSSPSModeFixValid 0x882
+#define HidUsage_Sen_FixTypeGPSPPSModeFixValid 0x883
+#define HidUsage_Sen_FixTypeRealTimeKinematic 0x884
+#define HidUsage_Sen_FixTypeFloatRTK 0x885
+#define HidUsage_Sen_FixTypeEstimateddeadreckoned 0x886
+#define HidUsage_Sen_FixTypeManualInputMode 0x887
+#define HidUsage_Sen_FixTypeSimulatorMode 0x888
+#define HidUsage_Sen_GPSOperationModeManual 0x890
+#define HidUsage_Sen_GPSOperationModeAutomatic 0x891
+#define HidUsage_Sen_GPSSelectionModeAutonomous 0x8a0
+#define HidUsage_Sen_GPSSelectionModeDGPS 0x8a1
+#define HidUsage_Sen_GPSSelectionModeEstimateddeadreckoned 0x8a2
+#define HidUsage_Sen_GPSSelectionModeManualInput 0x8a3
+#define HidUsage_Sen_GPSSelectionModeSimulator 0x8a4
+#define HidUsage_Sen_GPSSelectionModeDataNotValid 0x8a5
+#define HidUsage_Sen_GPSStatusDataValid 0x8b0
+#define HidUsage_Sen_GPSStatusDataNotValid 0x8b1
+#define HidUsage_Sen_DayofWeekSunday 0x8c0
+#define HidUsage_Sen_DayofWeekMonday 0x8c1
+#define HidUsage_Sen_DayofWeekTuesday 0x8c2
+#define HidUsage_Sen_DayofWeekWednesday 0x8c3
+#define HidUsage_Sen_DayofWeekThursday 0x8c4
+#define HidUsage_Sen_DayofWeekFriday 0x8c5
+#define HidUsage_Sen_DayofWeekSaturday 0x8c6
+#define HidUsage_Sen_KindCategory 0x8d0
+#define HidUsage_Sen_KindType 0x8d1
+#define HidUsage_Sen_KindEvent 0x8d2
+#define HidUsage_Sen_KindProperty 0x8d3
+#define HidUsage_Sen_KindDataField 0x8d4
+#define HidUsage_Sen_MagnetometerAccuracyLow 0x8e0
+#define HidUsage_Sen_MagnetometerAccuracyMedium 0x8e1
+#define HidUsage_Sen_MagnetometerAccuracyHigh 0x8e2
+#define HidUsage_Sen_SimpleOrientationDirectionNotRotated 0x8f0
+#define HidUsage_Sen_SimpleOrientationDirectionRotated90DegreesCCW 0x8f1
+#define HidUsage_Sen_SimpleOrientationDirectionRotated180DegreesCCW 0x8f2
+#define HidUsage_Sen_SimpleOrientationDirectionRotated270DegreesCCW 0x8f3
+#define HidUsage_Sen_SimpleOrientationDirectionFaceUp 0x8f4
+#define HidUsage_Sen_SimpleOrientationDirectionFaceDown 0x8f5
+#define HidUsage_Sen_VT_NULL 0x900
+#define HidUsage_Sen_VT_BOOL 0x901
+#define HidUsage_Sen_VT_UI1 0x902
+#define HidUsage_Sen_VT_I1 0x903
+#define HidUsage_Sen_VT_UI2 0x904
+#define HidUsage_Sen_VT_I2 0x905
+#define HidUsage_Sen_VT_UI4 0x906
+#define HidUsage_Sen_VT_I4 0x907
+#define HidUsage_Sen_VT_UI8 0x908
+#define HidUsage_Sen_VT_I8 0x909
+#define HidUsage_Sen_VT_R4 0x90a
+#define HidUsage_Sen_VT_R8 0x90b
+#define HidUsage_Sen_VT_WSTR 0x90c
+#define HidUsage_Sen_VT_STR 0x90d
+#define HidUsage_Sen_VT_CLSID 0x90e
+#define HidUsage_Sen_VT_VECTORVT_UI1 0x90f
+#define HidUsage_Sen_VT_F16E0 0x910
+#define HidUsage_Sen_VT_F16E1 0x911
+#define HidUsage_Sen_VT_F16E2 0x912
+#define HidUsage_Sen_VT_F16E3 0x913
+#define HidUsage_Sen_VT_F16E4 0x914
+#define HidUsage_Sen_VT_F16E5 0x915
+#define HidUsage_Sen_VT_F16E6 0x916
+#define HidUsage_Sen_VT_F16E7 0x917
+#define HidUsage_Sen_VT_F16E8 0x918
+#define HidUsage_Sen_VT_F16E9 0x919
+#define HidUsage_Sen_VT_F16EA 0x91a
+#define HidUsage_Sen_VT_F16EB 0x91b
+#define HidUsage_Sen_VT_F16EC 0x91c
+#define HidUsage_Sen_VT_F16ED 0x91d
+#define HidUsage_Sen_VT_F16EE 0x91e
+#define HidUsage_Sen_VT_F16EF 0x91f
+#define HidUsage_Sen_VT_F32E0 0x920
+#define HidUsage_Sen_VT_F32E1 0x921
+#define HidUsage_Sen_VT_F32E2 0x922
+#define HidUsage_Sen_VT_F32E3 0x923
+#define HidUsage_Sen_VT_F32E4 0x924
+#define HidUsage_Sen_VT_F32E5 0x925
+#define HidUsage_Sen_VT_F32E6 0x926
+#define HidUsage_Sen_VT_F32E7 0x927
+#define HidUsage_Sen_VT_F32E8 0x928
+#define HidUsage_Sen_VT_F32E9 0x929
+#define HidUsage_Sen_VT_F32EA 0x92a
+#define HidUsage_Sen_VT_F32EB 0x92b
+#define HidUsage_Sen_VT_F32EC 0x92c
+#define HidUsage_Sen_VT_F32ED 0x92d
+#define HidUsage_Sen_VT_F32EE 0x92e
+#define HidUsage_Sen_VT_F32EF 0x92f
+#define HidUsage_Sen_ActivityTypeUnknown 0x930
+#define HidUsage_Sen_ActivityTypeStationary 0x931
+#define HidUsage_Sen_ActivityTypeFidgeting 0x932
+#define HidUsage_Sen_ActivityTypeWalking 0x933
+#define HidUsage_Sen_ActivityTypeRunning 0x934
+#define HidUsage_Sen_ActivityTypeInVehicle 0x935
+#define HidUsage_Sen_ActivityTypeBiking 0x936
+#define HidUsage_Sen_ActivityTypeIdle 0x937
+#define HidUsage_Sen_UnitNotSpecified 0x940
+#define HidUsage_Sen_UnitLux 0x941
+#define HidUsage_Sen_UnitDegreesKelvin 0x942
+#define HidUsage_Sen_UnitDegreesCelsius 0x943
+#define HidUsage_Sen_UnitPascal 0x944
+#define HidUsage_Sen_UnitNewton 0x945
+#define HidUsage_Sen_UnitMetersSecond 0x946
+#define HidUsage_Sen_UnitKilogram 0x947
+#define HidUsage_Sen_UnitMeter 0x948
+#define HidUsage_Sen_UnitMetersSecondSecond 0x949
+#define HidUsage_Sen_UnitFarad 0x94a
+#define HidUsage_Sen_UnitAmpere 0x94b
+#define HidUsage_Sen_UnitWatt 0x94c
+#define HidUsage_Sen_UnitHenry 0x94d
+#define HidUsage_Sen_UnitOhm 0x94e
+#define HidUsage_Sen_UnitVolt 0x94f
+#define HidUsage_Sen_UnitHertz 0x950
+#define HidUsage_Sen_UnitBar 0x951
+#define HidUsage_Sen_UnitDegreesAnticlockwise 0x952
+#define HidUsage_Sen_UnitDegreesClockwise 0x953
+#define HidUsage_Sen_UnitDegrees 0x954
+#define HidUsage_Sen_UnitDegreesSecond 0x955
+#define HidUsage_Sen_UnitDegreesSecondSecond 0x956
+#define HidUsage_Sen_UnitKnot 0x957
+#define HidUsage_Sen_UnitPercent 0x958
+#define HidUsage_Sen_UnitSecond 0x959
+#define HidUsage_Sen_UnitMillisecond 0x95a
+#define HidUsage_Sen_UnitG 0x95b
+#define HidUsage_Sen_UnitBytes 0x95c
+#define HidUsage_Sen_UnitMilligauss 0x95d
+#define HidUsage_Sen_UnitBits 0x95e
+#define HidUsage_Sen_ActivityStateNoStateChange 0x960
+#define HidUsage_Sen_ActivityStateStartActivity 0x961
+#define HidUsage_Sen_ActivityStateEndActivity 0x962
+#define HidUsage_Sen_Exponent0 0x970
+#define HidUsage_Sen_Exponent1 0x971
+#define HidUsage_Sen_Exponent2 0x972
+#define HidUsage_Sen_Exponent3 0x973
+#define HidUsage_Sen_Exponent4 0x974
+#define HidUsage_Sen_Exponent5 0x975
+#define HidUsage_Sen_Exponent6 0x976
+#define HidUsage_Sen_Exponent7 0x977
+#define HidUsage_Sen_Exponent8 0x978
+#define HidUsage_Sen_Exponent9 0x979
+#define HidUsage_Sen_ExponentA 0x97a
+#define HidUsage_Sen_ExponentB 0x97b
+#define HidUsage_Sen_ExponentC 0x97c
+#define HidUsage_Sen_ExponentD 0x97d
+#define HidUsage_Sen_ExponentE 0x97e
+#define HidUsage_Sen_ExponentF 0x97f
+#define HidUsage_Sen_DevicePositionUnknown 0x980
+#define HidUsage_Sen_DevicePositionUnchanged 0x981
+#define HidUsage_Sen_DevicePositionOnDesk 0x982
+#define HidUsage_Sen_DevicePositionInHand 0x983
+#define HidUsage_Sen_DevicePositionMovinginBag 0x984
+#define HidUsage_Sen_DevicePositionStationaryinBag 0x985
+#define HidUsage_Sen_StepTypeUnknown 0x990
+#define HidUsage_Sen_StepTypeWalking 0x991
+#define HidUsage_Sen_StepTypeRunning 0x992
+#define HidUsage_Sen_GestureStateUnknown 0x9a0
+#define HidUsage_Sen_GestureStateStarted 0x9a1
+#define HidUsage_Sen_GestureStateCompleted 0x9a2
+#define HidUsage_Sen_GestureStateCancelled 0x9a3
+#define HidUsage_Sen_HingeFoldContributingPanelUnknown 0x9b0
+#define HidUsage_Sen_HingeFoldContributingPanelPanel1 0x9b1
+#define HidUsage_Sen_HingeFoldContributingPanelPanel2 0x9b2
+#define HidUsage_Sen_HingeFoldContributingPanelBoth 0x9b3
+#define HidUsage_Sen_HingeFoldTypeUnknown 0x9b4
+#define HidUsage_Sen_HingeFoldTypeIncreasing 0x9b5
+#define HidUsage_Sen_HingeFoldTypeDecreasing 0x9b6
+#define HidUsage_Sen_HumanPresenceDetectionTypeVendorDefinedNonBiometric 0x9c0
+#define HidUsage_Sen_HumanPresenceDetectionTypeVendorDefinedBiometric 0x9c1
+#define HidUsage_Sen_HumanPresenceDetectionTypeFacialBiometric 0x9c2
+#define HidUsage_Sen_HumanPresenceDetectionTypeAudioBiometric 0x9c3
+#define HidUsage_Sen_ModifierChangeSensitivityAbsolute 0x1000
+#define HidUsage_Sen_ModifierMaximum 0x2000
+#define HidUsage_Sen_ModifierMinimum 0x3000
+#define HidUsage_Sen_ModifierAccuracy 0x4000
+#define HidUsage_Sen_ModifierResolution 0x5000
+#define HidUsage_Sen_ModifierThresholdHigh 0x6000
+#define HidUsage_Sen_ModifierThresholdLow 0x7000
+#define HidUsage_Sen_ModifierCalibrationOffset 0x8000
+#define HidUsage_Sen_ModifierCalibrationMultiplier 0x9000
+#define HidUsage_Sen_ModifierReportInterval 0xa000
+#define HidUsage_Sen_ModifierFrequencyMax 0xb000
+#define HidUsage_Sen_ModifierPeriodMax 0xc000
+#define HidUsage_Sen_ModifierChangeSensitivityPercentofRange 0xd000
+#define HidUsage_Sen_ModifierChangeSensitivityPercentRelative 0xe000
+#define HidUsage_Sen_ModifierVendorReserved 0xf000
+#define HidUsage_MI_MedicalUltrasound 0x01
+#define HidUsage_MI_VCRAcquisition 0x20
+#define HidUsage_MI_FreezeThaw 0x21
+#define HidUsage_MI_ClipStore 0x22
+#define HidUsage_MI_Update 0x23
+#define HidUsage_MI_Next 0x24
+#define HidUsage_MI_Save 0x25
+#define HidUsage_MI_Print 0x26
+#define HidUsage_MI_MicrophoneEnable 0x27
+#define HidUsage_MI_Cine 0x40
+#define HidUsage_MI_TransmitPower 0x41
+#define HidUsage_MI_Volume 0x42
+#define HidUsage_MI_Focus 0x43
+#define HidUsage_MI_Depth 0x44
+#define HidUsage_MI_SoftStepPrimary 0x60
+#define HidUsage_MI_SoftStepSecondary 0x61
+#define HidUsage_MI_DepthGainCompensation 0x70
+#define HidUsage_MI_ZoomSelect 0x80
+#define HidUsage_MI_ZoomAdjust 0x81
+#define HidUsage_MI_SpectralDopplerModeSelect 0x82
+#define HidUsage_MI_SpectralDopplerAdjust 0x83
+#define HidUsage_MI_ColorDopplerModeSelect 0x84
+#define HidUsage_MI_ColorDopplerAdjust 0x85
+#define HidUsage_MI_MotionModeSelect 0x86
+#define HidUsage_MI_MotionModeAdjust 0x87
+#define HidUsage_MI_TwoDModeSelect 0x88
+#define HidUsage_MI_TwoDModeAdjust 0x89
+#define HidUsage_MI_SoftControlSelect 0xa0
+#define HidUsage_MI_SoftControlAdjust 0xa1
+#define HidUsage_BD_BrailleDisplay 0x01
+#define HidUsage_BD_BrailleRow 0x02
+#define HidUsage_BD_EightDotBrailleCell 0x03
+#define HidUsage_BD_SixDotBrailleCell 0x04
+#define HidUsage_BD_NumberofBrailleCells 0x05
+#define HidUsage_BD_ScreenReaderControl 0x06
+#define HidUsage_BD_ScreenReaderIdentifier 0x07
+#define HidUsage_BD_RouterSet1 0xfa
+#define HidUsage_BD_RouterSet2 0xfb
+#define HidUsage_BD_RouterSet3 0xfc
+#define HidUsage_BD_RouterKey 0x100
+#define HidUsage_BD_RowRouterKey 0x101
+#define HidUsage_BD_BrailleButtons 0x200
+#define HidUsage_BD_BrailleKeyboardDot1 0x201
+#define HidUsage_BD_BrailleKeyboardDot2 0x202
+#define HidUsage_BD_BrailleKeyboardDot3 0x203
+#define HidUsage_BD_BrailleKeyboardDot4 0x204
+#define HidUsage_BD_BrailleKeyboardDot5 0x205
+#define HidUsage_BD_BrailleKeyboardDot6 0x206
+#define HidUsage_BD_BrailleKeyboardDot7 0x207
+#define HidUsage_BD_BrailleKeyboardDot8 0x208
+#define HidUsage_BD_BrailleKeyboardSpace 0x209
+#define HidUsage_BD_BrailleKeyboardLeftSpace 0x20a
+#define HidUsage_BD_BrailleKeyboardRightSpace 0x20b
+#define HidUsage_BD_BrailleFaceControls 0x20c
+#define HidUsage_BD_BrailleLeftControls 0x20d
+#define HidUsage_BD_BrailleRightControls 0x20e
+#define HidUsage_BD_BrailleTopControls 0x20f
+#define HidUsage_BD_BrailleJoystickCenter 0x210
+#define HidUsage_BD_BrailleJoystickUp 0x211
+#define HidUsage_BD_BrailleJoystickDown 0x212
+#define HidUsage_BD_BrailleJoystickLeft 0x213
+#define HidUsage_BD_BrailleJoystickRight 0x214
+#define HidUsage_BD_BrailleDPadCenter 0x215
+#define HidUsage_BD_BrailleDPadUp 0x216
+#define HidUsage_BD_BrailleDPadDown 0x217
+#define HidUsage_BD_BrailleDPadLeft 0x218
+#define HidUsage_BD_BrailleDPadRight 0x219
+#define HidUsage_BD_BraillePanLeft 0x21a
+#define HidUsage_BD_BraillePanRight 0x21b
+#define HidUsage_BD_BrailleRockerUp 0x21c
+#define HidUsage_BD_BrailleRockerDown 0x21d
+#define HidUsage_BD_BrailleRockerPress 0x21e
+#define HidUsage_LAI_LampArray 0x01
+#define HidUsage_LAI_LampArrayAttributesReport 0x02
+#define HidUsage_LAI_LampCount 0x03
+#define HidUsage_LAI_BoundingBoxWidthInMicrometers 0x04
+#define HidUsage_LAI_BoundingBoxHeightInMicrometers 0x05
+#define HidUsage_LAI_BoundingBoxDepthInMicrometers 0x06
+#define HidUsage_LAI_LampArrayKind 0x07
+#define HidUsage_LAI_MinUpdateIntervalInMicroseconds 0x08
+#define HidUsage_LAI_LampAttributesRequestReport 0x20
+#define HidUsage_LAI_LampId 0x21
+#define HidUsage_LAI_LampAttributesResponseReport 0x22
+#define HidUsage_LAI_PositionXInMicrometers 0x23
+#define HidUsage_LAI_PositionYInMicrometers 0x24
+#define HidUsage_LAI_PositionZInMicrometers 0x25
+#define HidUsage_LAI_LampPurposes 0x26
+#define HidUsage_LAI_UpdateLatencyInMicroseconds 0x27
+#define HidUsage_LAI_RedLevelCount 0x28
+#define HidUsage_LAI_GreenLevelCount 0x29
+#define HidUsage_LAI_BlueLevelCount 0x2a
+#define HidUsage_LAI_IntensityLevelCount 0x2b
+#define HidUsage_LAI_IsProgrammable 0x2c
+#define HidUsage_LAI_InputBinding 0x2d
+#define HidUsage_LAI_LampMultiUpdateReport 0x50
+#define HidUsage_LAI_RedUpdateChannel 0x51
+#define HidUsage_LAI_GreenUpdateChannel 0x52
+#define HidUsage_LAI_BlueUpdateChannel 0x53
+#define HidUsage_LAI_IntensityUpdateChannel 0x54
+#define HidUsage_LAI_LampUpdateFlags 0x55
+#define HidUsage_LAI_LampRangeUpdateReport 0x60
+#define HidUsage_LAI_LampIdStart 0x61
+#define HidUsage_LAI_LampIdEnd 0x62
+#define HidUsage_LAI_LampArrayControlReport 0x70
+#define HidUsage_LAI_AutonomousMode 0x71
+#define HidUsage_Mon_MonitorControl 0x01
+#define HidUsage_Mon_EDIDInformation 0x02
+#define HidUsage_Mon_VDIFInformation 0x03
+#define HidUsage_Mon_VESAVersion 0x04
+#define HidUsage_VESAVC_Degauss 0x01
+#define HidUsage_VESAVC_Brightness 0x10
+#define HidUsage_VESAVC_Contrast 0x12
+#define HidUsage_VESAVC_RedVideoGain 0x16
+#define HidUsage_VESAVC_GreenVideoGain 0x18
+#define HidUsage_VESAVC_BlueVideoGain 0x1a
+#define HidUsage_VESAVC_Focus 0x1c
+#define HidUsage_VESAVC_HorizontalPosition 0x20
+#define HidUsage_VESAVC_HorizontalSize 0x22
+#define HidUsage_VESAVC_HorizontalPincushion 0x24
+#define HidUsage_VESAVC_HorizontalPincushionBalance 0x26
+#define HidUsage_VESAVC_HorizontalMisconvergence 0x28
+#define HidUsage_VESAVC_HorizontalLinearity 0x2a
+#define HidUsage_VESAVC_HorizontalLinearityBalance 0x2c
+#define HidUsage_VESAVC_VerticalPosition 0x30
+#define HidUsage_VESAVC_VerticalSize 0x32
+#define HidUsage_VESAVC_VerticalPincushion 0x34
+#define HidUsage_VESAVC_VerticalPincushionBalance 0x36
+#define HidUsage_VESAVC_VerticalMisconvergence 0x38
+#define HidUsage_VESAVC_VerticalLinearity 0x3a
+#define HidUsage_VESAVC_VerticalLinearityBalance 0x3c
+#define HidUsage_VESAVC_ParallelogramDistortionKeyBalance 0x40
+#define HidUsage_VESAVC_TrapezoidalDistortionKey 0x42
+#define HidUsage_VESAVC_TiltRotation 0x44
+#define HidUsage_VESAVC_TopCornerDistortionControl 0x46
+#define HidUsage_VESAVC_TopCornerDistortionBalance 0x48
+#define HidUsage_VESAVC_BottomCornerDistortionControl 0x4a
+#define HidUsage_VESAVC_BottomCornerDistortionBalance 0x4c
+#define HidUsage_VESAVC_HorizontalMoiré 0x56
+#define HidUsage_VESAVC_VerticalMoiré 0x58
+#define HidUsage_VESAVC_InputLevelSelect 0x5e
+#define HidUsage_VESAVC_InputSourceSelect 0x60
+#define HidUsage_VESAVC_RedVideoBlackLevel 0x6c
+#define HidUsage_VESAVC_GreenVideoBlackLevel 0x6e
+#define HidUsage_VESAVC_BlueVideoBlackLevel 0x70
+#define HidUsage_VESAVC_AutoSizeCenter 0xa2
+#define HidUsage_VESAVC_PolarityHorizontalSynchronization 0xa4
+#define HidUsage_VESAVC_PolarityVerticalSynchronization 0xa6
+#define HidUsage_VESAVC_SynchronizationType 0xa8
+#define HidUsage_VESAVC_ScreenOrientation 0xaa
+#define HidUsage_VESAVC_HorizontalFrequency 0xac
+#define HidUsage_VESAVC_VerticalFrequency 0xae
+#define HidUsage_VESAVC_Settings 0xb0
+#define HidUsage_VESAVC_OnScreenDisplay 0xca
+#define HidUsage_VESAVC_StereoMode 0xd4
+#define HidUsage_Pow_iName 0x01
+#define HidUsage_Pow_PresentStatus 0x02
+#define HidUsage_Pow_ChangedStatus 0x03
+#define HidUsage_Pow_UPS 0x04
+#define HidUsage_Pow_PowerSupply 0x05
+#define HidUsage_Pow_BatterySystem 0x10
+#define HidUsage_Pow_BatterySystemId 0x11
+#define HidUsage_Pow_Battery 0x12
+#define HidUsage_Pow_BatteryId 0x13
+#define HidUsage_Pow_Charger 0x14
+#define HidUsage_Pow_ChargerId 0x15
+#define HidUsage_Pow_PowerConverter 0x16
+#define HidUsage_Pow_PowerConverterId 0x17
+#define HidUsage_Pow_OutletSystem 0x18
+#define HidUsage_Pow_OutletSystemId 0x19
+#define HidUsage_Pow_Input 0x1a
+#define HidUsage_Pow_InputId 0x1b
+#define HidUsage_Pow_Output 0x1c
+#define HidUsage_Pow_OutputId 0x1d
+#define HidUsage_Pow_Flow 0x1e
+#define HidUsage_Pow_FlowId 0x1f
+#define HidUsage_Pow_Outlet 0x20
+#define HidUsage_Pow_OutletId 0x21
+#define HidUsage_Pow_Gang 0x22
+#define HidUsage_Pow_GangId 0x23
+#define HidUsage_Pow_PowerSummary 0x24
+#define HidUsage_Pow_PowerSummaryId 0x25
+#define HidUsage_Pow_Voltage 0x30
+#define HidUsage_Pow_Current 0x31
+#define HidUsage_Pow_Frequency 0x32
+#define HidUsage_Pow_ApparentPower 0x33
+#define HidUsage_Pow_ActivePower 0x34
+#define HidUsage_Pow_PercentLoad 0x35
+#define HidUsage_Pow_Temperature 0x36
+#define HidUsage_Pow_Humidity 0x37
+#define HidUsage_Pow_BadCount 0x38
+#define HidUsage_Pow_ConfigVoltage 0x40
+#define HidUsage_Pow_ConfigCurrent 0x41
+#define HidUsage_Pow_ConfigFrequency 0x42
+#define HidUsage_Pow_ConfigApparentPower 0x43
+#define HidUsage_Pow_ConfigActivePower 0x44
+#define HidUsage_Pow_ConfigPercentLoad 0x45
+#define HidUsage_Pow_ConfigTemperature 0x46
+#define HidUsage_Pow_ConfigHumidity 0x47
+#define HidUsage_Pow_SwitchOnControl 0x50
+#define HidUsage_Pow_SwitchOffControl 0x51
+#define HidUsage_Pow_ToggleControl 0x52
+#define HidUsage_Pow_LowVoltageTransfer 0x53
+#define HidUsage_Pow_HighVoltageTransfer 0x54
+#define HidUsage_Pow_DelayBeforeReboot 0x55
+#define HidUsage_Pow_DelayBeforeStartup 0x56
+#define HidUsage_Pow_DelayBeforeShutdown 0x57
+#define HidUsage_Pow_Test 0x58
+#define HidUsage_Pow_ModuleReset 0x59
+#define HidUsage_Pow_AudibleAlarmControl 0x5a
+#define HidUsage_Pow_Present 0x60
+#define HidUsage_Pow_Good 0x61
+#define HidUsage_Pow_InternalFailure 0x62
+#define HidUsage_Pow_VoltagOutOfRange 0x63
+#define HidUsage_Pow_FrequencyOutOfRange 0x64
+#define HidUsage_Pow_Overload 0x65
+#define HidUsage_Pow_OverCharged 0x66
+#define HidUsage_Pow_OverTemperature 0x67
+#define HidUsage_Pow_ShutdownRequested 0x68
+#define HidUsage_Pow_ShutdownImminent 0x69
+#define HidUsage_Pow_SwitchOnOff 0x6b
+#define HidUsage_Pow_Switchable 0x6c
+#define HidUsage_Pow_Used 0x6d
+#define HidUsage_Pow_Boost 0x6e
+#define HidUsage_Pow_Buck 0x6f
+#define HidUsage_Pow_Initialized 0x70
+#define HidUsage_Pow_Tested 0x71
+#define HidUsage_Pow_AwaitingPower 0x72
+#define HidUsage_Pow_CommunicationLost 0x73
+#define HidUsage_Pow_iManufacturer 0xfd
+#define HidUsage_Pow_iProduct 0xfe
+#define HidUsage_Pow_iSerialNumber 0xff
+#define HidUsage_BS_SmartBatteryBatteryMode 0x01
+#define HidUsage_BS_SmartBatteryBatteryStatus 0x02
+#define HidUsage_BS_SmartBatteryAlarmWarning 0x03
+#define HidUsage_BS_SmartBatteryChargerMode 0x04
+#define HidUsage_BS_SmartBatteryChargerStatus 0x05
+#define HidUsage_BS_SmartBatteryChargerSpecInfo 0x06
+#define HidUsage_BS_SmartBatterySelectorState 0x07
+#define HidUsage_BS_SmartBatterySelectorPresets 0x08
+#define HidUsage_BS_SmartBatterySelectorInfo 0x09
+#define HidUsage_BS_OptionalMfgFunction1 0x10
+#define HidUsage_BS_OptionalMfgFunction2 0x11
+#define HidUsage_BS_OptionalMfgFunction3 0x12
+#define HidUsage_BS_OptionalMfgFunction4 0x13
+#define HidUsage_BS_OptionalMfgFunction5 0x14
+#define HidUsage_BS_ConnectionToSMBus 0x15
+#define HidUsage_BS_OutputConnection 0x16
+#define HidUsage_BS_ChargerConnection 0x17
+#define HidUsage_BS_BatteryInsertion 0x18
+#define HidUsage_BS_UseNext 0x19
+#define HidUsage_BS_OKToUse 0x1a
+#define HidUsage_BS_BatterySupported 0x1b
+#define HidUsage_BS_SelectorRevision 0x1c
+#define HidUsage_BS_ChargingIndicator 0x1d
+#define HidUsage_BS_ManufacturerAccess 0x28
+#define HidUsage_BS_RemainingCapacityLimit 0x29
+#define HidUsage_BS_RemainingTimeLimit 0x2a
+#define HidUsage_BS_AtRate 0x2b
+#define HidUsage_BS_CapacityMode 0x2c
+#define HidUsage_BS_BroadcastToCharger 0x2d
+#define HidUsage_BS_PrimaryBattery 0x2e
+#define HidUsage_BS_ChargeController 0x2f
+#define HidUsage_BS_TerminateCharge 0x40
+#define HidUsage_BS_TerminateDischarge 0x41
+#define HidUsage_BS_BelowRemainingCapacityLimit 0x42
+#define HidUsage_BS_RemainingTimeLimitExpired 0x43
+#define HidUsage_BS_Charging 0x44
+#define HidUsage_BS_Discharging 0x45
+#define HidUsage_BS_FullyCharged 0x46
+#define HidUsage_BS_FullyDischarged 0x47
+#define HidUsage_BS_ConditioningFlag 0x48
+#define HidUsage_BS_AtRateOK 0x49
+#define HidUsage_BS_SmartBatteryErrorCode 0x4a
+#define HidUsage_BS_NeedReplacement 0x4b
+#define HidUsage_BS_AtRateTimeToFull 0x60
+#define HidUsage_BS_AtRateTimeToEmpty 0x61
+#define HidUsage_BS_AverageCurrent 0x62
+#define HidUsage_BS_MaxError 0x63
+#define HidUsage_BS_RelativeStateOfCharge 0x64
+#define HidUsage_BS_AbsoluteStateOfCharge 0x65
+#define HidUsage_BS_RemainingCapacity 0x66
+#define HidUsage_BS_FullChargeCapacity 0x67
+#define HidUsage_BS_RunTimeToEmpty 0x68
+#define HidUsage_BS_AverageTimeToEmpty 0x69
+#define HidUsage_BS_AverageTimeToFull 0x6a
+#define HidUsage_BS_CycleCount 0x6b
+#define HidUsage_BS_BatteryPackModelLevel 0x80
+#define HidUsage_BS_InternalChargeController 0x81
+#define HidUsage_BS_PrimaryBatterySupport 0x82
+#define HidUsage_BS_DesignCapacity 0x83
+#define HidUsage_BS_SpecificationInfo 0x84
+#define HidUsage_BS_ManufactureDate 0x85
+#define HidUsage_BS_SerialNumber 0x86
+#define HidUsage_BS_iManufacturerName 0x87
+#define HidUsage_BS_iDeviceName 0x88
+#define HidUsage_BS_iDeviceChemistry 0x89
+#define HidUsage_BS_ManufacturerData 0x8a
+#define HidUsage_BS_Rechargeable 0x8b
+#define HidUsage_BS_WarningCapacityLimit 0x8c
+#define HidUsage_BS_CapacityGranularity1 0x8d
+#define HidUsage_BS_CapacityGranularity2 0x8e
+#define HidUsage_BS_iOEMInformation 0x8f
+#define HidUsage_BS_InhibitCharge 0xc0
+#define HidUsage_BS_EnablePolling 0xc1
+#define HidUsage_BS_ResetToZero 0xc2
+#define HidUsage_BS_ACPresent 0xd0
+#define HidUsage_BS_BatteryPresent 0xd1
+#define HidUsage_BS_PowerFail 0xd2
+#define HidUsage_BS_AlarmInhibited 0xd3
+#define HidUsage_BS_ThermistorUnderRange 0xd4
+#define HidUsage_BS_ThermistorHot 0xd5
+#define HidUsage_BS_ThermistorCold 0xd6
+#define HidUsage_BS_ThermistorOverRange 0xd7
+#define HidUsage_BS_VoltageOutOfRange 0xd8
+#define HidUsage_BS_CurrentOutOfRange 0xd9
+#define HidUsage_BS_CurrentNotRegulated 0xda
+#define HidUsage_BS_VoltageNotRegulated 0xdb
+#define HidUsage_BS_MasterMode 0xdc
+#define HidUsage_BS_ChargerSelectorSupport 0xf0
+#define HidUsage_BS_ChargerSpec 0xf1
+#define HidUsage_BS_Level2 0xf2
+#define HidUsage_BS_Level3 0xf3
+#define HidUsage_BS_BarcodeBadgeReader 0x01
+#define HidUsage_BS_BarcodeScanner 0x02
+#define HidUsage_BS_DumbBarCodeScanner 0x03
+#define HidUsage_BS_CordlessScannerBase 0x04
+#define HidUsage_BS_BarCodeScannerCradle 0x05
+#define HidUsage_BS_AttributeReport 0x10
+#define HidUsage_BS_SettingsReport 0x11
+#define HidUsage_BS_ScannedDataReport 0x12
+#define HidUsage_BS_RawScannedDataReport 0x13
+#define HidUsage_BS_TriggerReport 0x14
+#define HidUsage_BS_StatusReport 0x15
+#define HidUsage_BS_UPCEANControlReport 0x16
+#define HidUsage_BS_EAN23LabelControlReport 0x17
+#define HidUsage_BS_Code39ControlReport 0x18
+#define HidUsage_BS_Interleaved2of5ControlReport 0x19
+#define HidUsage_BS_Standard2of5ControlReport 0x1a
+#define HidUsage_BS_MSIPlesseyControlReport 0x1b
+#define HidUsage_BS_CodabarControlReport 0x1c
+#define HidUsage_BS_Code128ControlReport 0x1d
+#define HidUsage_BS_Misc1DControlReport 0x1e
+#define HidUsage_BS_TwoDControlReport 0x1f
+#define HidUsage_BS_AimingPointerMode 0x30
+#define HidUsage_BS_BarCodePresentSensor 0x31
+#define HidUsage_BS_Class1ALaser 0x32
+#define HidUsage_BS_Class2Laser 0x33
+#define HidUsage_BS_HeaterPresent 0x34
+#define HidUsage_BS_ContactScanner 0x35
+#define HidUsage_BS_ElectronicArticleSurveillanceNotification 0x36
+#define HidUsage_BS_ConstantElectronicArticleSurveillance 0x37
+#define HidUsage_BS_ErrorIndication 0x38
+#define HidUsage_BS_FixedBeeper 0x39
+#define HidUsage_BS_GoodDecodeIndication 0x3a
+#define HidUsage_BS_HandsFreeScanning 0x3b
+#define HidUsage_BS_IntrinsicallySafe 0x3c
+#define HidUsage_BS_KlasseEinsLaser 0x3d
+#define HidUsage_BS_LongRangeScanner 0x3e
+#define HidUsage_BS_MirrorSpeedControl 0x3f
+#define HidUsage_BS_NotOnFileIndication 0x40
+#define HidUsage_BS_ProgrammableBeeper 0x41
+#define HidUsage_BS_Triggerless 0x42
+#define HidUsage_BS_Wand 0x43
+#define HidUsage_BS_WaterResistant 0x44
+#define HidUsage_BS_MultiRangeScanner 0x45
+#define HidUsage_BS_ProximitySensor 0x46
+#define HidUsage_BS_FragmentDecoding 0x4d
+#define HidUsage_BS_ScannerReadConfidence 0x4e
+#define HidUsage_BS_DataPrefix 0x4f
+#define HidUsage_BS_PrefixAIMI 0x50
+#define HidUsage_BS_PrefixNone 0x51
+#define HidUsage_BS_PrefixProprietary 0x52
+#define HidUsage_BS_ActiveTime 0x55
+#define HidUsage_BS_AimingLaserPattern 0x56
+#define HidUsage_BS_BarCodePresent 0x57
+#define HidUsage_BS_BeeperState 0x58
+#define HidUsage_BS_LaserOnTime 0x59
+#define HidUsage_BS_LaserState 0x5a
+#define HidUsage_BS_LockoutTime 0x5b
+#define HidUsage_BS_MotorState 0x5c
+#define HidUsage_BS_MotorTimeout 0x5d
+#define HidUsage_BS_PowerOnResetScanner 0x5e
+#define HidUsage_BS_PreventReadofBarcodes 0x5f
+#define HidUsage_BS_InitiateBarcodeRead 0x60
+#define HidUsage_BS_TriggerState 0x61
+#define HidUsage_BS_TriggerMode 0x62
+#define HidUsage_BS_TriggerModeBlinkingLaserOn 0x63
+#define HidUsage_BS_TriggerModeContinuousLaserOn 0x64
+#define HidUsage_BS_TriggerModeLaseronwhilePulled 0x65
+#define HidUsage_BS_TriggerModeLaserstaysonafterrelease 0x66
+#define HidUsage_BS_CommitParameterstoNVM 0x6d
+#define HidUsage_BS_ParameterScanning 0x6e
+#define HidUsage_BS_ParametersChanged 0x6f
+#define HidUsage_BS_Setparameterdefaultvalues 0x70
+#define HidUsage_BS_ScannerInCradle 0x75
+#define HidUsage_BS_ScannerInRange 0x76
+#define HidUsage_BS_AimDuration 0x7a
+#define HidUsage_BS_GoodReadLampDuration 0x7b
+#define HidUsage_BS_GoodReadLampIntensity 0x7c
+#define HidUsage_BS_GoodReadLED 0x7d
+#define HidUsage_BS_GoodReadToneFrequency 0x7e
+#define HidUsage_BS_GoodReadToneLength 0x7f
+#define HidUsage_BS_GoodReadToneVolume 0x80
+#define HidUsage_BS_NoReadMessage 0x82
+#define HidUsage_BS_NotonFileVolume 0x83
+#define HidUsage_BS_PowerupBeep 0x84
+#define HidUsage_BS_SoundErrorBeep 0x85
+#define HidUsage_BS_SoundGoodReadBeep 0x86
+#define HidUsage_BS_SoundNotOnFileBeep 0x87
+#define HidUsage_BS_GoodReadWhentoWrite 0x88
+#define HidUsage_BS_GRWTIAfterDecode 0x89
+#define HidUsage_BS_GRWTIBeepLampaftertransmit 0x8a
+#define HidUsage_BS_GRWTINoBeepLampuseatall 0x8b
+#define HidUsage_BS_BooklandEAN 0x91
+#define HidUsage_BS_ConvertEAN8to13Type 0x92
+#define HidUsage_BS_ConvertUPCAtoEAN13 0x93
+#define HidUsage_BS_ConvertUPCEtoA 0x94
+#define HidUsage_BS_EAN13 0x95
+#define HidUsage_BS_EAN8 0x96
+#define HidUsage_BS_EAN99128Mandatory 0x97
+#define HidUsage_BS_EAN99P5128Optional 0x98
+#define HidUsage_BS_EnableEANTwoLabel 0x99
+#define HidUsage_BS_UPCEAN 0x9a
+#define HidUsage_BS_UPCEANCouponCode 0x9b
+#define HidUsage_BS_UPCEANPeriodicals 0x9c
+#define HidUsage_BS_UPCA 0x9d
+#define HidUsage_BS_UPCAwith128Mandatory 0x9e
+#define HidUsage_BS_UPCAwith128Optional 0x9f
+#define HidUsage_BS_UPCAwithP5Optional 0xa0
+#define HidUsage_BS_UPCE 0xa1
+#define HidUsage_BS_UPCE1 0xa2
+#define HidUsage_BS_Periodical 0xa9
+#define HidUsage_BS_PeriodicalAutoDiscriminatePlus2 0xaa
+#define HidUsage_BS_PeriodicalOnlyDecodewithPlus2 0xab
+#define HidUsage_BS_PeriodicalIgnorePlus2 0xac
+#define HidUsage_BS_PeriodicalAutoDiscriminatePlus5 0xad
+#define HidUsage_BS_PeriodicalOnlyDecodewithPlus5 0xae
+#define HidUsage_BS_PeriodicalIgnorePlus5 0xaf
+#define HidUsage_BS_Check 0xb0
+#define HidUsage_BS_CheckDisablePrice 0xb1
+#define HidUsage_BS_CheckEnable4digitPrice 0xb2
+#define HidUsage_BS_CheckEnable5digitPrice 0xb3
+#define HidUsage_BS_CheckEnableEuropean4digitPrice 0xb4
+#define HidUsage_BS_CheckEnableEuropean5digitPrice 0xb5
+#define HidUsage_BS_EANTwoLabel 0xb7
+#define HidUsage_BS_EANThreeLabel 0xb8
+#define HidUsage_BS_EAN8FlagDigit1 0xb9
+#define HidUsage_BS_EAN8FlagDigit2 0xba
+#define HidUsage_BS_EAN8FlagDigit3 0xbb
+#define HidUsage_BS_EAN13FlagDigit1 0xbc
+#define HidUsage_BS_EAN13FlagDigit2 0xbd
+#define HidUsage_BS_EAN13FlagDigit3 0xbe
+#define HidUsage_BS_AddEAN23LabelDefinition 0xbf
+#define HidUsage_BS_ClearallEAN23LabelDefinitions 0xc0
+#define HidUsage_BS_Codabar 0xc3
+#define HidUsage_BS_Code128 0xc4
+#define HidUsage_BS_Code39 0xc7
+#define HidUsage_BS_Code93 0xc8
+#define HidUsage_BS_FullASCIIConversion 0xc9
+#define HidUsage_BS_Interleaved2of5 0xca
+#define HidUsage_BS_ItalianPharmacyCode 0xcb
+#define HidUsage_BS_MSIPlessey 0xcc
+#define HidUsage_BS_Standard2of5IATA 0xcd
+#define HidUsage_BS_Standard2of5 0xce
+#define HidUsage_BS_TransmitStartStop 0xd3
+#define HidUsage_BS_TriOptic 0xd4
+#define HidUsage_BS_UCCEAN128 0xd5
+#define HidUsage_BS_CheckDigit 0xd6
+#define HidUsage_BS_CheckDigitDisable 0xd7
+#define HidUsage_BS_CheckDigitEnableInterleaved2of5OPCC 0xd8
+#define HidUsage_BS_CheckDigitEnableInterleaved2of5USS 0xd9
+#define HidUsage_BS_CheckDigitEnableStandard2of5OPCC 0xda
+#define HidUsage_BS_CheckDigitEnableStandard2of5USS 0xdb
+#define HidUsage_BS_CheckDigitEnableOneMSIPlessey 0xdc
+#define HidUsage_BS_CheckDigitEnableTwoMSIPlessey 0xdd
+#define HidUsage_BS_CheckDigitCodabarEnable 0xde
+#define HidUsage_BS_CheckDigitCode39Enable 0xdf
+#define HidUsage_BS_TransmitCheckDigit 0xf0
+#define HidUsage_BS_DisableCheckDigitTransmit 0xf1
+#define HidUsage_BS_EnableCheckDigitTransmit 0xf2
+#define HidUsage_BS_SymbologyIdentifier1 0xfb
+#define HidUsage_BS_SymbologyIdentifier2 0xfc
+#define HidUsage_BS_SymbologyIdentifier3 0xfd
+#define HidUsage_BS_DecodedData 0xfe
+#define HidUsage_BS_DecodeDataContinued 0xff
+#define HidUsage_BS_BarSpaceData 0x100
+#define HidUsage_BS_ScannerDataAccuracy 0x101
+#define HidUsage_BS_RawDataPolarity 0x102
+#define HidUsage_BS_PolarityInvertedBarCode 0x103
+#define HidUsage_BS_PolarityNormalBarCode 0x104
+#define HidUsage_BS_MinimumLengthtoDecode 0x106
+#define HidUsage_BS_MaximumLengthtoDecode 0x107
+#define HidUsage_BS_DiscreteLengthtoDecode1 0x108
+#define HidUsage_BS_DiscreteLengthtoDecode2 0x109
+#define HidUsage_BS_DataLengthMethod 0x10a
+#define HidUsage_BS_DLMethodReadany 0x10b
+#define HidUsage_BS_DLMethodCheckinRange 0x10c
+#define HidUsage_BS_DLMethodCheckforDiscrete 0x10d
+#define HidUsage_BS_AztecCode 0x110
+#define HidUsage_BS_BC412 0x111
+#define HidUsage_BS_ChannelCode 0x112
+#define HidUsage_BS_Code16 0x113
+#define HidUsage_BS_Code32 0x114
+#define HidUsage_BS_Code49 0x115
+#define HidUsage_BS_CodeOne 0x116
+#define HidUsage_BS_Colorcode 0x117
+#define HidUsage_BS_DataMatrix 0x118
+#define HidUsage_BS_MaxiCode 0x119
+#define HidUsage_BS_MicroPDF 0x11a
+#define HidUsage_BS_PDF417 0x11b
+#define HidUsage_BS_PosiCode 0x11c
+#define HidUsage_BS_QRCode 0x11d
+#define HidUsage_BS_SuperCode 0x11e
+#define HidUsage_BS_UltraCode 0x11f
+#define HidUsage_BS_USD5SlugCode 0x120
+#define HidUsage_BS_VeriCode 0x121
+#define HidUsage_Sca_Scales 0x01
+#define HidUsage_Sca_ScaleDevice 0x20
+#define HidUsage_Sca_ScaleClass 0x21
+#define HidUsage_Sca_ScaleClassIMetric 0x22
+#define HidUsage_Sca_ScaleClassIIMetric 0x23
+#define HidUsage_Sca_ScaleClassIIIMetric 0x24
+#define HidUsage_Sca_ScaleClassIIILMetric 0x25
+#define HidUsage_Sca_ScaleClassIVMetric 0x26
+#define HidUsage_Sca_ScaleClassIIIEnglish 0x27
+#define HidUsage_Sca_ScaleClassIIILEnglish 0x28
+#define HidUsage_Sca_ScaleClassIVEnglish 0x29
+#define HidUsage_Sca_ScaleClassGeneric 0x2a
+#define HidUsage_Sca_ScaleAttributeReport 0x30
+#define HidUsage_Sca_ScaleControlReport 0x31
+#define HidUsage_Sca_ScaleDataReport 0x32
+#define HidUsage_Sca_ScaleStatusReport 0x33
+#define HidUsage_Sca_ScaleWeightLimitReport 0x34
+#define HidUsage_Sca_ScaleStatisticsReport 0x35
+#define HidUsage_Sca_DataWeight 0x40
+#define HidUsage_Sca_DataScaling 0x41
+#define HidUsage_Sca_WeightUnit 0x50
+#define HidUsage_Sca_WeightUnitMilligram 0x51
+#define HidUsage_Sca_WeightUnitGram 0x52
+#define HidUsage_Sca_WeightUnitKilogram 0x53
+#define HidUsage_Sca_WeightUnitCarats 0x54
+#define HidUsage_Sca_WeightUnitTaels 0x55
+#define HidUsage_Sca_WeightUnitGrains 0x56
+#define HidUsage_Sca_WeightUnitPennyweights 0x57
+#define HidUsage_Sca_WeightUnitMetricTon 0x58
+#define HidUsage_Sca_WeightUnitAvoirTon 0x59
+#define HidUsage_Sca_WeightUnitTroyOunce 0x5a
+#define HidUsage_Sca_WeightUnitOunce 0x5b
+#define HidUsage_Sca_WeightUnitPound 0x5c
+#define HidUsage_Sca_CalibrationCount 0x60
+#define HidUsage_Sca_ReZeroCount 0x61
+#define HidUsage_Sca_ScaleStatus 0x70
+#define HidUsage_Sca_ScaleStatusFault 0x71
+#define HidUsage_Sca_ScaleStatusStableatCenterofZero 0x72
+#define HidUsage_Sca_ScaleStatusInMotion 0x73
+#define HidUsage_Sca_ScaleStatusWeightStable 0x74
+#define HidUsage_Sca_ScaleStatusUnderZero 0x75
+#define HidUsage_Sca_ScaleStatusOverWeightLimit 0x76
+#define HidUsage_Sca_ScaleStatusRequiresCalibration 0x77
+#define HidUsage_Sca_ScaleStatusRequiresRezeroing 0x78
+#define HidUsage_Sca_ZeroScale 0x80
+#define HidUsage_Sca_EnforcedZeroReturn 0x81
+#define HidUsage_MSR_MSRDeviceReadOnly 0x01
+#define HidUsage_MSR_Track1Length 0x11
+#define HidUsage_MSR_Track2Length 0x12
+#define HidUsage_MSR_Track3Length 0x13
+#define HidUsage_MSR_TrackJISLength 0x14
+#define HidUsage_MSR_TrackData 0x20
+#define HidUsage_MSR_Track1Data 0x21
+#define HidUsage_MSR_Track2Data 0x22
+#define HidUsage_MSR_Track3Data 0x23
+#define HidUsage_MSR_TrackJISData 0x24
+#define HidUsage_CC_CameraAutofocus 0x20
+#define HidUsage_CC_CameraShutter 0x21
+#define HidUsage_Arc_GeneralPurposeIOCard 0x01
+#define HidUsage_Arc_CoinDoor 0x02
+#define HidUsage_Arc_WatchdogTimer 0x03
+#define HidUsage_Arc_GeneralPurposeAnalogInputState 0x30
+#define HidUsage_Arc_GeneralPurposeDigitalInputState 0x31
+#define HidUsage_Arc_GeneralPurposeOpticalInputState 0x32
+#define HidUsage_Arc_GeneralPurposeDigitalOutputState 0x33
+#define HidUsage_Arc_NumberofCoinDoors 0x34
+#define HidUsage_Arc_CoinDrawerDropCount 0x35
+#define HidUsage_Arc_CoinDrawerStart 0x36
+#define HidUsage_Arc_CoinDrawerService 0x37
+#define HidUsage_Arc_CoinDrawerTilt 0x38
+#define HidUsage_Arc_CoinDoorTest 0x39
+#define HidUsage_Arc_CoinDoorLockout 0x40
+#define HidUsage_Arc_WatchdogTimeout 0x41
+#define HidUsage_Arc_WatchdogAction 0x42
+#define HidUsage_Arc_WatchdogReboot 0x43
+#define HidUsage_Arc_WatchdogRestart 0x44
+#define HidUsage_Arc_AlarmInput 0x45
+#define HidUsage_Arc_CoinDoorCounter 0x46
+#define HidUsage_Arc_IODirectionMapping 0x47
+#define HidUsage_Arc_SetIODirectionMapping 0x48
+#define HidUsage_Arc_ExtendedOpticalInputState 0x49
+#define HidUsage_Arc_PinPadInputState 0x4a
+#define HidUsage_Arc_PinPadStatus 0x4b
+#define HidUsage_Arc_PinPadOutput 0x4c
+#define HidUsage_Arc_PinPadCommand 0x4d
+#define HidUsage_FIDOA_U2FAuthenticatorDevice 0x01
+#define HidUsage_FIDOA_InputReportData 0x20
+#define HidUsage_FIDOA_OutputReportData 0x21